package com.njcn.gather.system.dictionary.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.system.dictionary.mapper.DictTreeMapper;
import com.njcn.gather.system.dictionary.pojo.param.DictTreeParam;
import com.njcn.gather.system.dictionary.pojo.po.DictTree;
import com.njcn.gather.system.dictionary.service.IDictTreeService;
import com.njcn.gather.system.pojo.constant.DictConst;
import com.njcn.gather.system.pojo.enums.SystemResponseEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author caozehui
 * @data 2024/11/8
 */
@Service
@RequiredArgsConstructor
public class DictTreeServiceImpl extends ServiceImpl<DictTreeMapper, DictTree> implements IDictTreeService {


    @Override
    public List<DictTree> getTreeByCode(String code) {
        List<DictTree> dictTree = this.queryTree();

        if (ObjectUtil.isNotEmpty(dictTree)) {
            dictTree = dictTree.stream().filter(item -> item.getCode().equals(code)).collect(Collectors.toList());
        }

        return dictTree;
    }

    @Override
    public List<DictTree> getTreeByName(String name) {
        List<DictTree> dictTree = this.queryTree();

        if (ObjectUtil.isNotEmpty(dictTree) && StrUtil.isNotBlank(name)) {
            dictTree = dictTree.stream().filter(item -> item.getName().contains(name)).collect(Collectors.toList());
        }
        return dictTree;
    }

    @Override
    @Transactional
    public boolean addDictTree(DictTreeParam dictTreeParam) {
        dictTreeParam.setName(dictTreeParam.getName().trim());
        checkRepeat(dictTreeParam, false);
        boolean result;
        DictTree dictTree = new DictTree();
        BeanUtils.copyProperties(dictTreeParam, dictTree);
        if (!Objects.equals(dictTree.getPid(), DictConst.FATHER_ID)) {
            QueryWrapper<DictTree> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id", dictTree.getPid());
            DictTree instance = this.baseMapper.selectOne(queryWrapper);
            dictTree.setPids(instance.getPids() + StrPool.COMMA + instance.getId());
        } else {
            dictTree.setPids(DictConst.FATHER_ID);
        }
        dictTree.setState(DictConst.ENABLE);
        result = this.save(dictTree);
        return result;
    }

    @Override
    @Transactional
    public boolean updateDictTree(DictTreeParam.UpdateParam param) {
        param.setName(param.getName().trim());
        DictTree dictTree = this.getById(param.getId());
//        if ("975f63baeb6f653c54fca226a9ae36ca".equals(param.getId()) || dictTree.getPids().contains("975f63baeb6f653c54fca226a9ae36ca")) {
//            throw new BusinessException(SystemResponseEnum.CAN_NOT_UPDATE_USED_DICT);
//        }
        checkRepeat(param, true);
        DictTree copyDictTree = new DictTree();
        BeanUtils.copyProperties(param, copyDictTree);
        return this.updateById(copyDictTree);
    }

    @Override
    @Transactional
    public boolean deleteDictTree(String id) {
        boolean result = false;
        DictTree dictTree = this.getById(id);
        if ("975f63baeb6f653c54fca226a9ae36ca".equals(id) || dictTree.getPids().contains("975f63baeb6f653c54fca226a9ae36ca")) {
            throw new BusinessException(SystemResponseEnum.CAN_NOT_DELETE_USED_DICT);
        }

        List<DictTree> childrenList = this.lambdaQuery().eq(DictTree::getState, DictConst.ENABLE).eq(DictTree::getPid, id).list();
        if (CollectionUtils.isEmpty(childrenList)) {
            result = this.lambdaUpdate().set(DictTree::getState, DictConst.DELETE).in(DictTree::getId, id).update();
        } else {
            throw new BusinessException(SystemResponseEnum.EXISTS_CHILDREN_NOT_DELETE);
        }
        return result;
    }

    @Override
    public DictTree queryById(String id) {
        return this.lambdaQuery().eq(DictTree::getId, id).eq(DictTree::getState, DictConst.ENABLE).one();
    }

