package com.ssyf.module.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ssyf.module.auth.domain.bo.UserRoleRelationBo;
import com.ssyf.module.auth.domain.entity.DataRelation;
import com.ssyf.module.auth.domain.entity.MenuPermission;
import com.ssyf.module.auth.domain.entity.Role;
import com.ssyf.module.auth.domain.entity.UserRoleRelation;
import com.ssyf.module.auth.domain.query.DataRelationQuery;
import com.ssyf.module.auth.domain.query.RoleQuery;
import com.ssyf.module.auth.emuns.DataRelationEnum;
import com.ssyf.common.core.util.AssertUtil;
import com.ssyf.common.core.util.EntityUtil;
import com.ssyf.common.security.helper.ClientContextHelper;
import com.ssyf.common.security.domain.ClientInfo;
import com.ssyf.plugs.mysql.helper.MybatisPlusHelper;
import com.ssyf.module.auth.mapper.RoleMapper;
import com.ssyf.module.auth.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.ssyf.common.web.apicode.ApiCodeUser;
import com.ssyf.common.web.error.ServiceRuntimeException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author auth
 * @since 2022-12-12
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Lazy
    @Autowired
    private RoleMenuPermissionRelationService roleMenuPermissionRelationService;
    @Lazy
    @Autowired
    private UserRoleRelationService userRoleRelationService;
    @Lazy
    @Autowired
    private UserPermissionRelationService userPermissionRelationService;
    @Lazy
    @Autowired
    private MenuPermissionService menuPermissionService;
    @Lazy
    @Autowired
    private DataRelationService dataRelationService;
    // 在类中添加 RedisTemplate 依赖
    @Lazy
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public Role addOne(RoleQuery query) {
        if("超级管理员".equals(query.getName())){
            ServiceRuntimeException.throw0(ApiCodeUser.PARAMETER_ERROR.getCode(),"不能修改超级管理员");
        }
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        Role news = BeanUtil.copyProperties(query, Role.class);
        news.setUid(IdUtil.simpleUUID());
        news.setCreatorId(clientInfo.getId().toString()).setCreatorName(clientInfo.getNickname()).setCreatedTime(LocalDateTime.now());
        this.save(news);
        return news;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeByUid(String uid) {
        Role role = this.getOneByUid(uid);
        if(role == null){
            return;
        }
        if("超级管理员".equals(role.getName())){
            ServiceRuntimeException.throw0(ApiCodeUser.PARAMETER_ERROR.getCode(),"不能修改超级管理员");
        }
        //删除角色与用户关联关系
        this.userRoleRelationService.removeByRoleUid(uid);
        //删除角色与菜单的关联数据
        this.roleMenuPermissionRelationService.removeByRoleUid(uid);
        //删除依赖角色的用户和权限的关联数据
        this.userPermissionRelationService.removeByRoleUid(uid);
        //删除用户与角色的分享关联数据
        this.dataRelationService.removeByRelationIds(Arrays.asList(uid));
        //删除自身
        this.remove(new LambdaQueryWrapper<Role>().eq(Role::getUid ,uid));
    }

    @Override
    public void updateByUid(String uid, RoleQuery query) {
        if("超级管理员".equals(query.getName())){
            ServiceRuntimeException.throw0(ApiCodeUser.PARAMETER_ERROR.getCode(),"不能修改超级管理员");
        }
        Role old = this.getOneByUid(uid);
        AssertUtil.isNotNull(old ,ServiceRuntimeException.instance(ApiCodeUser.PARAMETER_ERROR));

        if("超级管理员".equals(old.getName())){
            ServiceRuntimeException.throw0(ApiCodeUser.PARAMETER_ERROR.getCode(),"不能修改超级管理员");
        }

        Role role = BeanUtil.copyProperties(query , Role.class);
        this.update(role ,new LambdaQueryWrapper<Role>().eq(Role::getUid ,uid));
    }

    @Override
    public Role getOneByUid(String uid) {
        return this.getOne(new LambdaQueryWrapper<Role>().eq(Role::getUid ,uid));
    }

    @Override
    public PageInfo<Role> getPage(RoleQuery query) {
        //分页
		PageHelper.startPage(query.getPageNum() ,query.getPageSize());
        List<Role> list = this.getList(query);
        return new PageInfo<>(list);
    }

    @Override
    public List<Role> getList(RoleQuery query) {
        LambdaQueryWrapper<Role> queryWrapper = createBaseWrapper(query);
        return this.list(queryWrapper);
    }

    @Override
    public List<Role> getRelationListByUserUid(String userUid, RoleQuery query) {
        List<UserRoleRelation> userRoleRelationList = this.userRoleRelationService.getListByUserUid(userUid);
        if(CollectionUtil.isEmpty(userRoleRelationList)){
            return Collections.emptyList();
        }
        List<String> roleUidList = EntityUtil.extractProperty(userRoleRelationList ,UserRoleRelation::getRoleUid);
        return this.getListInUids(roleUidList ,query);
    }

    @Override
    public List<Role> getListInUids(List<String> roleUids ,RoleQuery query) {
        if (CollectionUtil.isEmpty(roleUids)){
            return Collections.emptyList();
        }
        LambdaQueryWrapper<Role> queryWrapper = createBaseWrapper(query);
        queryWrapper.in(Role::getUid ,roleUids);
        return this.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignMenuPermissionAndRemoveOld(String roleUid, List<String> menuPermissionUids) {
        this.roleMenuPermissionRelationService.assignAndRemoveOld(roleUid ,menuPermissionUids);
        if(CollectionUtil.isEmpty(menuPermissionUids)){
            return;
        }
        List<MenuPermission> menuPermissionList = this.menuPermissionService.getListByUids(menuPermissionUids);
        List<UserRoleRelation> userRoleRelationList = this.userRoleRelationService.getListByRoleUid(roleUid);
        if(CollectionUtil.isEmpty(userRoleRelationList)){
            return;
        }
        //重构用户和角色的关联
        List<String> userUids = EntityUtil.extractProperty(userRoleRelationList ,UserRoleRelation::getUserUid);
        this.userPermissionRelationService.assignOrRemoveOldByRoleUid(roleUid ,userUids ,menuPermissionList);

        // 清除该用户的超级管理员缓存
        clearSuperAdminCacheForUsers(userUids);
    }

    /**
     * 关联角色或自己创建的角色
     * @param userUid
     * @param query
     * @return
     */
    @Override
    public List<Role> getVisibleByUserUid(String userUid, RoleQuery query) {
        query = query == null ? new RoleQuery() : query;
        DataRelationQuery dataRelationQuery = new DataRelationQuery().setHostId(userUid).setType(DataRelationEnum.userRoleShare.getValue());
        List<DataRelation> dataRelationList = this.dataRelationService.getList(dataRelationQuery);
        List<String> roleUids = EntityUtil.extractProperty(dataRelationList ,DataRelation::getRelationId);
        LambdaQueryWrapper<Role> queryWrapper = createBaseWrapper(query);
        queryWrapper.and(andWrapper->{
           andWrapper.in(CollectionUtil.isNotEmpty(roleUids) ,Role::getUid ,roleUids).or().eq(Role::getCreatorId ,ClientContextHelper.getClientInfo().getId().toString());
        });
        return list(queryWrapper);
    }

    @Override
    public void resetUserRelationShare(String userUid, List<String> roleUids) {
        this.dataRelationService.reset(DataRelationEnum.userRoleShare.getValue() ,userUid ,roleUids);
    }

    @Override
    public List<String> getVisibleNamesByUserUid(String userUid, RoleQuery query) {
        return getVisibleByUserUid(userUid ,query).stream().collect(ArrayList<String>::new ,(l ,r)->l.add(r.getName()) ,(l ,r)->{}).stream().filter(s -> StrUtil.isNotBlank(s)).collect(Collectors.toList());
    }

    @Override
    public List<UserRoleRelationBo> getBoByUserUids(List<String> userUids) {
        List<UserRoleRelation> userRoleRelationList = this.userRoleRelationService.getListByUserUids(userUids);
        List<String> roleUids = EntityUtil.extractProperty(userRoleRelationList ,UserRoleRelation::getRoleUid);
        List< Role> roles = this.getListInUids(roleUids ,new RoleQuery());
        Map<String , Role> roleMap = EntityUtil.toMap(roles , Role::getUid);
        List<UserRoleRelationBo> bos = new ArrayList<>();
        for (UserRoleRelation userRoleRelation : userRoleRelationList) {
            UserRoleRelationBo bo = BeanUtil.copyProperties(userRoleRelation , UserRoleRelationBo.class);
            if(roleMap.containsKey(userRoleRelation.getRoleUid())) {
                bo.setRoleName(roleMap.get(userRoleRelation.getRoleUid()).getName());
            }
            bos.add(bo);
        }
        return bos;
    }

    @Override
    public boolean isSuperAdmin() {
        if(!ClientContextHelper.isLogin()){
            return true;
        }
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();

        // 构造缓存键
        String cacheKey = "user:isSuperAdmin:" + clientInfo.getId();

        // 尝试从缓存中获取结果
        Boolean cachedResult = (Boolean) redisTemplate.opsForValue().get(cacheKey);
        if (cachedResult != null) {
            return cachedResult;
        }

        // 缓存中没有则从数据库查询
        List<String> roles = this.getVisibleNamesByUserUid(clientInfo.getId().toString(), null);
        boolean isSuperAdmin = roles.contains("超级管理员");

        // 将结果缓存30分钟
        redisTemplate.opsForValue().set(cacheKey, isSuperAdmin, 30, java.util.concurrent.TimeUnit.MINUTES);

        return isSuperAdmin;
    }

    // 辅助方法：清除特定角色相关的用户超级管理员缓存
    private void clearSuperAdminCacheForRole(String roleUid) {
        // 获取与该角色关联的所有用户
        List<UserRoleRelation> userRoleRelations = this.userRoleRelationService.getListByRoleUid(roleUid);
        List<String> userUids = EntityUtil.extractProperty(userRoleRelations, UserRoleRelation::getUserUid);

        // 清除这些用户的缓存
        clearSuperAdminCacheForUsers(userUids);

        // 获取通过分享获得该角色的用户
        DataRelationQuery query = new DataRelationQuery()
                .setRelationId(roleUid)
                .setType(DataRelationEnum.userRoleShare.getValue());
        List<DataRelation> dataRelations = this.dataRelationService.getList(query);
        List<String> sharedUserUids = EntityUtil.extractProperty(dataRelations, DataRelation::getHostId);

        // 清除这些用户的缓存
        clearSuperAdminCacheForUsers(sharedUserUids);
    }
    // 辅助方法：清除多个用户的超级管理员缓存
    @Override
    public void clearSuperAdminCacheForUsers(List<String> userUids) {
        if (CollectionUtil.isEmpty(userUids)) {
            return;
        }

        List<String> cacheKeys = userUids.stream()
                .map(uid -> "user:isSuperAdmin:" + uid)
                .collect(Collectors.toList());

        redisTemplate.delete(cacheKeys);
    }

    @Override
    public Role getOneByName(String name) {
        return this.getOne(new LambdaQueryWrapper<Role>().eq(Role::getName ,name).last("LIMIT 1"));
    }


    // 辅助方法：清除特定用户的超级管理员缓存
    private void clearSuperAdminCacheForUser(String userUid) {
        String cacheKey = "user:isSuperAdmin:" + userUid;
        redisTemplate.delete(cacheKey);
    }


    private LambdaQueryWrapper<Role> createBaseWrapper(RoleQuery query) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
        if (query == null) {
            return queryWrapper;
        }
        queryWrapper.like(StrUtil.isNotBlank(query.getName()),Role::getName ,query.getName());
        queryWrapper.like(StrUtil.isNotBlank(query.getNotes()),Role::getNotes ,query.getNotes());
        if(CollectionUtil.isNotEmpty(query.getSorts())){
            //自定义排序
            MybatisPlusHelper.orderAndIgnoreError(Role.class, queryWrapper, query.getSorts());
        }else{
            queryWrapper.orderByDesc(Role::getCreatedTime);
        }
        return queryWrapper;
    }
}
