package cn.qinys.platform.upms.api.service.impl;

import cn.qinys.platform.base.exceptions.BizException;
import cn.qinys.platform.base.utils.RedisUtils;
import cn.qinys.platform.upms.constants.UpmsConstants;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import cn.qinys.platform.entity.upms.*;
import cn.qinys.platform.upms.api.mapper.*;
import cn.qinys.platform.upms.api.req.*;
import cn.qinys.platform.upms.api.resp.MenuSelectedResp;
import cn.qinys.platform.upms.api.resp.RoleMenusTreeResp;
import cn.qinys.platform.upms.api.service.IRoleService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

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

/**
 * Description:
 *
 * @author tanlie
 * Date: 2024/2/27 11:10
 */
@Service
@AllArgsConstructor
public class RoleServiceImpl implements IRoleService {

    private final UpmsRoleMapper roleMapper;
    private final UpmsRolePermissionMapper rolePermissionMapper;
    private final UpmsRoleDepartmentMapper roleDepartmentMapper;
    private final UpmsUserRoleMapper userRoleMapper;
    private final UpmsRoleMenusMapper roleMenusMapper;
    private final UpmsMenuMapper menuMapper;
    private final RedisUtils redisUtils;
    private final MarketMapDepartmentMapper departmentMapper;
    private final UpmsMenuPermissionBaseMapper permissionBaseMapper;


    @Override
    public Page<UpmsRole> getRolePage(RolePageReq req) {
        Page<UpmsRole> page = new Page<>(req.getCurrent(), req.getSize());
        QueryWrapper<UpmsRole> wrapper = new QueryWrapper<>();
        wrapper.like(StringUtils.hasLength(req.getRoleCnName()), "role_cn_name", req.getRoleCnName());
        wrapper.like(StringUtils.hasLength(req.getRoleEnName()), "role_en_name", req.getRoleEnName());
        wrapper.orderByAsc("id");
        return roleMapper.selectRolePage(page, wrapper);
    }

    @Override
    public void createRole(RoleCreateReq req) {
        QueryWrapper<UpmsRole> wrapper = new QueryWrapper<>();
        wrapper.eq("role_cn_name", req.getRoleCnName());
        wrapper.last("LIMIT 1");
        UpmsRole cnExist = roleMapper.selectOne(wrapper);
        if (cnExist != null) {
            throw new BizException("角色中文名已存在");
        }
        QueryWrapper<UpmsRole> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("role_en_name", req.getRoleEnName());
        wrapper2.last("LIMIT 1");
        UpmsRole enExist = roleMapper.selectOne(wrapper);
        if (enExist != null) {
            throw new BizException("角色英文文名已存在");
        }
        UpmsRole role = new UpmsRole();
        role.setRoleCnName(req.getRoleCnName());
        role.setRoleEnName(req.getRoleEnName());
        role.setSuperAdmin("0");
        role.setDeletable("1");
        roleMapper.insert(role);
    }

    @Override
    public void updateRole(RoleUpdateReq req) {
        QueryWrapper<UpmsRole> wrapper = new QueryWrapper<>();
        wrapper.eq("role_cn_name", req.getRoleCnName());
        wrapper.last("LIMIT 1");
        UpmsRole cnExist = roleMapper.selectOne(wrapper);
        if (cnExist != null && !cnExist.getId().equalsIgnoreCase(req.getId())) {
            throw new BizException("角色中文名已存在");
        }
        QueryWrapper<UpmsRole> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("role_en_name", req.getRoleEnName());
        wrapper2.last("LIMIT 1");
        UpmsRole enExist = roleMapper.selectOne(wrapper);
        if (enExist != null && !enExist.getId().equalsIgnoreCase(req.getId())) {
            throw new BizException("角色英文文名已存在");
        }
        UpdateWrapper<UpmsRole> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", req.getId());
        UpmsRole role = new UpmsRole();
        role.setRoleCnName(req.getRoleCnName());
        role.setRoleEnName(req.getRoleEnName());
        roleMapper.update(role, updateWrapper);
    }

    @Override
    public void removeRole(RoleRemoveReq req) {
        // 判断不可删除的条件
        UpmsRole role = roleMapper.selectById(req.getId());
        if (!"1".equalsIgnoreCase(role.getDeletable())) {
            throw new BizException(role.getRoleCnName() + "不可删除");
        }
        roleMapper.deleteById(role.getId());

    }

    @Override
    public List<UpmsRole> getRoleList() {
        QueryWrapper<UpmsRole> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("id");
        return roleMapper.selectList(wrapper);
    }

    @Override
    public List<String> getPermissionCodes(String roleId, String superAdmin) {
        if ("1".equals(superAdmin)) {
            return permissionBaseMapper.selectAllPermissionCodes();
        }
        return rolePermissionMapper.selectPermissionCodeByRole(roleId);
    }

