package com.xy.redis;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.xy.collections.list.JArrayList;
import com.xy.collections.list.JList;
import com.xy.collections.map.JMap;
import com.xy.consts.CommConsts;
import com.xy.entity.*;
import com.xy.mapper.SysDeptMapper;
import com.xy.mapper.SysMenuMapper;
import com.xy.mapper.SysRoleMapper;
import com.xy.mapper.SysSystemMapper;
import com.xy.utils.*;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * 权限系统redis工具类
 */
@Component
public class RedisCache extends AuthorizeUtils {


    /**
     * 缓存业务系统权限到redis
     *
     * @param loginId 登录id
     */
    public static void workCache(Long loginId) {
        SysSystemMapper sysSystemMapper = SpringBeanUtils.getBean(SysSystemMapper.class);
        SysRoleMapper sysRoleMapper = SpringBeanUtils.getBean(SysRoleMapper.class);
        SysDeptMapper sysDeptMapper = SpringBeanUtils.getBean(SysDeptMapper.class);
        SysMenuMapper sysMenuMapper = SpringBeanUtils.getBean(SysMenuMapper.class);
        RedisService<List<AuthorizeUtils.CacheEntity>> roleMenuRedisService = getRedisService();
        //获取登录人所有系统
        JoinLambdaWrapper<SysSystem> sysSystemsJoinLambdaWrapper = new JoinLambdaWrapper<>(SysSystem.class)
                .eq(SysSystem::getStatus, true)
                .innerJoin(SysUserRole.class, SysUserRole::getSysId, SysSystem::getId)
                .eq(SysUserRole::getWorkUserId, loginId)
                .end();
        List<SysSystem> sysSystems = sysSystemMapper.joinSelectList(sysSystemsJoinLambdaWrapper, SysSystem.class);
        if (!Emptys.check(sysSystems)) {
            return;
        }
        //获取登录人所有角色
        JoinLambdaWrapper<SysRole> sysRoleJoinLambdaWrapper = new JoinLambdaWrapper<>(SysRole.class)
                .eq(SysRole::getStatus, true)
                .innerJoin(SysUserRole.class, SysUserRole::getRoleId, SysRole::getId)
                .eq(SysUserRole::getWorkUserId, loginId)
                .end();
        List<SysRole> sysRoles = sysRoleMapper.joinSelectList(sysRoleJoinLambdaWrapper, SysRole.class);
        JList<Long> sysRoleIds = new JArrayList<>(sysRoles).getProperty(SysRole::getId);
        if (sysRoleIds.size() == 0) {
            return;
        }
        //获取登录人所有部门
        JoinLambdaWrapper<SysDept> sysDeptJoinLambdaWrapper = new JoinLambdaWrapper<>(SysDept.class)
                .eq(SysDept::getStatus, true)
                .innerJoin(SysUserDept.class, SysUserDept::getDeptId, SysDept::getId)
                .eq(SysUserDept::getWorkUserId, loginId)
                .end();
        List<SysDept> sysDepts = sysDeptMapper.joinSelectList(sysDeptJoinLambdaWrapper, SysDept.class);
        JList<Long> sysDeptsIds = new JArrayList<>(sysDepts).getProperty(SysDept::getId);
        //获取登录人所有部门角色
        if (sysDeptsIds.size() > 0) {
            sysRoleJoinLambdaWrapper = new JoinLambdaWrapper<>(SysRole.class)
                    .eq(SysRole::getStatus, true)
                    .innerJoin(SysDeptRole.class, SysDeptRole::getRoleId, SysRole::getId)
                    .in(SysDeptRole::getDeptId, sysDeptsIds)
                    .end();
            List<SysRole> sysRoles2 = sysRoleMapper.joinSelectList(sysRoleJoinLambdaWrapper, SysRole.class);
            JList<Long> sysRoleIds2 = new JArrayList<>(sysRoles2).getProperty(SysRole::getId);
            if (sysRoleIds2.size() > 0) {
                sysRoleIds.setAll(sysRoleIds2)
                        .comparing();
                sysRoles = new JArrayList<>(sysRoles2).setAll(sysRoles);
            }
        }
        //获取登录人所有角色菜单
        JoinLambdaWrapper<SysMenu> sysMenuJoinLambdaWrapper = new JoinLambdaWrapper<>(SysMenu.class)
                .eq(SysMenu::getStatus, true)
                .innerJoin(SysRoleMenu.class, SysRoleMenu::getMenuId, SysMenu::getId)
                .selectAs(cb -> cb
                        .add(SysRoleMenu::getRoleId)
                        .add(SysRoleMenu::getSelectAdmin)
                )
                .in(SysRoleMenu::getRoleId, sysRoleIds)
                .end()
                .orderByAsc(SysMenu::getOrders);
        List<SysMenuJoinSysRoleMenu> sysMenus = sysMenuMapper.joinSelectList(sysMenuJoinLambdaWrapper, SysMenuJoinSysRoleMenu.class);
        JMap<Long, List<SysMenuJoinSysRoleMenu>> sysMenuMaps = new JArrayList<>(sysMenus).toMap(SysMenuJoinSysRoleMenu::getRoleId).group();
        //删除redis
        roleMenuRedisService.removeMap(getKey(loginId));
        //循环系统集合
        for (SysSystem sysSystem : sysSystems) {
            List<AuthorizeUtils.CacheEntity> cacheEntitys = new ArrayList<>();
            //系统下角色集合
            JList<SysRole> list = new JArrayList<>(sysRoles).filter().eq(SysRole::getSysId, sysSystem.getId()).list();
            //循环角色集合
            list.forEach(sysRole -> {
                //获取角色菜单
                List<SysMenuJoinSysRoleMenu> sysMenuJoinSysRoleMenus = sysMenuMaps.get(sysRole.getId());
                //封装redis对象
                AuthorizeUtils.CacheEntity cacheEntity = new AuthorizeUtils.CacheEntity()
                        .setRoleId(sysRole.getId())
                        .setRoleCode(sysRole.getCode())
                        .setList(sysMenuJoinSysRoleMenus);
                cacheEntitys.add(cacheEntity);
            });
            roleMenuRedisService.setMap(getKey(loginId), sysSystem.getId().toString(), cacheEntitys);
        }
    }

