package jnpf.notice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.net.URLDecoder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.model.notice.domain.FtbNoticeAnnouncements;
import jnpf.model.notice.domain.FtbNoticeCategories;
import jnpf.model.notice.dto.AppNoticeCategoriesDto;
import jnpf.model.notice.dto.FtbNoticeCategoriesDto;
import jnpf.model.notice.enums.NoticeEnums;
import jnpf.model.notice.req.category.AddCategoryReq;
import jnpf.model.notice.req.category.QueryCategoryListReq;
import jnpf.model.notice.req.category.QueryNextCategoryListReq;
import jnpf.model.notice.req.category.UpdateCategoryReq;
import jnpf.notice.mapper.FtbNoticeCategoriesMapper;
import jnpf.notice.service.FtbNoticeAnnouncementsService;
import jnpf.notice.service.FtbNoticeCategoriesService;
import jnpf.util.UserProvider;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author 许贵林
 * @description 针对表【ftb_notice_categories(公告分类表)】的数据库操作Service实现
 * @createDate 2024-05-08 09:42:09
 */
@Service
public class FtbNoticeCategoriesServiceImpl extends ServiceImpl<FtbNoticeCategoriesMapper, FtbNoticeCategories>
        implements FtbNoticeCategoriesService {

    @Autowired
    private FtbNoticeAnnouncementsService ftbNoticeAnnouncementsService;

    /**
     * 查询所有 返回tree
     *
     * @param req
     * @return
     */
    @Override
    public List<FtbNoticeCategoriesDto> listCategory(QueryCategoryListReq req) {
        if (req.getType() == null) {//默认查询所有
            req.setType(0);
        }
        if (!req.getType().equals(0) && !req.getType().equals(1)) {
            throw new RuntimeException("type参数错误");
        }
        //type 0 查询所有分类（默认）  1 查询一级分类
        if(StringUtils.isEmpty(req.getKeyWord())) {
            return searchNoKeyWord(req);
        }
        return searchHasKeyWord(req);
    }

    private List<FtbNoticeCategoriesDto> searchHasKeyWord(QueryCategoryListReq req) {
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(req.getType().equals(1), FtbNoticeCategories::getParentId, "")
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode())
                .like(StringUtils.isNotEmpty(req.getKeyWord()), FtbNoticeCategories::getName, URLDecoder.decode(req.getKeyWord(), StandardCharsets.UTF_8))
                .orderByAsc(FtbNoticeCategories::getCreatorTime);
        List<FtbNoticeCategories> categoriesList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(categoriesList)) {
            return new ArrayList<>();
        }
        Set<String> cateIds = new HashSet<>();
        for (FtbNoticeCategories ftbNoticeCategories : categoriesList) {
            cateIds.add(ftbNoticeCategories.getId());
            if(StringUtils.isNotEmpty(ftbNoticeCategories.getPath())){
                String[] split = ftbNoticeCategories.getPath().split(",");
                cateIds.addAll(Arrays.asList(split));
            }
        }
        List<FtbNoticeCategories> categoriesListAll = baseMapper.selectBatchIds(cateIds);
        if (req.getType().equals(1)) {
            //一级分类不需要够级分类树
            return BeanUtil.copyToList(categoriesListAll, FtbNoticeCategoriesDto.class);
        } else {
            return buildCateTree(categoriesListAll);
        }
    }

    private List<FtbNoticeCategoriesDto> searchNoKeyWord(QueryCategoryListReq req) {

        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(req.getType().equals(1), FtbNoticeCategories::getParentId, "")
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode())
                .orderByAsc(FtbNoticeCategories::getCreatorTime);
        List<FtbNoticeCategories> categoriesList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(categoriesList)) {
            return new ArrayList<>();
        }

        if (req.getType().equals(1)) {
            //一级分类不需要够级分类树
            return BeanUtil.copyToList(categoriesList, FtbNoticeCategoriesDto.class);
        } else {
            return buildCateTree(categoriesList);
        }
    }

    /**
     * 查询下级分类
     *
     * @param req
     * @return
     */
    @Override
    public List<FtbNoticeCategoriesDto> nextCatelists(QueryNextCategoryListReq req) {
        List<FtbNoticeCategories> categoriesList = queryChildCategory(req.getId());
        if (CollectionUtil.isEmpty(categoriesList)) {
            return Collections.emptyList();
        }
        List<FtbNoticeCategoriesDto> ftbNoticeCategoriesDtos = BeanUtil.copyToList(categoriesList, FtbNoticeCategoriesDto.class);
        for (FtbNoticeCategoriesDto ftbNoticeCategoriesDto : ftbNoticeCategoriesDtos) {
            fillCategoryLevel(ftbNoticeCategoriesDto);
        }
        return ftbNoticeCategoriesDtos;
    }

    /**
     * 查询是否有子分类
     *
     * @param list
     * @return
     */
    @Override
    public List<AppNoticeCategoriesDto> fillHasChild(List<FtbNoticeCategoriesDto> list) {
        if (CollectionUtil.isEmpty(list)) {
            return CollectionUtil.newArrayList();
        }
        List<AppNoticeCategoriesDto> appNoticeCategoriesList = BeanUtil.copyToList(list, AppNoticeCategoriesDto.class);
        for (AppNoticeCategoriesDto dto : appNoticeCategoriesList) {
            Long aLong = queryChildCategoryNum(dto.getId());
            if (aLong > 0) {
                dto.setHasChild(true);
            } else {
                dto.setHasChild(false);
            }
        }
        return appNoticeCategoriesList;
    }

    /**
     * 查询所有分类并返回分类树
     *
     * @return
     */
    @Override
    public List<FtbNoticeCategories> listAll() {

        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode())
                .orderByAsc(FtbNoticeCategories::getCreatorTime);
        List<FtbNoticeCategories> categoriesList = baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(categoriesList)) {
            return new ArrayList<>();
        }
        return categoriesList;
    }

    /**
     * 添加分类
     *
     * @param req
     * @return
     */
    @Override
    public FtbNoticeCategories insertData(AddCategoryReq req) {
        //检测名称是否重复
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbNoticeCategories::getName, req.getName())
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        Long count = baseMapper.selectCount(wrapper);
        if (null != count && count > 0) {
            throw new RuntimeException("分类名称已经存在");
        }
        //查询检测父级分类是否存在
        FtbNoticeCategories parent = null;
        if (StringUtils.isNotEmpty(req.getParentId())) {
            parent = queryAndCheckParent(req.getParentId());
        }

        //添加分类
        FtbNoticeCategories categories = new FtbNoticeCategories();
        categories.setName(req.getName());
        categories.setParentId(req.getParentId());
        String path = "";
        if (null != parent) {
            //检查是否超过5级
            if (StringUtils.isNotEmpty(parent.getPath())) {
                if (parent.getPath().split("-").length > 5) {
                    throw new RuntimeException("分类最多支持5级");
                }
            }

            if (StringUtils.isNotEmpty(parent.getPath())) {
                path = parent.getPath() + "-" + parent.getId();
            } else {
                path = parent.getId();
            }
        }
        categories.setPath(path);
        categories.setEnabledMark(NoticeEnums.DeleteType.VALID.getCode());
        baseMapper.insert(categories);
        return categories;
    }

    /**
     * 修改分类
     *
     * @param id  分类id
     * @param req
     * @return
     */
    @Override
    public FtbNoticeCategories updateData(String id, UpdateCategoryReq req) {
        //检测分类是否删除
        queryAndCheckById(id);
        //检测名称是否重复
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbNoticeCategories::getName, req.getName())
                .ne(FtbNoticeCategories::getId, id)
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        Long count = baseMapper.selectCount(wrapper);
        if (null != count && count > 0) {
            throw new RuntimeException("分类名称已经存在");
        }

        FtbNoticeCategories parent = null;
        if (StringUtils.isNotEmpty(req.getParentId())) {
            parent = queryAndCheckParent(req.getParentId());
        }

        //修改分类
        FtbNoticeCategories categories = new FtbNoticeCategories();
        categories.setName(req.getName());
