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.ChannelLegDto;
import com.tuoheng.admin.entity.Dept;
import com.tuoheng.admin.entity.ChannelDept;
import com.tuoheng.admin.entity.Leg;
import com.tuoheng.admin.entity.LegDept;
import com.tuoheng.admin.enums.code.dept.EditDeptCodeEnum;
import com.tuoheng.admin.mapper.DeptMapper;
import com.tuoheng.admin.mapper.ChannelDeptMapper;
import com.tuoheng.admin.mapper.LegDeptMapper;
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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

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

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private ChannelDeptMapper channelDeptMapper;

    @Autowired
    private LegDeptMapper legDeptMapper;

    /**
     * 修改部门信息，涉及航道、航段数据
     *
     * @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.channelHandle(tenantId, oldEditDeptRequest, newEditDeptRequest);

        // 处理航段与部门数据
        this.leghandle(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.isEmpty(newEditDeptRequest.getChannelLegDtoList())) {
            return JsonResult.error(EditDeptCodeEnum.ROAD_IS_NULL.getCode(), EditDeptCodeEnum.ROAD_IS_NULL.getMsg());
        }

        List<Leg> legList;
        List<ChannelLegDto> channelLegDtoList = newEditDeptRequest.getChannelLegDtoList();
        for (ChannelLegDto channelLegDto : channelLegDtoList) {
            legList = channelLegDto.getLegList();
            if (CollectionUtil.isEmpty(legList)) {
                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 channelHandle(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        List<ChannelLegDto> oldRoadSectionList = oldEditDeptRequest.getChannelLegDtoList();
        List<String> oldChannelIdList = null;
        if (CollectionUtil.isNotEmpty(oldRoadSectionList)) {
            oldChannelIdList = oldRoadSectionList.stream().map(o -> o.getChannel().getId()).collect(Collectors.toList());
        }
        List<ChannelLegDto> newRoadSectionList = newEditDeptRequest.getChannelLegDtoList();
        List<String> newChannelIdList = null;
        if (CollectionUtil.isNotEmpty(newRoadSectionList)) {
            newChannelIdList = newRoadSectionList.stream().map(o -> o.getChannel().getId()).collect(Collectors.toList());
        }

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

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

        // 差集：删除航道
        if (CollectionUtil.isNotEmpty(oldChannelIdList)) {
            Collection<String> subRoadIdList = org.apache.commons.collections4.CollectionUtils.subtract(oldChannelIdList, newChannelIdList);
            Map<String, Long> oldRoadIdMap = oldChannelIdList.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 channelId : subRoadIdList) {
                    Long oldCount = oldRoadIdMap.get(channelId);
                    Long subCount = subRoadIdMap.get(channelId);
                    if (oldCount.equals(subCount)) {
                        deleteRoadIdList.add(channelId);
                    }
                }
                if (CollectionUtil.isNotEmpty(deleteRoadIdList)) {
                    this.removeRoadToDept(tenantId, newEditDeptRequest.getId(), subRoadIdList);
                }
            }
        }
    }

    /**
     * 新增航道部门数据
     * 1、先删除原有记录数据
     * 2、新增此次提交的数据
     *
     * @param tenantId   租户Id
     * @param deptId     部门Id
     * @param channelIdList 航道Id集合
     * @return 结果
     */
    private void addRoadToDept(String tenantId, String deptId, Collection<String> channelIdList) {
        List<ChannelDept> list = new ArrayList<>();
        ChannelDept channelDept;
        ChannelDept channelDeptTmp;
        for (String channelId : channelIdList) {
            channelDept = new ChannelDept();
            channelDept.setTenantId(tenantId);
            channelDept.setDeptId(deptId);
            channelDept.setChannelId(channelId);

            // 判断是否存在, 存在则不用再次添加
            channelDeptTmp = channelDeptMapper.selectOne(new LambdaQueryWrapper<ChannelDept>()
                    .eq(ChannelDept::getTenantId, tenantId)
                    .eq(ChannelDept::getDeptId, deptId)
                    .eq(ChannelDept::getChannelId, channelId));
            if (null != channelDeptTmp) {
                continue;
            }
            list.add(channelDept);
        }
        if (CollectionUtil.isNotEmpty(list)) {
            channelDeptMapper.insertBatch(list);
        }
    }

    /**
     * 移除航道部门数据
     * 如若是该航道被分配给了子部门或子子部门，同样一并删除
     *
     * @param tenantId   租户Id
     * @param deptId     部门Id
     * @param channelIdList 航道Id集合
     * @return 结果
     */
    private void removeRoadToDept(String tenantId, String deptId, Collection<String> channelIdList) {
        // 查找部门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 channelId : channelIdList) {
            channelDeptMapper.delete(new LambdaQueryWrapper<ChannelDept>()
                    .eq(ChannelDept::getTenantId, tenantId)
                    .eq(ChannelDept::getChannelId, channelId)
                    .in(ChannelDept::getDeptId, deptIdList));
        }
    }

    /**
     * 处理航段和部门数据
     *
     * @param tenantId
     * @param oldEditDeptRequest
     * @param newEditDeptRequest
     */
    private void leghandle(String tenantId, EditDeptRequest oldEditDeptRequest, EditDeptRequest newEditDeptRequest) {
        List<ChannelLegDto> oldRoadSectionList = oldEditDeptRequest.getChannelLegDtoList();
        List<Leg> oldSectionList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(oldRoadSectionList)) {
            for (ChannelLegDto channelLegDto : oldRoadSectionList) {
                oldSectionList.addAll(channelLegDto.getLegList());
            }
        }

        List<ChannelLegDto> newRoadSectionList = newEditDeptRequest.getChannelLegDtoList();
        List<Leg> newSectionList = new ArrayList<>();
        for (ChannelLegDto channelLegDto : newRoadSectionList) {
            newSectionList.addAll(channelLegDto.getLegList());
        }
        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 legIdList 航段id集合
     * @return 结果
     */
    private void addSectionToDept(String tenantId, String deptId, Collection<String> legIdList) {
        List<LegDept> list = new ArrayList<>();
        LegDept legDept;
        LegDept legDeptTmp;
        for (String legId : legIdList) {
            legDept = new LegDept();
            legDept.setTenantId(tenantId);
            legDept.setDeptId(deptId);
            legDept.setLegId(legId);

            // 判断是否存在, 存在则不用再次添加
            legDeptTmp = legDeptMapper.selectOne(new LambdaQueryWrapper<LegDept>()
                    .eq(LegDept::getTenantId, tenantId)
                    .eq(LegDept::getDeptId, deptId)
                    .eq(LegDept::getLegId, legId));
            if (null != legDeptTmp) {
                continue;
            }
            list.add(legDept);
        }

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

    /**
     * 移除航段部门数据
     *
     * @param tenantId      租户Id
     * @param deptId        部门Id
     * @param legIdList 航段Id集合
     * @return 结果
     */
    private void removeSectionToDept(String tenantId, String deptId, Collection<String> legIdList) {
        List<String> deptIdList = deptMapper.selectAllChildListById(deptId);
        if (CollectionUtil.isEmpty(deptIdList)) {
            return;
        }
        for (String legId : legIdList) {
            legDeptMapper.delete(new LambdaQueryWrapper<LegDept>()
                    .eq(LegDept::getTenantId, tenantId)
                    .eq(LegDept::getLegId, legId)
                    .in(LegDept::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);
    }

}