package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.ruoyi.common.enums.DictEnum;
import com.ruoyi.common.utils.SecurityUtil;
import com.ruoyi.common.web.domain.entity.SysDept;
import com.ruoyi.common.web.domain.entity.SysRole;
import com.ruoyi.common.web.domain.entity.SysUser;
import com.ruoyi.common.web.exception.ServiceException;
import com.ruoyi.system.domain.vo.TreeSelect;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

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

/**
 * 部门 服务层实现
 * @author ruoyi
 */
@Component
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements ISysDeptService {

    @Inject
    SysDeptMapper sysDeptMapper;

    @Inject
    ISysUserService sysUserService;

    @Inject
    ISysRoleService sysRoleService;

    /**
     * 获取部门列表
     * @param sysDept
     * @return
     */
    @Override
    public List<SysDept> selectDeptList(SysDept sysDept) {
        return sysDeptMapper.selectDeptList(sysDept, DictEnum.DEL_FLAG.OK.getValue());
    }

    /**
     * 查询部门列表（排除节点）
     * @param deptId
     * @return
     */
    @Override
    public List<SysDept> excludeChild(Long deptId) {
        List<SysDept> depts = selectDeptList(new SysDept());
        depts.removeIf(d -> d.getDeptId().intValue() == deptId || CollectionUtil.contains(StrUtil.split(d.getAncestors(), ","), deptId + ""));
        return depts;
    }

    /**
     * 查询部门树结构信息
     * @param sysDept 部门信息
     * @return
     */
    @Override
    public List<TreeSelect> selectDeptTreeList(SysDept sysDept) {
        List<SysDept> depts = selectDeptList(sysDept);
        return buildDeptTreeSelect(depts);
    }

    /**
     * 根据部门详情
     * @param deptId
     * @param sysDept
     * @return
     */
    @Override
    public SysDept info(Long deptId, SysDept sysDept) {
        sysDept.setDeptId(deptId);
        checkDeptDataScope(sysDept);
        return sysDeptMapper.selectOneById(deptId);
    }

    /**
     * 新增部门
     * @param sysDept
     * @return
     */
    @Override
    public int add(SysDept sysDept) {
        if (!checkDeptNameUnique(sysDept)) {
            throw new ServiceException("部门名称已存在");
        }
        SysDept info = sysDeptMapper.selectOneById(sysDept.getParentId());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (!DictEnum.COMMON_STATUS.OK.getValue().equals(info.getStatus())) {
            throw new ServiceException("部门停用，不允许新增");
        }
        sysDept.setAncestors(info.getAncestors() + "," + sysDept.getParentId());
        return sysDeptMapper.insert(sysDept);
    }

    /**
     * 修改部门
     * @param sysDept
     * @return
     */
    @Override
    public int edit(SysDept sysDept) {
        checkDeptDataScope(sysDept);
        if (!checkDeptNameUnique(sysDept)) {
            throw new ServiceException("部门名称已存在");
        } else if (sysDept.getParentId().equals(sysDept.getDeptId())) {
            throw new ServiceException("上级部门不能是自己");
        } else if (StrUtil.equals(DictEnum.COMMON_STATUS.DISABLE.getValue(), sysDept.getStatus())
                && sysDeptMapper.selectNormalChildrenDeptById(sysDept.getDeptId(), DictEnum.COMMON_STATUS.OK.getValue(), DictEnum.DEL_FLAG.OK.getValue()) > 0) {
            throw new ServiceException("该部门包含未停用的子部门！");
        }
        SysDept newParentDept = sysDeptMapper.selectOneById(sysDept.getParentId());
        SysDept oldDept = sysDeptMapper.selectOneById(sysDept.getDeptId());
        if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
            String oldAncestors = oldDept.getAncestors();
            sysDept.setAncestors(newAncestors);
            updateDeptChildren(sysDept.getDeptId(), newAncestors, oldAncestors);
        }
        int row = sysDeptMapper.update(sysDept);
        if (DictEnum.COMMON_STATUS.OK.getValue().equals(sysDept.getStatus()) && StrUtil.isNotEmpty(sysDept.getAncestors())
                && !StrUtil.equals("0", sysDept.getAncestors())) {
            // 如果该部门是启用状态，则启用该部门的所有上级部门
            updateParentDeptStatusNormal(sysDept);
        }
        return row;
    }

    /**
     * 删除部门
     * @param deptId
     * @param sysDept
     */
    @Override
    public int delete(Long deptId, SysDept sysDept) {
        QueryWrapper qwD = QueryWrapper.create();
        qwD.and(SysDept::getParentId).eq(deptId);
        qwD.limit(1);
        long lD = sysDeptMapper.selectCountByQuery(qwD);
        if (lD > 0) {
            throw new ServiceException("存在下级部门,不允许删除");
        }
        QueryWrapper qwU = QueryWrapper.create();
        qwU.and(SysUser::getDeptId).eq(deptId);
        long lU = sysUserService.count(qwU);
        if (lU > 0) {
            throw new ServiceException("部门存在用户,不允许删除");
        }
        sysDept.setDeptId(deptId);
        checkDeptDataScope(sysDept);
        return sysDeptMapper.deleteById(deptId);
    }

    /**
     * 获取对应角色部门树列表
     * @param roleId
     * @param sysDept
     * @return
     */
    @Override
    public Map<String, Object> deptTree(Long roleId, SysDept sysDept) {
        Map<String, Object> map = new HashMap<>();
        map.put("depts", selectDeptTreeList(sysDept));
        SysRole role = sysRoleService.selectRoleById(roleId);
        map.put("checkedKeys", sysDeptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly(), DictEnum.DEL_FLAG.OK.getValue()));
        return map;
    }

    /**
     * 校验部门是否有数据权限
     * @param sysDept
     */
    private void checkDeptDataScope(SysDept sysDept) {
        if(!SecurityUtil.isAdmin(SecurityUtil.getUserId())) {
            List<SysDept> sysDepts = selectDeptList(sysDept);
            if (CollectionUtil.isEmpty(sysDepts)) {
                throw new ServiceException("没有权限访问部门数据！");
            }
        }
    }

    /**
     * 校验部门名称是否唯一
     * @param sysDept
     * @return
     */
    public boolean checkDeptNameUnique(SysDept sysDept) {
        long deptId = sysDept.getDeptId() == null ? -1L : sysDept.getDeptId();
        QueryWrapper qw = QueryWrapper.create();
        qw.and(SysDept::getDeptName).eq(sysDept.getDeptName());
        qw.and(SysDept::getParentId).eq(sysDept.getParentId());
        qw.limit(1);
        SysDept sd = sysDeptMapper.selectOneByQuery(qw);
        return ObjectUtil.isNull(sd) || sd.getDeptId() == deptId;
    }

    /**
     * 修改子元素关系
     * @param deptId 被修改的部门ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
        List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
        for (SysDept child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
        if (children.size() > 0) {
            sysDeptMapper.updateDeptChildren(children);
        }
    }

    /**
     * 修改该部门的父级部门状态
     * @param sysDept 当前部门
     */
    private void updateParentDeptStatusNormal(SysDept sysDept) {
        String ancestors = sysDept.getAncestors();
        Long[] deptIds = Convert.toLongArray(ancestors);
        sysDeptMapper.updateDeptStatusNormal(deptIds, DictEnum.COMMON_STATUS.OK.getValue());
    }

    /**
     * 构建前端所需要下拉树结构
     * @param depts 部门列表
     * @return
     */
    private List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {
        List<SysDept> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    /**
     * 构建前端所需要树结构
     * @param depts 部门列表
     * @return
     */
    public List<SysDept> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<>();
        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t) {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tlist = new ArrayList<>();
        for (SysDept n : list) {
            if (n.getParentId() != null && n.getParentId().longValue() == t.getDeptId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDept> list, SysDept t) {
        return getChildList(list, t).size() > 0;
    }

}
