package com.njcn.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
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.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.db.constant.DbConstant;
import com.njcn.device.biz.commApi.CommLedgerDeptClient;
import com.njcn.device.pq.api.DeptLineFeignClient;
import com.njcn.system.api.AreaFeignClient;
import com.njcn.system.pojo.dto.AreaTreeDTO;
import com.njcn.system.pojo.po.Area;
import com.njcn.user.enums.UserResponseEnum;
import com.njcn.user.enums.UserStatusEnum;
import com.njcn.user.mapper.DeptMapper;
import com.njcn.user.mapper.UserMapper;
import com.njcn.user.pojo.dto.DeptDTO;
import com.njcn.user.pojo.param.DeptParam;
import com.njcn.user.pojo.po.Dept;
import com.njcn.user.pojo.po.User;
import com.njcn.user.pojo.vo.DeptAllTreeVO;
import com.njcn.user.pojo.vo.DeptTreeVO;
import com.njcn.user.pojo.vo.DeptVO;
import com.njcn.user.pojo.vo.PvTerminalTreeVO;
import com.njcn.user.service.IDeptService;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.RequestUtil;
import com.njcn.web.utils.WebUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hongawen
 * @since 2021-12-13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {

    private final AreaFeignClient areaFeignClient;

    private final DeptLineFeignClient deptLineFeignClient;

    private final UserMapper userMapper;

    private final CommLedgerDeptClient commLedgerDeptClient;


    @Override
    public Page<DeptVO> listDept(DeptParam.QueryParam queryParam) {
        QueryWrapper<DeptVO> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(queryParam)) {
            //查询参数不为空，进行条件填充
            if (StrUtil.isNotBlank(queryParam.getSearchValue())) {
                //部门根据名称模糊查询
                queryWrapper
                        .and(param -> param.like("sys_dept.name", queryParam.getSearchValue()));
            }
            //排序
            if (ObjectUtil.isAllNotEmpty(queryParam.getSortBy(), queryParam.getOrderBy())) {
                queryWrapper.orderBy(true, queryParam.getOrderBy().equals(DbConstant.ASC), StrUtil.toUnderlineCase(queryParam.getSortBy()));
            } else {
                //没有排序参数，默认根据sort字段排序，没有排序字段的，根据updateTime更新时间排序
                queryWrapper.orderBy(true, true, "sys_dept.sort");
            }
        }
        queryWrapper.ne("sys_dept.state", DataStateEnum.DELETED.getCode());
        //初始化分页数据
        return this.baseMapper.page(new Page<>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)), queryWrapper);
    }


    @Override
    public boolean addDept(DeptParam deptParam) {
        checkDicDataCode(deptParam, false);
        Dept dept = new Dept();
        BeanUtil.copyProperties(deptParam, dept);
        //进行先解绑，再新增
        Integer httpResult = deptLineFeignClient.removeBind(deptParam.getPid()).getData();
        if ("-1".equals(deptParam.getPid())) {
            //上层节点
            dept.setPids("0");
        } else {
            String pids = "," + deptParam.getPid();
            String pid = this.baseMapper.getIdString(deptParam.getPid());
            if (StrUtil.isBlank(deptParam.getPid())) {
                throw new BusinessException(UserResponseEnum.DEPT_PID_EXCEPTION);
            }

            //上层节点
            dept.setPids(pid + pids);
        }
        //默认为正常状态
        dept.setState(DataStateEnum.ENABLE.getCode());
        if (StrUtil.isBlank(dept.getCode())) {
            dept.setCode(dept.getId());
        }
        return this.save(dept);
    }

    @Override
    public boolean updateDept(DeptParam.DeptUpdateParam updateParam) {
        checkDicDataCode(updateParam, true);
        Dept dept = new Dept();
        BeanUtil.copyProperties(updateParam, dept);

        Dept deptTem = this.getDeptById(updateParam.getId());

        this.updateById(dept);
        if (!updateParam.getName().equals(deptTem.getName())) {
            //修改了部门名称需要修改台账信息中的单位部门
            commLedgerDeptClient.update(dept);
        }
        return true;
    }

    @Override
    public boolean deleteDept(List<String> ids) {
        LambdaQueryWrapper<Dept> queryWrapperDept = new LambdaQueryWrapper<>();
        queryWrapperDept.eq(Dept::getState, DataStateEnum.ENABLE.getCode());
        //查询出所有部门
        List<Dept> deptList = this.baseMapper.selectList(queryWrapperDept);
        List<String> allIds = new ArrayList<>();
        for (String id : ids) {
            for (Dept dept : deptList) {
                if (dept.getId().equalsIgnoreCase(id) || dept.getPids().indexOf(id) > 0) {
                    allIds.add(dept.getId());
                }
            }
        }
        allIds = allIds.stream().distinct().collect(Collectors.toList());
        // 删除部门和监测点的绑定
        this.baseMapper.deleteDeptLine(allIds);
        // 清空用户和部门的绑定关系
        this.baseMapper.deleteUserDept(allIds);
        return this.lambdaUpdate().set(Dept::getState, DataStateEnum.DELETED.getCode()).in(Dept::getId, allIds).update();
    }

    @Override
    public List<DeptTreeVO> deptTree() {
        List<Integer> deptType = WebUtil.filterDeptType();
        String deptIndex = RequestUtil.getDeptIndex();
        List<DeptTreeVO> deptList = this.baseMapper.getDeptTree(deptIndex, deptType);
        return deptList.stream()
                .filter(deptVO -> deptVO.getId().equals(deptIndex))
                .peek(deptFirst -> {
                    if (!Objects.isNull(deptFirst.getPid())) {
                        deptFirst.setLevel(deptFirst.getPids().split(StrPool.COMMA).length - 1);
                    }
                    deptFirst.setChildren(getChildren(deptFirst, deptList));
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<DeptTreeVO> existMonitorDeptTree() {
        List<Dept> deptTem = commLedgerDeptClient.existMonitorDeptTree().getData();
        if (CollectionUtil.isEmpty(deptTem)) {
            throw new BusinessException("当前没有部门存在监测点");
        }

        List<String> useMonitorIds = deptTem.stream().map(Dept::getId).collect(Collectors.toList());
        List<String> resultDeptId = deptTem.stream().map(item -> item.getPids().split(StrPool.COMMA)).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
        resultDeptId.addAll(useMonitorIds);

        List<Integer> deptType = WebUtil.filterDeptType();
        String deptIndex = RequestUtil.getDeptIndex();
        List<DeptTreeVO> deptList = this.baseMapper.getDeptTree(deptIndex, deptType);
        List<DeptTreeVO> finalDeptList = deptList.stream().filter(item -> resultDeptId.contains(item.getId())).collect(Collectors.toList());
        List<DeptTreeVO> lastList = finalDeptList.stream().peek(item -> {
            if (useMonitorIds.contains(item.getId())) {
                item.setLevel(2);
            }
        }).collect(Collectors.toList());
        return lastList.stream()
                .filter(deptVO -> deptVO.getId().equals(deptIndex))
                .peek(deptFirst -> deptFirst.setChildren(getChildren(deptFirst, lastList)))
                .collect(Collectors.toList());
    }

    @Override
    public List<DeptAllTreeVO> loginDeptTree() {
        List<Integer> deptType = WebUtil.filterDeptType();
        String deptIndex = RequestUtil.getDeptIndex();
        List<DeptAllTreeVO> deptList = this.baseMapper.getAllDeptTree(deptIndex, deptType);
        return deptList.stream()
                .filter(deptVO -> deptVO.getId().equals(deptIndex))
                .peek(deptFirst -> deptFirst.setChildren(getChildrens(deptFirst, deptList)))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> deptArea() {
        return this.baseMapper.deptArea(DataStateEnum.ENABLE.getCode());
    }

    @Override
    public List<AreaTreeDTO> getAreaTree(String id, Integer type) {
        List<String> areaTreeVO = deptArea();
        HttpResult<List<AreaTreeDTO>> areaTreeDTOList = areaFeignClient.areaDeptTree(id, type);
        List<AreaTreeDTO> list = areaTreeDTOList.getData();
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        for (AreaTreeDTO areaTreeVOList : list) {
            if (areaTreeVO.contains(areaTreeVOList.getId())) {
                areaTreeVOList.setName(areaTreeVOList.getName() + "(已被绑定)");
                areaTreeVOList.setIsFalse(1);
            }
            if (!areaTreeVOList.getChildren().isEmpty()) {
                for (AreaTreeDTO treeDTO : areaTreeVOList.getChildren()) {
                    if (areaTreeVO.contains(treeDTO.getId())) {
                        treeDTO.setName(treeDTO.getName() + "(已被绑定)");
                        treeDTO.setIsFalse(1);
                    }
                }
            }
        }
        return list;
    }


    @Override
    public List<AreaTreeDTO> getPidAreaByAreaId(String id, Integer type) {
        List<AreaTreeDTO> result = new ArrayList<>();
        List<String> deptBindAreaList = deptArea();
        List<Area> areaList = areaFeignClient.getPidAreaList(id, type).getData();
        areaList.forEach(item -> {
            AreaTreeDTO areaTreeDTO = new AreaTreeDTO();
            areaTreeDTO.setId(item.getId());
            areaTreeDTO.setPid(item.getPid());
            if (deptBindAreaList.contains(item.getId())) {
                areaTreeDTO.setName(item.getName() + "(已被绑定)");
                areaTreeDTO.setIsFalse(1);
            } else {
                areaTreeDTO.setName(item.getName());
                areaTreeDTO.setIsFalse(0);
            }
            result.add(areaTreeDTO);
        });
        return result;
    }

    @Override
    public boolean selectPid(List<String> ids) {
        // 判断是否有子节点
        List<Dept> dept = this.baseMapper.selectPid(ids, DataStateEnum.ENABLE.getCode());
        // 判断是否存在绑定关系
        HttpResult<Boolean> deptLineVOHttpResult = deptLineFeignClient.selectDeptBindLines(ids);
        // 用户是否关联
        List<User> userList = userMapper.selectDeptsId(ids, DataStateEnum.ENABLE.getCode());
        return !dept.isEmpty() || deptLineVOHttpResult.getData() != null || !userList.isEmpty();
    }

    @Override
    public String getNameByDeptId(String id) {
        if (!Objects.isNull(lambdaQuery().eq(Dept::getId, id).one())) {
            return lambdaQuery().eq(Dept::getId, id).one().getName();
        }
        return "";
    }

    @Override
    public List<DeptDTO> getDeptDescendantIndexes(String id, List<Integer> type) {
        return this.baseMapper.getDeptDescendantIndexes(id, type);
    }

    @Override
    public String getDeptIdByArea(String area) {
        Dept dept = lambdaQuery().eq(Dept::getArea, area).eq(Dept::getState, UserStatusEnum.NORMAL.getCode()).one();
        if (!Objects.isNull(dept)) {
            return dept.getId();
        } else {
            return "";
        }
    }

    @Override
    public String getAreaIdByDeptId(String deptId) {
        Dept dept = lambdaQuery().eq(Dept::getId, deptId).eq(Dept::getState, UserStatusEnum.NORMAL.getCode()).one();
        if (!Objects.isNull(dept)) {
            return dept.getArea();
        } else {
            return "";
        }
    }

    @Override
    public String getTopDeptId() {
        return this.lambdaQuery().eq(Dept::getPid, "0").one().getId();
    }

    @Override
    public List<PvTerminalTreeVO> allDeptList() {
        return this.baseMapper.allDeptList();
    }

    @Override
    public Dept getDeptById(String id) {
        return this.baseMapper.selectById(id);
    }

    @Override
    public Dept getDeptByCode(String deptCode) {
        LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Dept::getCode, deptCode).eq(Dept::getState, DataStateEnum.ENABLE.getCode());
        return this.baseMapper.selectOne(lambdaQueryWrapper);
    }


    /**
     * 校验参数，检查是否存在相同编码的部门
     */
    private void checkDicDataCode(DeptParam deptParam, boolean isExcludeSelf) {
        LambdaQueryWrapper<Dept> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deptLambdaQueryWrapper
                .eq(Dept::getName, deptParam.getName())
                .eq(Dept::getState, DataStateEnum.ENABLE.getCode()).orderByAsc(Dept::getSort);
        //更新的时候，需排除当前记录
        if (isExcludeSelf) {
            if (deptParam instanceof DeptParam.DeptUpdateParam) {
                deptLambdaQueryWrapper.ne(Dept::getId, ((DeptParam.DeptUpdateParam) deptParam).getId());
            }
        }
        int countByAccount = this.count(deptLambdaQueryWrapper);
        //大于等于1个则表示重复
        if (countByAccount >= 1) {
            throw new BusinessException(UserResponseEnum.DEPT_NAME_REPEAT);
        }
    }

    /**
     * 递归查找所有部门的下级部门
     */
    private List<DeptTreeVO> getChildren(DeptTreeVO deptFirst, List<DeptTreeVO> allDept) {
        return allDept.stream().filter(dept -> dept.getPid().equals(deptFirst.getId()))
                .peek(deptVo -> {
                    if (!Objects.isNull(deptVo.getPids())) {
                        deptVo.setLevel(deptVo.getPids().split(",").length - 1);
                    }
                    deptVo.setChildren(getChildren(deptVo, allDept));
                    if (deptVo.getType() == 0) {
                        deptVo.setName(deptVo.getAreaName());
                    }
                }).sorted(Comparator.comparing(DeptTreeVO::getSort)).collect(Collectors.toList());
    }

    /**
     * 递归查找所有部门的下级部门
     */
    private List<DeptAllTreeVO> getChildrens(DeptAllTreeVO deptFirst, List<DeptAllTreeVO> allDept) {
        return allDept.stream().filter(dept -> dept.getPid().equals(deptFirst.getId()))
                .peek(deptVo -> {
                    deptVo.setChildren(getChildrens(deptVo, allDept));
                }).sorted(Comparator.comparing(DeptAllTreeVO::getSort)).collect(Collectors.toList());
    }


    /**
     * 根据部门id获取所有子部门ids包含自身
     */
    @Override
    public List<String> getDepSonIdtByDeptId(String id) {
        List<String> sonIds = this.baseMapper.getDeptSonIds(id);
        sonIds.add(id);
        return sonIds;
    }

    @Override
    public List<String> getDepSonSelfCodetByDeptId(String id) {
        Dept dept = this.getDeptById(id);
        if (Objects.isNull(dept)) {
            throw new BusinessException(UserResponseEnum.DEPT_MISSING);
        }
        List<String> sonIds = this.baseMapper.getDeptSonSlfeIds(id);
        sonIds.add(dept.getCode());
        return sonIds;
    }

    @Override
    public List<String> getDepSonSelfCodetByCode(String code) {
        List<String> codes = new ArrayList<>();
        Dept dept = this.getDeptByCode(code);
        if (Objects.isNull(dept)) {
            throw new BusinessException(UserResponseEnum.DEPT_MISSING);
        }
        List<DeptDTO> deptList = this.baseMapper.getDeptDescendantIndexes(dept.getId(), Stream.of(0, 1).collect(Collectors.toList()));
        if (CollectionUtil.isNotEmpty(deptList)) {
            codes = deptList.stream().map(DeptDTO::getCode).collect(Collectors.toList());
            codes.add(dept.getCode());
        }
        return codes;
    }

    @Override
    public List<String> getDepSonIdByDeptId(String id) {
        List<String> sonId = this.baseMapper.getDeptSonId(id);
        if (sonId.isEmpty()) {
            sonId.add(id);
        }
        return sonId;
    }

    @Override
    public List<Dept> getDirectSonSelf(String deptId) {
        LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.and(wrapper -> wrapper
                        .eq(Dept::getPid, deptId)
                        .or()
                        .eq(Dept::getId, deptId)).eq(Dept::getState, DataStateEnum.ENABLE.getCode())
                        .orderByAsc(Dept::getSort)
        ;
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public List<Dept> getSpecialDeptList() {
        LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper
                .eq(Dept::getSpecialType, 1)
                .eq(Dept::getState, DataStateEnum.ENABLE.getCode())
                .orderByAsc(Dept::getSort)
        ;
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public Dept getRootDept() {
        LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Dept::getState, DataStateEnum.ENABLE.getCode()).eq(Dept::getPid, '0').orderByAsc(Dept::getSort);
        return this.getOne(lambdaQueryWrapper);
    }

    /**
     * @param deptId 部门id
     * @Description: "获取当前部门的的下级子部门list，如果没子部门就是返回当前部门
     */
    @Override
    public List<DeptDTO> getDepSonDetailByDeptId(String deptId) {
        List<Dept> result;

        LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Dept::getPid, deptId).
                eq(Dept::getState, DataStateEnum.ENABLE.getCode())
                .orderByAsc(Dept::getSort);
        result = this.baseMapper.selectList(lambdaQueryWrapper);
        if (CollectionUtils.isEmpty(result)) {
            LambdaQueryWrapper<Dept> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
            deptLambdaQueryWrapper.eq(Dept::getId, deptId).
                    eq(Dept::getState, DataStateEnum.ENABLE.getCode());
            result = this.baseMapper.selectList(deptLambdaQueryWrapper);
        }
        return result.stream().map(temp -> {
            DeptDTO deptDTO = new DeptDTO();
            BeanUtils.copyProperties(temp, deptDTO);
            return deptDTO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<String> getUpByDeptIds(String deptId) {
        // 查询出所有的部门
        List<Dept> allDept = this.getAllDept();
        // 递归找出所有上级部门，排除根目录
        List<Dept> upDeptList = allDept.stream()
                .filter(dept -> dept.getId().equals(deptId))
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(upDeptList)) {
            return new ArrayList<>();
        }
        upDeptList.addAll(getParentDept(upDeptList, allDept));
        //递归出所有的上级部门
        return upDeptList.stream().map(Dept::getId).collect(Collectors.toList());
    }

    /**
     * 找出当前部门的父级部门
     *
     * @param upDeptList 当前部门
     * @param allDept    所有部门
     * @return 父级部门
     */
    private List<Dept> getParentDept(List<Dept> upDeptList, List<Dept> allDept) {
        if (CollectionUtil.isEmpty(upDeptList)) {
            return new ArrayList<>();
        } else {
            List<Dept> parentDeptList = new ArrayList<>();
            upDeptList.forEach(upDept -> {
                List<Dept> parentDept = allDept.stream().filter(dept -> dept.getId().equals(upDept.getPid())).collect(Collectors.toList());
                parentDeptList.addAll(parentDept);
            });
            return getParentDept(parentDeptList, allDept);
        }
    }

    @Override
    public List<Dept> getDeptByCodeList(List<String> list) {
        return this.lambdaQuery().in(Dept::getCode, list).eq(Dept::getState, DataStateEnum.ENABLE.getCode()).list();
    }

    @Override
    public List<Dept> getDeptInfoListByIds(List<String> deptIds) {
        return this.lambdaQuery().in(Dept::getId, deptIds).eq(Dept::getState, DataStateEnum.ENABLE.getCode()).list();
    }

    @Override
    public List<Dept> getAllDept() {
        return this.lambdaQuery().eq(Dept::getState, DataStateEnum.ENABLE.getCode()).list();
    }

    @Override
    public List<Tree<String>> orgTreeSelector() {
        List<Dept> deptList = this.lambdaQuery().eq(Dept::getState, DataStateEnum.ENABLE.getCode()).list();
        List<TreeNode<String>> treeNodeList = deptList.stream().map(dept ->
                        new TreeNode<>(dept.getId(), dept.getPid(), dept.getName(), dept.getSort()))
                .collect(Collectors.toList());
        return TreeUtil.build(treeNodeList, "0");
    }

}