//        categories.setParentId(req.getParentId());
//        String path = "";
//        if (null != parent) {
//            if (id.equals(parent.getId())) {
//                throw new RuntimeException("对不起,自己不能是自己的父级分类");
//            }
//            if (StringUtils.isNotEmpty(parent.getPath())) {
//                path = parent.getPath() + "-" + parent.getId();
//            } else {
//                path = parent.getId();
//            }
//        }
//        categories.setPath(path);

        categories.setId(id);
        categories.setEnabledMark(NoticeEnums.DeleteType.VALID.getCode());
        baseMapper.updateById(categories);
        return categories;

    }

    /**
     * 查询并验证父分类是否存在且有效
     * 该方法用于查询给定ID的父分类，并确保该父分类存在且未被标记为删除
     * 如果父分类不存在或已被标记为删除，则抛出运行时异常
     *
     * @param parentId 父分类的ID
     * @return 返回查询到的父分类对象
     * @throws RuntimeException 如果父分类不存在或已被标记为删除，则抛出此异常
     */
    private FtbNoticeCategories queryAndCheckParent(String parentId) {
        FtbNoticeCategories parent = baseMapper.selectById(parentId);
        if (null == parent) {
            throw new RuntimeException("父级分类不存在");
        }
        if (parent.getEnabledMark().equals(NoticeEnums.DeleteType.INVALID.getCode())) {
            throw new RuntimeException("父级分类已被删除");
        }
        return parent;
    }

    /**
     * 查询分类并检查分类是否存在
     *
     * @param id 分类id
     * @return
     */
    @Override
    public FtbNoticeCategories queryAndCheckById(String id) {
        FtbNoticeCategories entity = baseMapper.selectById(id);
        if (null == entity) {
            throw new RuntimeException("分类不存在");
        }
        if (entity.getEnabledMark().equals(NoticeEnums.DeleteType.INVALID.getCode())) {
            throw new RuntimeException("分类已经删除");
        }
        return entity;
    }

    /**
     * 删除分类
     *
     * @param id 分类id
     */
    @Override
    public void deleteData(String id) {
        String loginUserId = UserProvider.getLoginUserId();
        List<String> deleteIds = new ArrayList<>();
        deleteIds.add(id);
        //检测分类是否删除
        FtbNoticeCategories currCategory = queryAndCheckById(id);

        //检测分类下是否有下级分类
        List<String> childCategoryIds = queryChildCategoryIds(currCategory);
        if (CollectionUtil.isNotEmpty(childCategoryIds)) {
            deleteIds.addAll(childCategoryIds);
        }

        //检测分类是否有公告
        QueryWrapper<FtbNoticeAnnouncements> announcementsQueryWrapper = new QueryWrapper<>();
        announcementsQueryWrapper.lambda()
                .select(FtbNoticeAnnouncements::getId, FtbNoticeAnnouncements::getTitle,FtbNoticeAnnouncements::getCreatorUserId)
                .in(FtbNoticeAnnouncements::getCategoryId, deleteIds)
                .eq(FtbNoticeAnnouncements::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        List<FtbNoticeAnnouncements> announcementsList = ftbNoticeAnnouncementsService.list(announcementsQueryWrapper);
        if (CollectionUtil.isNotEmpty(announcementsList)) {
            boolean myIsHas = false;
            for (FtbNoticeAnnouncements ftbNoticeAnnouncements : announcementsList) {
                if (ftbNoticeAnnouncements.getCreatorUserId().equals(loginUserId)) {
                    myIsHas = true;
                }
            }
            if(myIsHas) {
                throw new RuntimeException("分类下存在公告，请先删除公告");
            }else{
                throw new RuntimeException("分类下存在其他员工建立的公告,请先删除公告");
            }
        }

        //删除分类
        List<FtbNoticeCategories> updateList = new ArrayList<>();
        for (String deleteId : deleteIds) {
            FtbNoticeCategories categories = new FtbNoticeCategories();
            categories.setId(deleteId);
            categories.setEnabledMark(NoticeEnums.DeleteType.INVALID.getCode());
            updateList.add(categories);
        }

        updateBatchById(updateList);
    }

    /**
     * 查询子分类
     *
     * @param parentId 父分类id
     * @return
     */
    @Override
    public List<FtbNoticeCategories> queryChildCategory(String parentId) {
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbNoticeCategories::getParentId, parentId)
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        return baseMapper.selectList(wrapper);
    }

    /**
     * 查询子分类数量
     *
     * @param parentId 分类id
     * @return
     */
    @Override
    public Long queryChildCategoryNum(String parentId) {
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(FtbNoticeCategories::getParentId, parentId)
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        return baseMapper.selectCount(wrapper);
    }

    /**
     * 查询子分类id
     *
     * @param currCategory
     * @return
     */
    @Override
    public List<String> queryChildCategoryIds(FtbNoticeCategories currCategory) {
        String path = "";
        if (currCategory == null) {
            return new ArrayList<>();
        }
        if (StringUtils.isNotEmpty(currCategory.getPath())) {
            path = currCategory.getPath() + "-" + currCategory.getId();
        } else {
            path = currCategory.getId();
        }
        QueryWrapper<FtbNoticeCategories> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .likeRight(FtbNoticeCategories::getPath, path)
                .eq(FtbNoticeCategories::getEnabledMark, NoticeEnums.DeleteType.VALID.getCode());
        List<FtbNoticeCategories> categoriesList = baseMapper.selectList(wrapper);
        List<String> childIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(categoriesList)) {
            for (FtbNoticeCategories ftbNoticeCategories : categoriesList) {
                childIds.add(ftbNoticeCategories.getId());
            }
        }
        return childIds;
    }

    /**
     * 构建分类树
     *
     * @param categoriesList
     * @return
     */
    private List<FtbNoticeCategoriesDto> buildCateTree(List<FtbNoticeCategories> categoriesList) {
        List<FtbNoticeCategoriesDto> categoriesDtoList = BeanUtil.copyToList(categoriesList, FtbNoticeCategoriesDto.class);
        List<FtbNoticeCategoriesDto> retList = new ArrayList<>();
        Map<String, List<FtbNoticeCategoriesDto>> map = new HashMap<>();
        for (FtbNoticeCategoriesDto dto : categoriesDtoList) {
            fillCategoryLevel(dto);
            if (StringUtils.isEmpty(dto.getParentId())) {
                retList.add(dto);
            } else {
                List<FtbNoticeCategoriesDto> tempList = map.get(dto.getParentId());
                if (CollectionUtil.isEmpty(tempList)) {
                    tempList = new ArrayList<>();
                }
                tempList.add(dto);
                map.put(dto.getParentId(), tempList);
            }
        }

        for (FtbNoticeCategoriesDto dto : categoriesDtoList) {
            List<FtbNoticeCategoriesDto> child = map.get(dto.getId());
            if (CollectionUtil.isNotEmpty(child)) {
                dto.setChildren(child);
            }
        }
        return retList;
    }

    private void fillCategoryLevel(FtbNoticeCategoriesDto dto) {
        if (StringUtils.isEmpty(dto.getPath())) {
            dto.setLevel(0);
            return;
        }
        String[] split = dto.getPath().split("-");
        dto.setLevel(split.length - 1);
    }


}




