package com.jy.system.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jy.framework.model.constants.CommonConstant;
import com.jy.framework.model.constants.DataScopeConstant;
import com.jy.framework.satoken.LoginContext;
import com.jy.framework.utils.AssertUtil;
import com.jy.framework.utils.tree.TreeUtil;
import com.jy.system.dao.SysMenuDao;
import com.jy.system.dao.SysRoleDao;
import com.jy.system.dao.SysRoleDeptDao;
import com.jy.system.dao.SysRoleMenuDao;
import com.jy.system.dao.SysUserRoleDao;
import com.jy.system.model.dto.EditRoleDataScopeDto;
import com.jy.system.model.dto.EditRoleMenuScopeDto;
import com.jy.system.model.dto.SysRoleDto;
import com.jy.system.model.dto.SysRoleSelectDto;
import com.jy.system.model.entity.SysRole;
import com.jy.system.model.entity.SysRoleDept;
import com.jy.system.model.vo.RoleDataScopeVo;
import com.jy.system.model.vo.RoleMenuScopeVo;
import com.jy.system.model.vo.SysMenuVo;
import com.jy.system.model.vo.SysRoleVo;
import com.jy.system.service.SysRoleMenuService;
import com.jy.system.service.SysRoleService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author
 * @since 2024-06-20
 */
@Service
public class SysRoleServiceImpl implements SysRoleService {

    @Resource
    private SysRoleDao sysRoleDao;

    @Resource
    private SysRoleDeptDao sysRoleDeptDao;

    @Resource
    private SysRoleMenuDao sysRoleMenuDao;

    @Resource
    private SysUserRoleDao sysUserRoleDao;

    @Resource
    private SysMenuDao sysMenuDao;

    @Resource
    private SysRoleMenuService sysRoleMenuService;

    @Override
    public List<SysRoleVo> getList(SysRoleSelectDto dto) {
        return sysRoleDao.getList(dto);
    }

    @Override
    public Page<SysRoleVo> getPage(SysRoleSelectDto dto) {
        return sysRoleDao.getPage(dto);
    }

    @Override
    public SysRoleVo getDetail(Long id) {
        SysRoleVo vo = sysRoleDao.getDetail(id);
        AssertUtil.notNull(vo, "未知数据");
        return vo;
    }

    @Override
    public void add(SysRoleDto dto) {
        // 赋值全部数据权限
        dto.setDataScope(DataScopeConstant.FULL);

        // 验证角色编码是否唯一
        boolean codeExists = sysRoleDao.codeExists(dto.getCode());
        AssertUtil.eqFalse(codeExists, "角色编码已存在");

        // 验证角色名称是否唯一
        boolean nameExists = sysRoleDao.nameExists(dto.getName());
        AssertUtil.eqFalse(nameExists, "角色名称已存在");

        // 新增角色
        sysRoleDao.save(dto);
    }

    @Override
    public void edit(SysRoleDto dto) {
        // 验证角色名称是否唯一
        boolean nameExists = sysRoleDao.nameExists(dto.getName(), dto.getId());
        AssertUtil.eqFalse(nameExists, "角色名称已存在");

        // 角色编码不允许修改
        dto.setCode(null);

        // 编辑角色
        sysRoleDao.updateById(dto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<Long> idList) {
        // 验证角色是否分配用户
        boolean exists = sysUserRoleDao.roleExists(idList);
        AssertUtil.eqFalse(exists, "角色已被分配");

        // 删除角色目录关联
        sysRoleMenuDao.removeByRoleId(idList);

        // 删除角色部门关联
        sysRoleDeptDao.removeByRoleId(idList);

        // 删除角色
        sysRoleDao.removeBatchByIds(idList);
    }

    @Override
    public List<SysRole> getUserEnableList(Long userId) {
        // 超级管理员不在角色列表内
        if (CommonConstant.SUPER_ADMIN_USER_ID.equals(userId)) {
            return Collections.emptyList();
        }

        return sysRoleDao.getUserEnableList(userId);
    }

    @Override
    public RoleMenuScopeVo getMenuScope(Long id) {
        // 获取菜单范围列表
        List<SysMenuVo> menuList;
        if (LoginContext.isSupperAdmin()) {
            menuList = sysMenuDao.getEnableList();
        } else {
            menuList = sysMenuDao.getEnableListByRoleIds(LoginContext.getRoleIdSet());
        }
        List<SysMenuVo> menuTree = TreeUtil.build(menuList);

        // 获取角色拥有的菜单id列表
        List<Long> menuIdList = sysRoleMenuDao.getMenuIdListByRoleId(id);

        // 返回封装对象
        return new RoleMenuScopeVo(menuTree, menuIdList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editMenuScope(EditRoleMenuScopeDto dto) {
        sysRoleMenuService.editRoleLinked(dto.getId(), dto.getSelectMenuIdList());
    }

    @Override
    public RoleDataScopeVo getDataScope(Long id) {
        // 角色详情
        SysRole systemRole = sysRoleDao.getById(id);
        AssertUtil.notNull(systemRole, "未知角色");

        RoleDataScopeVo vo = new RoleDataScopeVo();
        vo.setId(systemRole.getId());
        vo.setDataScope(systemRole.getDataScope());

        // 获取选中部门id
        if (DataScopeConstant.CUSTOM.equals(systemRole.getDataScope())) {
            vo.setSelectDeptIdList(sysRoleDeptDao.getDeptIdListByRoleId(id));
        } else {
            vo.setSelectDeptIdList(Collections.emptyList());
        }

        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editDataScope(EditRoleDataScopeDto dto) {
        // 编辑角色关联部门
        sysRoleDeptDao.removeByRoleId(dto.getId());
        if (DataScopeConstant.CUSTOM.equals(dto.getDataScope())) {
            List<SysRoleDept> systemRoleDeptList = dto.getSelectDeptIdList().stream()
                    .map(deptId -> new SysRoleDept(dto.getId(), deptId))
                    .collect(Collectors.toList());
            sysRoleDeptDao.saveBatch(systemRoleDeptList);
        }

        // 编辑角色数据范围
        SysRole sysRole = new SysRole();
        sysRole.setId(dto.getId());
        sysRole.setDataScope(dto.getDataScope());
        sysRoleDao.updateById(sysRole);
    }

}
