package com.jojubanking.boot.module.system.service.building;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Multimap;
import com.jojubanking.boot.framework.common.enums.CommonStatusEnum;
import com.jojubanking.boot.framework.common.exception.util.ServiceExceptionUtil;
import com.jojubanking.boot.module.system.convert.dept.DeptConvert;
import com.jojubanking.boot.module.system.dal.dataobject.dept.DeptDO;
import com.jojubanking.boot.module.system.enums.dept.DeptIdEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import com.jojubanking.boot.module.system.controller.admin.building.vo.*;
import com.jojubanking.boot.module.system.dal.dataobject.building.BuildingDO;
import com.jojubanking.boot.framework.common.pojo.PageResult;

import com.jojubanking.boot.module.system.convert.building.BuildingConvert;
import com.jojubanking.boot.module.system.dal.mysql.building.BuildingMapper;

import static com.jojubanking.boot.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.jojubanking.boot.module.system.enums.ErrorCodeConstants.*;

/**
 * 楼层导视 Service 实现类
 *
 * @author admin
 */
@Service
@Validated
public class BuildingServiceImpl implements BuildingService {

    @Resource
    private BuildingMapper buildingMapper;
    private volatile Multimap<Long, BuildingDO> parentBuildingCache;

    @Override
    public Long createBuilding(BuildingCreateReqVO createReqVO) {
        // 校验正确性
        if (createReqVO.getParentId() == null) {
            createReqVO.setParentId(DeptIdEnum.ROOT.getId());
        }

        checkCreateOrUpdate(null, createReqVO.getParentId(), createReqVO.getName());
        // 插入
        BuildingDO building = BuildingConvert.INSTANCE.convert(createReqVO);
        buildingMapper.insert(building);
        // 发送刷新消息
//        deptProducer.sendDeptRefreshMessage();
        // 返回
        return building.getId();
    }
    private void checkCreateOrUpdate(Long id, Long parentId, String name) {
        // 校验自己存在
        checkBuildingExists(id);
        // 校验父部门的有效性
        checkParentBuildingEnable(id, parentId);
        // 校验部门名的唯一性
        checkBuildingNameUnique(id, parentId, name);
    }

    private void checkParentBuildingEnable(Long id, Long parentId) {
        if (parentId == null || DeptIdEnum.ROOT.getId().equals(parentId)) {
            return;
        }
        // 不能设置自己为父部门
        if (parentId.equals(id)) {
            throw ServiceExceptionUtil.exception(BUILDING_PARENT_ERROR);
        }
        // 父岗位不存在
        BuildingDO building = buildingMapper.selectById(parentId);
        if (building == null) {
            throw ServiceExceptionUtil.exception(BUILDING_PARENT_NOT_EXITS);
        }
        // 父部门被禁用
        if (!CommonStatusEnum.ENABLE.getStatus().equals(building.getStatus())) {
            throw ServiceExceptionUtil.exception(BUILDING_NOT_ENABLE);
        }
        // 父部门不能是原来的子部门
//        List<BuildingDO> children = this.getBuildingsByParentIdFromCache(id, true);
//        if (children.stream().anyMatch(building1 -> building1.getId().equals(parentId))) {
//            throw ServiceExceptionUtil.exception(BUILDING_PARENT_IS_CHILD);
//        }
    }
    @Override
    public List<BuildingDO> getBuildingsByParentIdFromCache(Long parentId, boolean recursive) {
        if (parentId == null) {
            return Collections.emptyList();
        }
        List<BuildingDO> result = new ArrayList<>(); // TODO TW：待优化，新增缓存，避免每次遍历的计算
        // 递归，简单粗暴
        this.getBuildingsByParentIdFromCache(result, parentId,
                recursive ? Integer.MAX_VALUE : 1, // 如果递归获取，则无限；否则，只递归 1 次
                parentBuildingCache);
        return result;
    }

    /**
     * 递归获取所有的子部门，添加到 result 结果
     *
     * @param result 结果
     * @param parentId 父编号
     * @param recursiveCount 递归次数
     * @param parentBuildingCache 父部门 Map，使用缓存，避免变化
     */
    private void getBuildingsByParentIdFromCache(List<BuildingDO> result, Long parentId, int recursiveCount,
                                             Multimap<Long, BuildingDO> parentBuildingCache) {
        // 递归次数为 0，结束！
        if (recursiveCount == 0) {
            return;
        }
        // 获得子部门
        Collection<BuildingDO> depts = parentBuildingCache.get(parentId);
        if (CollUtil.isEmpty(depts)) {
            return;
        }
        result.addAll(depts);
        // 继续递归
        depts.forEach(dept -> getBuildingsByParentIdFromCache(result, dept.getId(),
                recursiveCount - 1, parentBuildingCache));
    }
    private void checkBuildingExists(Long id) {
        if (id == null) {
            return;
        }
        BuildingDO building = buildingMapper.selectById(id);
        if (building == null) {
            throw ServiceExceptionUtil.exception(BUILDING_NOT_FOUND);
        }
    }

    private void checkBuildingNameUnique(Long id, Long parentId, String name) {
        BuildingDO menu = buildingMapper.selectByParentIdAndName(parentId, name);
        if (menu == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的岗位
        if (id == null) {
            throw ServiceExceptionUtil.exception(BUILDING_NAME_DUPLICATE);
        }
        if (!menu.getId().equals(id)) {
            throw ServiceExceptionUtil.exception(BUILDING_NAME_DUPLICATE);
        }
    }
    @Override
    public void updateBuilding(BuildingUpdateReqVO updateReqVO) {

        // 校验正确性
        if (updateReqVO.getParentId() == null) {
            updateReqVO.setParentId(DeptIdEnum.ROOT.getId());
        }
        checkCreateOrUpdate(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
        // 更新部门
        BuildingDO updateObj = BuildingConvert.INSTANCE.convert(updateReqVO);
        buildingMapper.updateById(updateObj);
        // 发送刷新消息
//        deptProducer.sendDeptRefreshMessage();

    }

    @Override
    public void deleteBuilding(Long id) {
        // 校验是否存在
        checkBuildingExists(id);
        // 校验是否有子部门
        if (buildingMapper.selectCountByParentId(id) > 0) {
            throw ServiceExceptionUtil.exception(BUILDING_EXITS_CHILDREN);
        }
        // 删除部门
        buildingMapper.deleteById(id);
        // 发送刷新消息
//        deptProducer.sendDeptRefreshMessage();

    }

    private void validateBuildingExists(Long id) {
        if (buildingMapper.selectById(id) == null) {
            throw exception(BUILDING_NOT_EXISTS);
        }
    }

    @Override
    public BuildingDO getBuilding(Long id) {
        return buildingMapper.selectById(id);
    }

    @Override
    public List<BuildingDO> getBuildingList(Collection<Long> ids) {
        return buildingMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<BuildingDO> getBuildingPage(BuildingPageReqVO pageReqVO) {
        return buildingMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BuildingDO> getBuildingList(BuildingExportReqVO exportReqVO) {
        return buildingMapper.selectList(exportReqVO);
    }

    @Override
    public List<BuildingDO> getSimpleBuildings(BuildingListReqVO reqVO){
        return buildingMapper.selectList01(reqVO);
    }

}