    @Override
    public List<DictTree> queryTree() {
        LambdaQueryWrapper<DictTree> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DictTree::getState, DictConst.ENABLE);
        List<DictTree> dictTreeList = this.list(lambdaQueryWrapper);
        return dictTreeList.stream().filter(item -> DictConst.FATHER_ID.equals(item.getPid())).peek(item -> {
//            item.setLevel(0);
            item.setChildren(getChildren(item, dictTreeList));
        }).sorted(Comparator.comparingInt(DictTree::getSort)).collect(Collectors.toList());
    }

    @Override
    public List<DictTree> getDictTreeById(List<String> ids) {
        return this.list(new LambdaQueryWrapper<DictTree>()
                .in(CollUtil.isNotEmpty(ids), DictTree::getId, ids)
        );
    }

    @Override
    public DictTree getDictTreeByCode(String code) {
        return this.getOne(new LambdaQueryWrapper<DictTree>()
                .eq(DictTree::getCode, code)
        );
    }

    @Override
    public List<DictTree> listByFatherIds(List<String> fatherIdList) {
        if (CollUtil.isNotEmpty(fatherIdList)) {
            return this.lambdaQuery().in(DictTree::getPid, fatherIdList).eq(DictTree::getState, DictConst.ENABLE).list();
        }
        return null;
    }

    @Override
    public DictTree queryParentById(String id) {
        DictTree temp =  this.lambdaQuery().eq(DictTree::getId, id).eq(DictTree::getState, DictConst.ENABLE).one();
        return this.lambdaQuery().eq(DictTree::getId, temp.getPid()).one();
    }

    @Override
    public List<String> getChildIds(String scriptId) {
        List<DictTree> subTree = this.lambdaQuery().eq(DictTree::getPid, scriptId)
                .eq(DictTree::getState, DictConst.ENABLE)
                .list();
        if(CollectionUtil.isNotEmpty(subTree)){
            return subTree.stream().map(DictTree::getId).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    public List<String> sort(List<String> scriptList) {
        if (CollectionUtil.isEmpty(scriptList)) {
            return Collections.emptyList();
        }

        return this.lambdaQuery()
                .in(DictTree::getId, scriptList)
                .orderByAsc(DictTree::getSort)
                .list()
                .stream()
                .map(DictTree::getId)
                .collect(Collectors.toList());
    }

    private void checkRepeat(DictTreeParam dictTreeParam, boolean isExcludeSelf) {
        LambdaQueryWrapper<DictTree> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DictTree::getPid, dictTreeParam.getPid()) // 同一父节点下不能有相同的code
                .eq(DictTree::getCode, dictTreeParam.getCode())
                .eq(DictTree::getState, DictConst.ENABLE);
        if (isExcludeSelf) {
            if (dictTreeParam instanceof DictTreeParam.UpdateParam) {
                wrapper.ne(DictTree::getId, ((DictTreeParam.UpdateParam) dictTreeParam).getId());
            }
        }
        int count = this.count(wrapper);
        if (count > 0) {
            throw new BusinessException(SystemResponseEnum.CODE_REPEAT);
        }
    }

    private List<DictTree> filterTreeByName(List<DictTree> tree, String keyword) {
        if (CollectionUtils.isEmpty(tree) || !StrUtil.isNotBlank(keyword)) {
            return tree;
        }
        filter(tree, keyword);
        return tree;
    }

    private void filter(List<DictTree> list, String keyword) {
        for (int i = list.size() - 1; i >= 0; i--) {
            DictTree dictTree = list.get(i);
            List<DictTree> children = dictTree.getChildren();
            if (!dictTree.getName().contains(keyword)) {
                if (!CollectionUtils.isEmpty(children)) {
                    filter(children, keyword);
                }
                if (CollectionUtils.isEmpty(dictTree.getChildren())) {
                    list.remove(i);
                }
            }
//            else {
//                if (!CollectionUtils.isEmpty(children)) {
//                    filter(children, keyword);
//                }
//            }
        }
    }

    private List<DictTree> getChildren(DictTree dictTree, List<DictTree> all) {
        return all.stream().filter(item -> item.getPid().equals(dictTree.getId())).peek(item -> {
//            item.setLevel(dictTree.getLevel() + 1);
            item.setChildren(getChildren(item, all));
        }).sorted(Comparator.comparingInt(DictTree::getSort)).collect(Collectors.toList());
    }
}