package com.bonus.system.service.impl;

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

import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.web.domain.BaseEntity;
import com.bonus.config.SystemConfig;
import com.bonus.system.api.domain.*;
import com.bonus.system.domain.SysRoleMenu;
import com.bonus.system.mapper.*;
import com.bonus.common.datascope.utils.CommonDataPermissionInfo;
import com.bonus.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.bonus.common.core.constant.UserConstants;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.text.Convert;
import com.bonus.common.core.utils.SpringUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.datascope.annotation.DataScope;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.domain.vo.TreeSelect;
import com.bonus.system.service.ISysDeptService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 部门管理 服务实现
 *
 * @author bonus
 */
@Service
@Slf4j
public class SysDeptServiceImpl implements ISysDeptService
{
    @Autowired
    private SysDeptMapper deptMapper;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysRoleMapper roleMapper;

    @Resource
    private SysUserRoleMapper userRoleMapper;

    @Resource
    private SysRoleMenuMapper roleMenuMapper;

    @Resource
    SysTemplateMenuMapper sysTemplateMenuMapper;

    @Resource
    private SysRoleDeptMapper roleDeptMapper;

    @Lazy
    @Autowired
    ISysUserService userService;

    @Resource
    private SystemConfig systemConfig;

    /**
     * 查询部门管理数据
     *
     * @param dept 部门信息
     * @return 部门信息集合
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysDept> selectDeptList(SysDept dept)
    {
        try {
            BaseEntity entity = CommonDataPermissionInfo.backMissionInfo(dept.getParams().get("dataScope").toString());
            BeanUtils.copyProperties(entity, dept);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (dept.getDeptName() != null) {
            String str = dept.getDeptName().replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_");
            dept.setDeptName(str);
        }
        dept.setCompanyId(SecurityUtils.getLoginUser().getSysUser().getCompanyId());
        return deptMapper.selectDeptList(dept);
    }

    @Override
    public List<SysDept> getDeptList(SysDept dept) {
        return deptMapper.getDeptList(dept);
    }

    @Override
    public List<SysDept> getCompanyUserCount() {
        return deptMapper.getCompanyUserCount();
    }

    /**
     * 查询部门树结构信息
     *
     * @param dept 部门信息
     * @return 部门树信息集合
     */
    @Override
    public List<TreeSelect> selectDeptTreeList(SysDept dept)
    {
        List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
        return buildDeptTreeSelect(depts);
    }

    /**
     * 查询部门人员树列表
     *
     * @param sysUser 用户对象
     * @return 部门树信息集合
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<TreeSelect> selectDeptUserTree(SysUser sysUser)
    {
        List<SysDept> depts = deptMapper.selectDeptUserList(sysUser.getRoleIds());
        for (int i = 0; i < 5; i++) {
            depts = getFilterDepts(depts);
        }
        return buildDeptTreeSelect(depts);
    }

    private static List<SysDept> getFilterDepts(List<SysDept> depts) {
        List<SysDept> newDepts = new ArrayList<>();
        Set<Long> pids = depts.stream().map(SysDept::getParentId).collect(Collectors.toSet());
        for (SysDept sysDept : depts) {
            if (sysDept.getLevel().equals(99) || pids.contains(sysDept.getDeptId())) {
                newDepts.add(sysDept);
            }
        }
        return newDepts;
    }

    /**
     * 构建前端所需要树结构
     *
     * @param depts 部门列表
     * @return 树结构列表
     */
    @Override
    public List<SysDept> buildDeptTree(List<SysDept> depts)
    {
        List<SysDept> returnList = new ArrayList<SysDept>();
        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;
    }

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

    /**
     * 根据角色ID查询部门树信息
     *
     * @param roleId 角色ID
     * @return 选中部门列表
     */
    @Override
    public List<Long> selectDeptListByRoleId(Long roleId)
    {
        SysRole role = roleMapper.selectRoleById(roleId);
        return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
    }

