package com.tuoheng.admin.service.dept.update;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.admin.constant.SystemConstant;
import com.tuoheng.admin.dto.RoadSectionDto;
import com.tuoheng.admin.entity.*;
import com.tuoheng.admin.enums.code.dept.EditDeptCodeEnum;
import com.tuoheng.admin.mapper.DeptMapper;
import com.tuoheng.admin.mapper.RoadDeptMapper;
import com.tuoheng.admin.mapper.SectionDeptMapper;
import com.tuoheng.admin.request.dept.EditDeptRequest;
import com.tuoheng.admin.utils.CurrentUserUtil;
import com.tuoheng.common.core.utils.DateUtils;
import com.tuoheng.common.core.utils.JsonResult;
import com.tuoheng.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 添加部门业务层处理
 *
 * @author wanjing
 * @team tuoheng
 * @date 2022-11-19
 */
@Slf4j
@Service
public class UpdateDeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private RoadDeptMapper roadDeptMapper;

    @Autowired
    private SectionDeptMapper sectionDeptMapper;

    /**
     * 修改部门信息，涉及公路、路段数据
     *
     * @param oldEditDeptRequest
     * @param newEditDeptRequest
     * @return
     */
    public JsonResult update(EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        log.info("进入修改部门业务接口");
        String tenantId = CurrentUserUtil.getTenantId();
        JsonResult result = this.check(tenantId, oldEditDeptRequest, newEditDeptRequest);
        if (0 != result.getCode()) {
            log.info("修改部门业务接口：校验失败：{}", result.getMsg());
            return result;
        }

        // 修改部门数据
        result = this.updateDept(tenantId, oldEditDeptRequest, newEditDeptRequest);
        if (0 != result.getCode()) {
            log.info("修改部门业务接口：修改部门失败：{}", result.getMsg());
            return JsonResult.error(EditDeptCodeEnum.EDIT_DEPT_IS_FAILED.getCode(), EditDeptCodeEnum.EDIT_DEPT_IS_FAILED.getMsg());
        }

        // 处理公路与部门数据
        this.roadHandle(tenantId, oldEditDeptRequest, newEditDeptRequest);

        // 处理路段与部门数据
        this.sectionhandle(tenantId, oldEditDeptRequest, newEditDeptRequest);

        log.info("修改部门业务接口：修改部门成功：{}");
        return JsonResult.success("修改部门成功");
    }

    /**
     * 检查参数
     *
     * @param tenantId
     * @param newEditDeptRequest
     * @return
     */
    private JsonResult check(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        if (StringUtils.isEmpty(newEditDeptRequest.getPid())) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_PID_IS_NULL.getCode(), EditDeptCodeEnum.DEPT_PID_IS_NULL.getMsg());
        }

        if (StringUtils.isEmpty(newEditDeptRequest.getId())) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_ID_IS_NOT_NULL.getCode(), EditDeptCodeEnum.DEPT_ID_IS_NOT_NULL.getMsg());
        }

        if (StringUtils.isEmpty(newEditDeptRequest.getName())) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_NAME_IS_NOT_NULL.getCode(), EditDeptCodeEnum.DEPT_NAME_IS_NOT_NULL.getMsg());
        }

        if (!oldEditDeptRequest.getId().equals(newEditDeptRequest.getId())) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_ID_IS_NOT_SAME.getCode(), EditDeptCodeEnum.DEPT_ID_IS_NOT_SAME.getMsg());
        }

        if (!oldEditDeptRequest.getPid().equals(newEditDeptRequest.getPid())) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_PID_IS_NOT_SAME.getCode(), EditDeptCodeEnum.DEPT_PID_IS_NOT_SAME.getMsg());
        }

        // 判断部门是否存在
        Dept dept = deptMapper.selectOne(new LambdaQueryWrapper<Dept>()
                .eq(Dept::getTenantId, tenantId)
                .eq(Dept::getId, newEditDeptRequest.getId())
                .eq(Dept::getMark, 1));
        if (null == dept) {
            return JsonResult.error(EditDeptCodeEnum.DEPT_IS_NOT_EXIST.getCode(), EditDeptCodeEnum.DEPT_IS_NOT_EXIST.getMsg());
        }

        if (SystemConstant.ROOT_DEPT_PID.equals(newEditDeptRequest.getPid())) {
            // 判断部门是否存在
            Dept parentDept = deptMapper.selectOne(new LambdaQueryWrapper<Dept>()
                    .eq(Dept::getTenantId, tenantId)
                    .eq(Dept::getId, newEditDeptRequest.getId())
                    .eq(Dept::getMark, 1));
            if (null == parentDept) {
                return JsonResult.error(EditDeptCodeEnum.DEPT_IS_NOT_EXIST.getCode(), EditDeptCodeEnum.DEPT_IS_NOT_EXIST.getMsg());
            }
        }

        if (!oldEditDeptRequest.getName().equals(newEditDeptRequest.getName())) {
            // 判断是否已存在该部门名称，同部门下，部门名称不能重复,
            // 注意要增加id不能与自己的相同的判断
            Integer count = deptMapper.selectCount(new LambdaQueryWrapper<Dept>()
                    .eq(Dept::getTenantId, tenantId)
                    .eq(Dept::getPid, newEditDeptRequest.getPid())
                    .ne(Dept::getId, newEditDeptRequest.getId())
                    .eq(Dept::getName, newEditDeptRequest.getName())
                    .eq(Dept::getMark, 1));

            // 系统中已存在
            if (count > 0) {
                return JsonResult.error(EditDeptCodeEnum.DEPT_NAME_IS_ALREADY_EXIST.getCode(), EditDeptCodeEnum.DEPT_NAME_IS_ALREADY_EXIST.getMsg());
            }
        }

        if (CollectionUtil.isNotEmpty(newEditDeptRequest.getRoadSectionDtoList())) {
            List<Section> sectionList;
            List<RoadSectionDto> roadSectionDtoList = newEditDeptRequest.getRoadSectionDtoList();
            for (RoadSectionDto roadSectionDto : roadSectionDtoList) {
                sectionList = roadSectionDto.getSectionList();
                if (CollectionUtil.isEmpty(sectionList)) {
                    return JsonResult.error(EditDeptCodeEnum.SECTION_IS_NULL.getCode(), EditDeptCodeEnum.SECTION_IS_NULL.getMsg());
                }
            }
        }

        return JsonResult.success();
    }

    /**
     * 修改部门信息
     * 根据业务修改，部门只能修改部门名称，若部门名称和原来一致，可不用修改
     *
     * @param tenantId
     * @param oldEditDeptRequest
     * @param newEditDeptRequest
     * @return
     */
    private JsonResult updateDept(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        if (!oldEditDeptRequest.getName().equals(newEditDeptRequest.getName())) {
            Dept dept = new Dept();
            dept.setId(newEditDeptRequest.getId());
            dept.setTenantId(tenantId);
            dept.setName(newEditDeptRequest.getName());
            dept.setFullname(newEditDeptRequest.getName());
            dept.setUpdateUser(CurrentUserUtil.getUserId());
            dept.setUpdateTime(DateUtils.now());

            Integer rowId = deptMapper.update(dept);
            log.info("修改部门, 返回结果: deptId={}", dept.getId());
            if (rowId <= 0) {
                return JsonResult.error(EditDeptCodeEnum.EDIT_DEPT_IS_FAILED.getCode(), EditDeptCodeEnum.EDIT_DEPT_IS_FAILED.getMsg());
            }
        }
        return JsonResult.success();
    }

    /**
     * 处理公路和部门数据
     *
     * @param tenantId
     * @param oldEditDeptRequest
     * @param newEditDeptRequest
     */
    private void roadHandle(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        List<RoadSectionDto> oldRoadSectionList = oldEditDeptRequest.getRoadSectionDtoList();
        List<String> oldRoadIdList = null;
        if (CollectionUtil.isNotEmpty(oldRoadSectionList)) {
            oldRoadIdList = oldRoadSectionList.stream().map(o -> o.getRoad().getId()).collect(Collectors.toList());
        }
        List<RoadSectionDto> newRoadSectionList = newEditDeptRequest.getRoadSectionDtoList();
        List<String> newRoadIdList = null;
        if (CollectionUtil.isNotEmpty(newRoadSectionList)) {
            newRoadIdList = newRoadSectionList.stream().map(o -> o.getRoad().getId()).collect(Collectors.toList());
        }

        // 交集：存在公路, 不做处理
//        Collection<String> union = org.apache.commons.collections4.CollectionUtils.union(oldRoadIdList, newRoadIdList);

        // 差集：新增公路
        Collection<String> addRoadIdList;
        if (CollectionUtil.isNotEmpty(oldRoadIdList)) {
            addRoadIdList = org.apache.commons.collections4.CollectionUtils.subtract(newRoadIdList, oldRoadIdList);
        } else {
            addRoadIdList = newRoadIdList;
        }
        if (CollectionUtil.isNotEmpty(addRoadIdList)) {
            // 去重，防止前端提交了重复的数据
            addRoadIdList= addRoadIdList.stream().distinct().collect(Collectors.toList());
            this.addRoadToDept(tenantId, newEditDeptRequest.getId(), addRoadIdList);
        }

        // 差集：删除公路
        if (CollectionUtil.isNotEmpty(oldRoadIdList)) {
            Collection<String> subRoadIdList = org.apache.commons.collections4.CollectionUtils.subtract(oldRoadIdList, newRoadIdList);
            Map<String, Long> oldRoadIdMap = oldRoadIdList.stream().collect(Collectors.groupingBy(p -> p, Collectors.counting()));
            Map<String, Long> subRoadIdMap = subRoadIdList.stream().collect(Collectors.groupingBy(p -> p, Collectors.counting()));
            if (CollectionUtil.isNotEmpty(subRoadIdList)) {
                List<String> deleteRoadIdList = new ArrayList<>();
                for (String roadId : subRoadIdList) {
                    Long oldCount = oldRoadIdMap.get(roadId);
                    Long subCount = subRoadIdMap.get(roadId);
                    if (oldCount.equals(subCount)) {
                        deleteRoadIdList.add(roadId);
                    }
                }
                if (CollectionUtil.isNotEmpty(deleteRoadIdList)) {
                    this.removeRoadToDept(tenantId, newEditDeptRequest.getId(), subRoadIdList);
                }
            }
        }
    }

    /**
     * 新增公路部门数据
     * 1、先删除原有记录数据
     * 2、新增此次提交的数据
     *
     * @param tenantId   租户Id
     * @param deptId     部门Id
     * @param roadIdList 公路Id集合
     * @return 结果
     */
    private void addRoadToDept(String tenantId, String deptId, Collection<String> roadIdList) {
        List<RoadDept> list = new ArrayList<>();
        RoadDept roadDept;
        RoadDept roadDeptTmp;
        for (String roadId : roadIdList) {
            roadDept = new RoadDept();
            roadDept.setTenantId(tenantId);
            roadDept.setDeptId(deptId);
            roadDept.setRoadId(roadId);

            // 判断是否存在, 存在则不用再次添加
            roadDeptTmp = roadDeptMapper.selectOne(new LambdaQueryWrapper<RoadDept>()
                    .eq(RoadDept::getTenantId, tenantId)
                    .eq(RoadDept::getDeptId, deptId)
                    .eq(RoadDept::getRoadId, roadId));
            if (null != roadDeptTmp) {
                continue;
            }
            list.add(roadDept);
        }
        if (CollectionUtil.isNotEmpty(list)) {
            roadDeptMapper.insertBatch(list);
        }
    }

    /**
     * 移除公路部门数据
     * 如若是该公路被分配给了子部门或子子部门，同样一并删除
     *
     * @param tenantId   租户Id
     * @param deptId     部门Id
     * @param roadIdList 公路Id集合
     * @return 结果
     */
    private void removeRoadToDept(String tenantId, String deptId, Collection<String> roadIdList) {
        // 查找部门id及下面所有的子部门
        Dept parentDept = new Dept();
        parentDept.setTenantId(tenantId);
        parentDept.setId(deptId);

        List<Dept> deptList = new ArrayList<>();
        deptList.add(parentDept);
        queryChildDeptList(deptList, parentDept);

        List<String> deptIdList = deptList.stream().map(p -> p.getId()).collect(Collectors.toList());;
        for (String roadId : roadIdList) {
            roadDeptMapper.delete(new LambdaQueryWrapper<RoadDept>()
                    .eq(RoadDept::getTenantId, tenantId)
                    .eq(RoadDept::getRoadId, roadId)
                    .in(RoadDept::getDeptId, deptIdList));
        }
    }

    /**
     * 处理路段和部门数据
     *
     * @param tenantId
     * @param oldEditDeptRequest
     * @param newEditDeptRequest
     */
    private void sectionhandle(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        List<RoadSectionDto> oldRoadSectionList = oldEditDeptRequest.getRoadSectionDtoList();
        List<Section> oldSectionList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(oldRoadSectionList)) {
            for (RoadSectionDto roadSectionDto : oldRoadSectionList) {
                oldSectionList.addAll(roadSectionDto.getSectionList());
            }
        }

        List<RoadSectionDto> newRoadSectionList = newEditDeptRequest.getRoadSectionDtoList();
        List<Section> newSectionList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(newRoadSectionList)) {
            for (RoadSectionDto roadSectionDto : newRoadSectionList) {
                newSectionList.addAll(roadSectionDto.getSectionList());
            }
        }
        List<String> newSectionIdList = newSectionList.stream().map(o -> o.getId()).collect(Collectors.toList());

        // 差集：新增路段
        Collection<String> addSectionIdList;
        if (CollectionUtil.isNotEmpty(oldSectionList)) {
            List<String> oldSectionIdList = oldSectionList.stream().map(o -> o.getId()).collect(Collectors.toList());
            addSectionIdList = org.apache.commons.collections4.CollectionUtils.subtract(newSectionIdList, oldSectionIdList);
        } else {
            addSectionIdList = newSectionIdList;
        }
        if (CollectionUtil.isNotEmpty(addSectionIdList)) {
            // 去重，防止前端提交了重复的数据
            addSectionIdList= addSectionIdList.stream().distinct().collect(Collectors.toList());
            // 添加路段和部门数据
            this.addSectionToDept(tenantId, newEditDeptRequest.getId(), addSectionIdList);
        }

        // 差集：删除路段
        if (CollectionUtil.isNotEmpty(oldSectionList)) {
            List<String> oldSectionIdList = oldSectionList.stream().map(o -> o.getId()).collect(Collectors.toList());
            Collection<String> subSectionIdList = org.apache.commons.collections4.CollectionUtils.subtract(oldSectionIdList, newSectionIdList);
            if (CollectionUtil.isNotEmpty(subSectionIdList)) {
                // 删除路段和部门数据
                this.removeSectionToDept(tenantId, newEditDeptRequest.getId(), subSectionIdList);
            }
        }
    }

    /**
     * 新增路段部门数据
     * 1、先删除原有记录数据
     * 2、新增此次提交的数据
     *
     * @param tenantId      租户Id
     * @param deptId        部门Id
     * @param sectionIdList 路段id集合
     * @return 结果
     */
    private void addSectionToDept(String tenantId, String deptId, Collection<String> sectionIdList) {
        List<SectionDept> list = new ArrayList<>();
        SectionDept sectionDept;
        SectionDept sectionDeptTmp;
        for (String sectionId : sectionIdList) {
            sectionDept = new SectionDept();
            sectionDept.setTenantId(tenantId);
            sectionDept.setDeptId(deptId);
            sectionDept.setSectionId(sectionId);

            // 判断是否存在, 存在则不用再次添加
            sectionDeptTmp = sectionDeptMapper.selectOne(new LambdaQueryWrapper<SectionDept>()
                    .eq(SectionDept::getTenantId, tenantId)
                    .eq(SectionDept::getDeptId, deptId)
                    .eq(SectionDept::getSectionId, sectionId));
            if (null != sectionDeptTmp) {
               continue;
            }
            list.add(sectionDept);
        }

        if (CollectionUtil.isNotEmpty(list)) {
            sectionDeptMapper.insertBatch(list);
        }
    }

    /**
     * 移除路段部门数据
     *
     * @param tenantId      租户Id
     * @param deptId        部门Id
     * @param sectionIdList 路段Id集合
     * @return 结果
     */
    private void removeSectionToDept(String tenantId, String deptId, Collection<String> sectionIdList) {
        List<String> deptIdList = deptMapper.selectAllChildListById(deptId);
        if (CollectionUtil.isEmpty(deptIdList)) {
            return;
        }
        for (String sectionId : sectionIdList) {
            sectionDeptMapper.delete(new LambdaQueryWrapper<SectionDept>()
                    .eq(SectionDept::getTenantId, tenantId)
                    .eq(SectionDept::getSectionId, sectionId)
                    .in(SectionDept::getDeptId, deptIdList));
        }
    }

    /**
     * 递归查询子部门信息
     * 1、递归算法，效率比较低，考虑时间数据量不会太多，后期可优化
     * 2、另一方案，通过数据库查询，根据pid，查询该部门下所有子部门及子子部门数据
     *
     * @param deptList
     * @param parentDept
     */
    private void queryChildDeptList(List<Dept> deptList, Dept parentDept) {
        List<Dept> childDeptlist = deptMapper.selectList(new LambdaQueryWrapper<Dept>()
                .eq(Dept::getTenantId, 0)
                .eq(Dept::getPid, parentDept.getId())
                .eq(Dept::getMark, 1));

        for (Dept dept : childDeptlist) {
            queryChildDeptList(deptList, dept);
        }
        deptList.addAll(childDeptlist);
    }

}