    @Override
    public List<Integer> getPermissionDepartments(UpmsRole activeRole) {
        // 系统管理员不校验权限
        if ("1".equals(activeRole.getSuperAdmin())) {
            List<MarketMapDepartment> departments = departmentMapper.selectList(null);
            if (departments.isEmpty()) {
                return Collections.singletonList(0);
            }
            return departments.stream().map(MarketMapDepartment::getId).collect(Collectors.toList());
        }
        // 非系统管理员
        QueryWrapper<UpmsRoleDepartment> wrapper = new QueryWrapper<>();
        wrapper.eq("tenant_id", activeRole.getTenantId());
        wrapper.eq("role_id", activeRole.getId());
        List<UpmsRoleDepartment> departments = roleDepartmentMapper.selectList(wrapper);
        if (departments.isEmpty()) {
            return Collections.singletonList(0);
        }
        List<Integer> roleDepartmentIds = departments.stream().map(UpmsRoleDepartment::getDepartmentId).collect(Collectors.toList());
        QueryWrapper<MarketMapDepartment> departmentQueryWrapper = new QueryWrapper<>();
        departmentQueryWrapper.in("id", roleDepartmentIds).or().in("pid", roleDepartmentIds);
        return departmentMapper.selectDepartmentIds(departmentQueryWrapper);
    }

    @Override
    public void updateUserActiveRole(String userId, String roleId) {
        userRoleMapper.setUserUnActive(userId);
        userRoleMapper.setUserActive(userId, roleId);
    }


    @Override
    public MenuSelectedResp getMenuSelected(String roleId) {
        List<UpmsMenu> menus = roleMenusMapper.selectMenusByRole(roleId);
        if (menus == null) {
            menus = new ArrayList<>();
        }
        List<Integer> permissions = rolePermissionMapper.selectPermissionByRole(roleId);
        if (permissions == null) {
            permissions = new ArrayList<>();
        }
        MenuSelectedResp resp = new MenuSelectedResp();
        resp.setCheckedMenus(menus);
        resp.setPermissionIds(permissions);
        return resp;
    }

    @Override
    public List<RoleMenusTreeResp> getMenusTree() {
        QueryWrapper<UpmsMenu> wrapper = new QueryWrapper<>();
        wrapper.ne("id", 1);
        wrapper.orderByAsc("ord", "id");
        List<UpmsMenu> menuList = menuMapper.selectList(wrapper);
        return this.getTree(menuList);
    }


    @Transactional
    @Override
    public void createResource(RoleMenuAuthReq req) {
        // 删除
        QueryWrapper<UpmsRoleMenus> wrapper = new QueryWrapper<>();
        wrapper.eq("role_id", req.getRoleId());
        roleMenusMapper.delete(wrapper);
        for (Integer menuId : req.getMenuIds()) {
            UpmsRoleMenus menus = new UpmsRoleMenus();
            menus.setMenuId(menuId);
            menus.setRoleId(req.getRoleId());
            roleMenusMapper.insert(menus);
        }
        String key = UpmsConstants.RedisKey.UPMS_AUTH_MENUS.getCode() + req.getRoleId();
        redisUtils.delete(key);
    }

    @Transactional
    @Override
    public void createAuthPermission(RolePermissionReq req) {
        QueryWrapper<UpmsRolePermission> wrapper = new QueryWrapper<>();
        wrapper.eq("role_id", req.getRoleId());
        wrapper.eq("menu_id", req.getMenuId());
        rolePermissionMapper.delete(wrapper);
        for (Integer id : req.getPermissionIds()) {
            UpmsRolePermission permission = new UpmsRolePermission();
            permission.setMenuId(req.getMenuId());
            permission.setRoleId(req.getRoleId());
            permission.setPermissionId(id);
            rolePermissionMapper.insert(permission);
        }
    }


    private List<RoleMenusTreeResp> getTree(List<UpmsMenu> menuList) {
        List<UpmsMenu> firstLevel = new ArrayList<>();
        menuList.forEach(menu -> {
            if (menu.getParentId() == 0) {
                firstLevel.add(menu);
            }
        });
        List<RoleMenusTreeResp> resp = new ArrayList<>();
        for (UpmsMenu menu : firstLevel) {
            RoleMenusTreeResp root = new RoleMenusTreeResp();
            root.setId(menu.getId());
            root.setTitle(menu.getTitle());
            root.setHidden(menu.getHidden());
            root.setComponent(menu.getComponent());
            root.setIcon(menu.getIcon());
            root.setOrd(menu.getOrd());
            root.setKeepAlive(menu.getKeepAlive());
            root.setPath(menu.getPath());
            root.setParentId(0);
            root.setChildren(this.getAuthMenuChildren(menu.getId(), menuList));
            resp.add(root);
        }
        return resp;
    }

    private List<RoleMenusTreeResp> getAuthMenuChildren(Integer parentId, List<UpmsMenu> menuList) {
        List<RoleMenusTreeResp> children = new ArrayList<>();
        for (UpmsMenu menu : menuList) {
            if (parentId.equals(menu.getParentId())) {
                RoleMenusTreeResp child = new RoleMenusTreeResp();
                child.setId(menu.getId());
                child.setTitle(menu.getTitle());
                child.setHidden(menu.getHidden());
                child.setComponent(menu.getComponent());
                child.setIcon(menu.getIcon());
                child.setOrd(menu.getOrd());
                child.setKeepAlive(menu.getKeepAlive());
                child.setPath(menu.getPath());
                child.setParentId(parentId);
                child.setChildren(this.getAuthMenuChildren(child.getId(), menuList));
                children.add(child);
            }
        }
        return children;
    }


}