    /**
     * 根据部门ID查询信息
     *
     * @param deptId 部门ID
     * @return 部门信息
     */
    @Override
    public SysDept selectDeptById(Long deptId)
    {
        SysDept sysDept = deptMapper.selectDeptById(deptId);
        if (systemConfig.isAddRootCompany() && Objects.nonNull(sysDept.getParentId()) && sysDept.getParentId().equals(0L)) {
            SysUser sysUser = deptMapper.selectCompanyAdminByDept(deptId);
            sysDept.setSysUser(sysUser);
        }
        return sysDept;
    }

    @Override
    public SysDept selectActiveDeptById(Long deptId)
    {
        return deptMapper.selectActiveDeptById(deptId);
    }

    /**
     * 根据ID查询所有子部门（正常状态）
     *
     * @param deptId 部门ID
     * @return 子部门数
     */
    @Override
    public int selectNormalChildrenDeptById(Long deptId)
    {
        return deptMapper.selectNormalChildrenDeptById(deptId);
    }

    /**
     * 是否存在子节点
     *
     * @param deptId 部门ID
     * @return 结果
     */
    @Override
    public boolean hasChildByDeptId(Long deptId)
    {
        int result = deptMapper.hasChildByDeptId(deptId);
        return result > 0;
    }

    /**
     * 查询部门是否存在用户
     *
     * @param deptId 部门ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkDeptExistUser(Long deptId)
    {
        int result = deptMapper.checkDeptExistUser(deptId);
        return result > 0;
    }

    /**
     * 校验部门名称是否唯一
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    public boolean checkDeptNameUnique(SysDept dept)
    {
        Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
        //如果没有parentid则认为是根节点，检查根节点是否重名，added by weiweiwang 2024/9/20
        Long parentId = StringUtils.isNull(dept.getParentId()) ? 0L : dept.getParentId();

        SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), parentId);
        if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验部门是否有数据权限
     *
     * @param deptId 部门id
     */
    @Override
    public void checkDeptDataScope(Long deptId)
    {
        if (!SysUser.isAdmin(SecurityUtils.getUserId()) && StringUtils.isNotNull(deptId))
        {
            SysDept dept = new SysDept();
            dept.setDeptId(deptId);
            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
            if (StringUtils.isEmpty(depts))
            {
                throw new ServiceException("没有权限访问部门数据！");
            }
        }
    }

    /**
     * 新增保存部门信息
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertDept(SysDept dept)
    {
        //增加根公司的处理
        if (dept.getParentId() == null){
            dept.setParentId(0L);
            dept.setAncestors("0");
            dept.setStatus("0");//默认启用
            int result = deptMapper.insertDept(dept);
            if (SecurityUtils.isAdmin(SecurityUtils.getUserId()) && systemConfig.isAddRootCompany() && result > 0) {
                if (StringUtils.isNotNull(dept.getSysUser()) && !userService.checkUserNameUnique(dept.getSysUser())) {
                    throw new ServiceException("新增公司管理员用户'" + dept.getSysUser().getUserName() + "'失败，登录账号已存在");
                }
                SysUser user = createCompanyAdminUser(dept);
                createCompanyAdminRole(dept, user);
            }
            return result;
        } else {
            SysDept info = deptMapper.selectDeptById(dept.getParentId());
            // 如果父节点不为正常状态,则不允许新增子节点
            if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
                throw new ServiceException("部门停用，不允许新增");
            }
            dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
            return deptMapper.insertDept(dept);
        }
    }

    /**
     * 修改保存部门信息
     *
     * @param dept 部门信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDept(SysDept dept)
    {
        SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
        SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
        if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
        {
            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
            String oldAncestors = oldDept.getAncestors();
            dept.setAncestors(newAncestors);
            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
        }
        int result = deptMapper.updateDept(dept);
        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
                && !StringUtils.equals("0", dept.getAncestors()))
        {
            // 如果该部门是启用状态，则启用该部门的所有上级部门
            updateParentDeptStatusNormal(dept);
        }
        //判断是否需要修改公司管理员用户信息
        if (SecurityUtils.isAdmin(SecurityUtils.getUserId()) && systemConfig.isAddRootCompany() && Objects.nonNull(dept.getParentId()) && dept.getParentId().equals(0L)){
            SysUser companyAdminUser = dept.getSysUser();
            if (Objects.nonNull(companyAdminUser.getRoleId())) {
                companyAdminUser.setUpdateBy(SecurityUtils.getUsername());
                companyAdminUser.setUpdateTime(DateUtils.getNowDate());
                roleMenuMapper.deleteRoleMenuByRoleId(companyAdminUser.getRoleId());
                batchInsertRoleMenuFromTemplate(dept, companyAdminUser.getRoleId());
                userMapper.updateUser(companyAdminUser);
            }
        }
        return result;
    }

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

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

    /**
     * 删除部门管理信息
     *
     * @param deptId 部门ID
     * @return 结果
     */
    @Override
    public int deleteDeptById(Long deptId)
    {
        return deptMapper.deleteDeptById(deptId);
    }

