package com.njcn.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrPool;
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.constant.BizParamConstant;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.mapper.SysDicTreePOMapper;
import com.njcn.system.pojo.constant.DicState;
import com.njcn.system.pojo.param.DictTreeParam;
import com.njcn.system.pojo.po.SysDicTreePO;
import com.njcn.system.pojo.vo.DictTreeVO;
import com.njcn.system.service.SysDicTreePOService;
import com.njcn.user.enums.UserResponseEnum;
import com.njcn.user.pojo.constant.FunctionState;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * Description:
 * Date: 2023/6/9  14:00【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
public class SysDicTreePOServiceImpl extends ServiceImpl<SysDicTreePOMapper, SysDicTreePO> implements SysDicTreePOService {

    private final RedisUtil redisUtil;

    @Override
    public void refreshDictTreeCache() {
        LambdaQueryWrapper<SysDicTreePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysDicTreePO::getStatus,0);
        List<SysDicTreePO> list = this.list(queryWrapper);
        redisUtil.saveByKey(AppRedisKey.DICT_TREE,list);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean addDictTree(DictTreeParam dictTreeParam) {
        checkFunctionParam(dictTreeParam,false);
        boolean result;
        SysDicTreePO sysDicTreePO = new SysDicTreePO();
        BeanUtils.copyProperties(dictTreeParam, sysDicTreePO);
        if (!Objects.equals(sysDicTreePO.getPid(), BizParamConstant.PARENT_ID)) {
            QueryWrapper<SysDicTreePO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id", sysDicTreePO.getPid());
            SysDicTreePO instance = this.baseMapper.selectOne(queryWrapper);
            sysDicTreePO.setPids(instance.getPids() + StrPool.COMMA + instance.getId());
        } else {
            sysDicTreePO.setPids(BizParamConstant.PARENT_ID);
        }
        sysDicTreePO.setStatus(0);
        if (Objects.nonNull(dictTreeParam.getType())) {
            sysDicTreePO.setType(dictTreeParam.getType());
        }
        result = this.save(sysDicTreePO);
        if (result) {
            refreshDictTreeCache();
        }
        return result;
    }

    @Override
    public boolean updateDictTree(DictTreeParam dictTreeParam) {
        checkFunctionParam(dictTreeParam,true);
        boolean result;
        SysDicTreePO sysDicTreePO = new SysDicTreePO();
        BeanUtils.copyProperties(dictTreeParam, sysDicTreePO);
        if (Objects.isNull(sysDicTreePO.getType())) {
            sysDicTreePO.setType(null);
        }
        result = this.updateById(sysDicTreePO);
        if (result) {
            refreshDictTreeCache();
        }
        return result;
    }

    @Override
    public boolean deleteDictTree(String id) {
        boolean result = this.lambdaUpdate().set(SysDicTreePO::getStatus, DicState.DELETE).in(SysDicTreePO::getId,id).update();
        if (result) {
            refreshDictTreeCache();
        }
        return result;
    }

    @Override
    public List<DictTreeVO> queryByPid(String pid) {
        List<DictTreeVO> collect = new ArrayList<>();
        LambdaQueryWrapper<SysDicTreePO> query = new LambdaQueryWrapper<>();
        query.eq(SysDicTreePO::getPid, pid).eq(SysDicTreePO::getStatus, "0").orderByDesc(SysDicTreePO::getSort);
        List<SysDicTreePO> resultList = this.list(query);

        SysDicTreePO byId = this.getById(pid);

        if (CollUtil.isNotEmpty(resultList)) {
            collect = resultList.stream().map(temp -> {
                DictTreeVO resultVO = new DictTreeVO();
                BeanUtils.copyProperties(temp, resultVO);
                resultVO.setPname(Objects.nonNull(byId) ? byId.getName() : "最高级");
                return resultVO;
            }).collect(Collectors.toList());
        }
        return collect;
    }

    @Override
    public DictTreeVO queryByCode(String code) {
        LambdaQueryWrapper<SysDicTreePO> query = new LambdaQueryWrapper<>();
        query.clear();
        query.eq(SysDicTreePO::getCode, code).eq(SysDicTreePO::getStatus, "0");
        SysDicTreePO result = this.getOne(query);

        if (result != null) {
            DictTreeVO resultVO = new DictTreeVO();
            BeanUtils.copyProperties(result, resultVO);
            return resultVO;
        }

        return null;
    }

    @Override
    public List<DictTreeVO> queryLastLevelById(String id) {
        return this.baseMapper.queryLastLevelById(id);
    }

    @Override
    public SysDicTreePO queryById(String id) {
        return this.lambdaQuery().eq(SysDicTreePO::getId, id).eq(SysDicTreePO::getStatus, 0).one();
    }