    /**
     * 获取当前系统ID
     *
     * @return
     */
    public static Long getSystemId() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String sysId = request.getHeader(CommConsts.SYS_ID);
        return Long.valueOf(sysId);
    }

    /**
     * 获取当前接口uri
     *
     * @return
     */
    public static String getUri() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getRequestURI();
    }

    /**
     * 判断数据查询权限
     *
     * @param lambdaQueryWrapper 查询构造器
     * @param function           普通查询权限时，条件lambda引用字段
     * @return true=管理员数据查询权限 false=普通查询权限
     */
    public static <T> boolean getDataAuth(Long systemId, LambdaQueryWrapper<T> lambdaQueryWrapper, SFunction<T, ?> function) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        boolean dataAuth = authByData(systemId, request.getRequestURI());
        if (!dataAuth) {
            lambdaQueryWrapper.eq(function, getLoginId(Long.class));
            return false;
        }
        return true;
    }

    /**
     * 判断数据查询权限
     */
    public static <T> boolean getDataAuth(Long systemId) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return authByData(systemId, request.getRequestURI());
    }

    /**
     * 获取菜单
     *
     * @param systemId 系统id
     * @return
     */
    public static List<SysMenuJoinSysRoleMenu> getMenu(Long systemId) {
        return getMenu(systemId, getClientType(getToken()));
    }

    /**
     * 获取菜单
     *
     * @param systemId   系统id
     * @param clientType 菜单类型
     * @return
     */
    public static List<SysMenuJoinSysRoleMenu> getMenu(Long systemId, String clientType) {
        String token = getToken();
        JList<SysMenuJoinSysRoleMenu> sysMenuJoinSysRoleMenus = new JArrayList<>();
        //获取redis缓存
        List<AuthorizeUtils.CacheEntity> cacheEntities = getRedisService().getMap(getKey(getLoginId(token, Long.class)), systemId.toString());
        if (!Emptys.check(cacheEntities)) {
            return sysMenuJoinSysRoleMenus;
        }
        //角色菜单累加
        cacheEntities.forEach(cacheEntity -> {
            List<SysMenuJoinSysRoleMenu> sysMenuJoinSysRoleMenuss = cacheEntity.getList();
            if (Emptys.check(cacheEntity.getList())) {
                JList<SysMenuJoinSysRoleMenu> list = new JArrayList<>(sysMenuJoinSysRoleMenuss).filter()
                        .eq(SysMenuJoinSysRoleMenu::getClientType, clientType)
                        .list();
                if (Emptys.check(list)) {
                    sysMenuJoinSysRoleMenus.addAll(list);
                }
            }
        });
        //去重
        return sysMenuJoinSysRoleMenus
                .comparing(SysMenuJoinSysRoleMenu::getId)
                .asc(SysMenuJoinSysRoleMenu::getOrders);
    }

    /**
     * 获取菜单树
     *
     * @param systemId 系统id
     * @return
     */
    public static List<SysMenuJoinSysRoleMenu> getMenuTree(Long systemId) {
        return getMenuTree(systemId, getClientType(getToken()));
    }

    /**
     * 获取菜单树
     *
     * @param systemId   系统id
     * @param clientType 菜单类型
     * @return
     */
    public static List<SysMenuJoinSysRoleMenu> getMenuTree(Long systemId, String clientType) {
        //获取菜单
        List<SysMenuJoinSysRoleMenu> menu = getMenu(systemId, clientType);
        JList<SysMenuJoinSysRoleMenu> sysMenuJoinSysRoleMenus = new JArrayList<>(menu);
        //生成树
        JList<SysMenuJoinSysRoleMenu> tops = sysMenuJoinSysRoleMenus.filter().isNull(SysMenuJoinSysRoleMenu::getPaterId).list();
        tops.forEach(top -> {
            List<SysMenuJoinSysRoleMenu> tree = Beans.tree(top, sysMenuJoinSysRoleMenus, SysMenuJoinSysRoleMenu::getId, SysMenuJoinSysRoleMenu::getPaterId, SysMenuJoinSysRoleMenu::getSonSysMenu);
            top.setSonSysMenu(tree);
        });
        return tops;
    }
}