    /**
     * 注销或恢复公司
     *
     * @param dept 当前公司
     */
    @Override
    public int turnOnOffDeptById(SysDept dept)
    {
        return deptMapper.turnOnOffDeptById(dept);
    }

    /**
     * 递归列表
     */
    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<SysDept>();
        Iterator<SysDept> it = list.iterator();
        while (it.hasNext())
        {
            SysDept n = (SysDept) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && 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 ? true : false;
    }

    /**
     * 创建公司管理员用户
     * @param dept
     */
    private SysUser createCompanyAdminUser(SysDept dept) {
        log.info("创建公司管理员用户：{}",dept);
        SysUser user = dept.getSysUser();
        user.setCreateBy(SecurityUtils.getUsername());
        user.setPassword(SecurityUtils.encryptPassword(dept.getInitPassword()));
        user.setDeptId(dept.getDeptId());
        user.setLoginType("0"); //后台
        userMapper.insertUser(user);
        dept.setAdminUserId(user.getUserId());
        deptMapper.updateDept(dept);
        return user;
    }

    /**
     * 创建公司管理员并分配角色菜单等
     */
    private void createCompanyAdminRole(SysDept sysDept, SysUser user) {
        log.info("部门信息{}，公司管理员用户{}",sysDept,user);
        SysRole role = new SysRole();
        role.setRoleKey("company_admin");
        role.setRoleName("公司管理员");
        role.setRemark("公司管理员");
        role.setCompanyId(sysDept.getDeptId());
        role.setRoleSort(0);
        role.setStatus("0");
        role.setCreateBy(SecurityUtils.getUsername());
        roleMapper.insertRole(role);
        log.info("创建的角色id为：{}",role.getRoleId());

        //用户绑定角色
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(user.getUserId());
        sysUserRole.setRoleId(role.getRoleId());
        List<SysUserRole> sysUserRoleList = new ArrayList<SysUserRole>();
        sysUserRoleList.add(sysUserRole);
        userRoleMapper.batchUserRole(sysUserRoleList);

        //对初始化管理员赋值菜单权限
        batchInsertRoleMenuFromTemplate(sysDept, role.getRoleId());
    }

    private void batchInsertRoleMenuFromTemplate(SysDept sysDept, Long roleId) {
        List<SysRoleMenu> sysRoleMenulist = new ArrayList<>();
        List<Long> menuIds = sysTemplateMenuMapper.queryMenuIdByTemplateId(sysDept.getMenuTemplateId());
        SysRoleMenu sysRoleMenu = null;
        for (Long menuId : menuIds) {
            sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(roleId);
            sysRoleMenu.setMenuId(menuId);
            sysRoleMenulist.add(sysRoleMenu);
        }
        roleMenuMapper.batchRoleMenu(sysRoleMenulist);
    }
}