    @Override
    public List<SysDicTreePO> queryAll() {
        LambdaQueryWrapper<SysDicTreePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysDicTreePO::getStatus, 0);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public List<SysDicTreePO> queryAllByType(Integer type) {
        LambdaQueryWrapper<SysDicTreePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysDicTreePO::getStatus, 0).eq(SysDicTreePO::getType, type);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public List<SysDicTreePO> queryTree() {
        LambdaQueryWrapper<SysDicTreePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysDicTreePO::getStatus, 0);
        List<SysDicTreePO> sysDicTreePOList = this.list(lambdaQueryWrapper);
        return sysDicTreePOList.stream().filter(item -> BizParamConstant.PARENT_ID.equals(item.getPid()) && !item.getCode().equals(DicDataTypeEnum.DEVICE_UNIT.getCode())).peek(item -> {
            item.setLevel(0);
            item.setChildren(getChildren(item, sysDicTreePOList));
        }).collect(Collectors.toList());
    }

    @Override
    public List<SysDicTreePO> queryFirstNodeList(Integer type) {
        LambdaQueryWrapper<SysDicTreePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysDicTreePO::getPid,"0").eq(SysDicTreePO::getStatus,0).eq(SysDicTreePO::getType,type);
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public List<SysDicTreePO> queryByCodeList(String code) {
        List<SysDicTreePO> sysDicTreePOList = this.list(new LambdaQueryWrapper<SysDicTreePO>().eq(SysDicTreePO::getStatus, 0));
        return sysDicTreePOList.stream().filter(item -> item.getCode().equals(code)).peek(item -> {
            item.setLevel(0);
            item.setChildren(getChildren(item, sysDicTreePOList));
        }).collect(Collectors.toList());
    }

    @Override
    public List<SysDicTreePO> queryDictType(Integer lineType, Integer conType) {
        DictTreeVO vo = queryByCode("Statistical_Type");
        LambdaQueryWrapper<SysDicTreePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysDicTreePO::getPid,vo.getId())
                .eq(SysDicTreePO::getStatus,0)
                .orderByAsc(SysDicTreePO::getSort);
        //治理APF指标
        if (Objects.equals(lineType,0)) {
            queryWrapper.eq(SysDicTreePO::getType,3);
        }
        //通用指标
        else {
            //0-星型接线
            if (Objects.equals(conType,0)) {
                queryWrapper.in(SysDicTreePO::getType, Arrays.asList(2,4));
            }
            //1-角型接线
            else if (Objects.equals(conType,1)) {
                queryWrapper.in(SysDicTreePO::getType,Arrays.asList(2,5));
            }
            //2-V型接线
            else if (Objects.equals(conType,2)) {
                queryWrapper.in(SysDicTreePO::getType,Arrays.asList(2,5,6));
            }
        }
        return this.list(queryWrapper);
    }


    private List<SysDicTreePO> getChildren(SysDicTreePO sysDicTreePO, List<SysDicTreePO> all) {
        return all.stream().filter(item -> item.getPid().equals(sysDicTreePO.getId())).peek(item -> {
            item.setLevel(sysDicTreePO.getLevel() + 1);
            item.setChildren(getChildren(item, all));
        }).collect(Collectors.toList());
    }

    private void checkFunctionParam(DictTreeParam dictTreeParam, boolean isExcludeSelf) {
        // 检查同名同父级的功能是否存在
        checkFunctionDuplicate(dictTreeParam, isExcludeSelf,
                wrapper -> wrapper.eq(SysDicTreePO::getName, dictTreeParam.getName())
                        .eq(SysDicTreePO::getPid, dictTreeParam.getPid()),
                UserResponseEnum.FUNCTION_NAME_EXIST);
        // 检查同路径同父级的功能是否存在
        checkFunctionDuplicate(dictTreeParam, isExcludeSelf,
                wrapper -> wrapper.eq(SysDicTreePO::getCode, dictTreeParam.getCode())
                        .eq(SysDicTreePO::getPid, dictTreeParam.getPid()),
                UserResponseEnum.FUNCTION_CODE_EXIST);
    }

    private void checkFunctionDuplicate(DictTreeParam dictTreeParam,
                                        boolean isExcludeSelf,
                                        Consumer<LambdaQueryWrapper<SysDicTreePO>> queryCustomizer,
                                        UserResponseEnum errorEnum) {
        LambdaQueryWrapper<SysDicTreePO> wrapper = new LambdaQueryWrapper<>();
        // 应用公共条件
        wrapper.eq(SysDicTreePO::getStatus, FunctionState.DELETE);
        // 应用自定义条件
        queryCustomizer.accept(wrapper);
        // 排除自身条件
        if (isExcludeSelf && dictTreeParam instanceof DictTreeParam.DictTreeUpdateParam) {
            wrapper.ne(SysDicTreePO::getId, ((DictTreeParam.DictTreeUpdateParam) dictTreeParam).getId());
        }
        // 检查是否存在重复记录
        if (this.count(wrapper) >= 1) {
            throw new BusinessException(errorEnum);
        }
    }

}
