package com.sckw.system.service;

import com.sckw.core.exception.SystemException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.IdWorker;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.system.dao.KwsDataPermissionDao;
import com.sckw.system.dao.KwsEnterpriseDao;
import com.sckw.system.dao.KwsRoleDao;
import com.sckw.system.model.KwsDataPermission;
import com.sckw.system.model.KwsEnterprise;
import com.sckw.system.model.KwsRole;
import com.sckw.system.model.vo.req.DataPermissionReqVo;
import com.sckw.system.model.vo.res.DataPermissionEntTreeResVo;
import com.sckw.system.model.vo.res.DataPermissionResVo;
import com.sckw.system.model.vo.res.EntBaseInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 数据权限Service
 *
 * @author cxf
 * @date 2026-03-26
 */
@Slf4j
@Service
public class KwsDataPermissionService {

    /** Redis缓存key前缀：角色数据权限企业ID列表 */
    private static final String REDIS_DATA_PERM_PREFIX = "dataPermission:role:";
    /** Redis缓存key前缀：角色个人数据权限标识 */
    private static final String REDIS_PERSONAL_FLAG_PREFIX = "dataPermission:personal:";
    /** 缓存过期时间：2小时 */
    private static final long CACHE_EXPIRE = 2 * 60 * 60L;

    @Autowired
    private KwsDataPermissionDao kwsDataPermissionDao;

    @Autowired
    private KwsRoleDao kwsRoleDao;

    @Autowired
    private KwsEnterpriseDao kwsEnterpriseDao;

    /**
     * 保存/更新角色数据权限（先删后插）
     *
     * @param reqVo 数据权限请求
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveDataPermission(DataPermissionReqVo reqVo) {
        Long roleId = reqVo.getRoleId();
        KwsRole kwsRole = kwsRoleDao.selectByKey(roleId);
        if (Objects.isNull(kwsRole)) {
            throw new SystemException(HttpStatus.CRUD_FAIL_CODE, "角色不存在");
        }

        // 1. 更新角色的个人数据权限标识
        KwsRole updateRole = new KwsRole();
        updateRole.setId(roleId);
        if (Objects.nonNull(reqVo.getPersonalDataFlag())) {
            kwsRole.setPersonalDataFlag(reqVo.getPersonalDataFlag());
            updateRole.setPersonalDataFlag(reqVo.getPersonalDataFlag());
            kwsRoleDao.updateById(updateRole);
        }

        // 2. 逻辑删除旧的数据权限
        kwsDataPermissionDao.deleteByRoleId(roleId);

        // 3. 批量插入新的数据权限
        List<Long> entIds = reqVo.getEntIds();
        if (CollectionUtils.isNotEmpty(entIds)) {
            Long userId = LoginUserHolder.getUserId();
            Date now = new Date();
            List<KwsDataPermission> permList = new ArrayList<>();
            for (Long entId : entIds) {
                KwsDataPermission perm = new KwsDataPermission();
                perm.setId(new IdWorker(1L).nextId());
                perm.setRoleId(roleId);
                perm.setEntId(entId);
                perm.setStatus(Global.NO);
                perm.setDelFlag(Global.NO);
                perm.setCreateBy(userId);
                perm.setCreateTime(now);
                perm.setUpdateBy(userId);
                perm.setUpdateTime(now);
                permList.add(perm);
            }
            if (kwsDataPermissionDao.saveBatch(permList) < permList.size()) {
                throw new SystemException(HttpStatus.CRUD_FAIL_CODE, HttpStatus.INSERT_FAIL);
            }
        }

        // 4. 清除该角色的数据权限缓存，使权限立即生效
        clearCache(roleId);
    }

    /**
     * 查询角色的数据权限配置
     *
     * @param roleId 角色ID
     * @return 数据权限响应
     */
    public DataPermissionResVo getDataPermission(Long roleId) {
        KwsRole kwsRole = kwsRoleDao.selectByKey(roleId);
        if (Objects.isNull(kwsRole)) {
            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, "角色不存在");
        }

        DataPermissionResVo resVo = new DataPermissionResVo();
        resVo.setRoleId(roleId);
        resVo.setRoleName(kwsRole.getName());
        resVo.setPersonalDataFlag(kwsRole.getPersonalDataFlag() != null ? kwsRole.getPersonalDataFlag() : Global.NO);

        List<KwsDataPermission> permList = kwsDataPermissionDao.selectByRoleId(roleId);
        if (CollectionUtils.isNotEmpty(permList)) {
            List<Long> entIds = permList.stream().map(KwsDataPermission::getEntId).toList();
            resVo.setEntIds(entIds);
            // 查询企业名称
            List<KwsEnterprise> entList = kwsEnterpriseDao.selectAllByKeys(entIds);
            if (CollectionUtils.isNotEmpty(entList)) {
                resVo.setEntNames(entList.stream().map(KwsEnterprise::getFirmName).toList());
            }
        } else {
            resVo.setEntIds(new ArrayList<>());
            resVo.setEntNames(new ArrayList<>());
        }

        return resVo;
    }

    /**
     * 查询数据权限企业树
     * 客户端：展示当前账号所属企业及下级企业
     * 平台端：展示所有入驻企业
     *
     * @return 企业树
     */
    public List<DataPermissionEntTreeResVo> getEntTree() {
        List<DataPermissionEntTreeResVo> treeList;

        if (LoginUserHolder.isManager()) {
            // 平台端：展示所有入驻企业
            List<KwsEnterprise> allEnts = kwsEnterpriseDao.findAllEnterprise();
            treeList = buildEntTree(allEnts, 0L);
        } else {
            // 客户端：展示当前企业及下级企业（递归CTE查询）
            Long entId = LoginUserHolder.getEntId();
            List<EntBaseInfo> entBaseInfos = kwsEnterpriseDao.queryCte(entId);
            if (CollectionUtils.isEmpty(entBaseInfos)) {
                return new ArrayList<>();
            }
            treeList = buildEntTreeFromCte(entBaseInfos, entId);
        }

        return treeList;
    }

    /**
     * 根据角色ID列表级联删除数据权限（角色删除时调用）
     *
     * @param roleIds 角色ID列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteByRoleIds(List<Long> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return;
        }
        kwsDataPermissionDao.deleteByRoleIds(roleIds);
        // 清除所有相关角色的缓存
        for (Long roleId : roleIds) {
            clearCache(roleId);
        }
    }

    // ==================== 缓存相关 ====================

    /**
     * 从缓存获取角色可访问的企业ID列表，缓存未命中则查库并回填
     *
     * @param roleId 角色ID
     * @return 可访问的企业ID集合
     */
    public Set<Long> getCachedEntIds(Long roleId) {
        String cacheKey = REDIS_DATA_PERM_PREFIX + roleId;
        try {
            Object cached = RedissonUtils.get(cacheKey);
            if (Objects.nonNull(cached) && cached instanceof Set) {
                return (Set<Long>) cached;
            }
        } catch (Exception e) {
            log.warn("读取数据权限缓存异常, roleId={}", roleId, e);
        }

        // 缓存未命中，查库
        List<KwsDataPermission> permList = kwsDataPermissionDao.selectByRoleId(roleId);
        Set<Long> entIdSet = CollectionUtils.isEmpty(permList)
                ? Collections.emptySet()
                : permList.stream().map(KwsDataPermission::getEntId).collect(Collectors.toSet());

        try {
            RedissonUtils.put(cacheKey, entIdSet, CACHE_EXPIRE);
        } catch (Exception e) {
            log.warn("写入数据权限缓存异常, roleId={}", roleId, e);
        }
        return entIdSet;
    }

    /**
     * 从缓存获取角色的个人数据权限标识
     *
     * @param roleId 角色ID
     * @return true=开启个人数据权限
     */
    public boolean getCachedPersonalFlag(Long roleId) {
        String cacheKey = REDIS_PERSONAL_FLAG_PREFIX + roleId;
        try {
            Object cached = RedissonUtils.get(cacheKey);
            if (Objects.nonNull(cached)) {
                return Objects.equals(cached, Global.YES);
            }
        } catch (Exception e) {
            log.warn("读取个人数据权限缓存异常, roleId={}", roleId, e);
        }

        KwsRole kwsRole = kwsRoleDao.selectByKey(roleId);
        int flag = (kwsRole != null && kwsRole.getPersonalDataFlag() != null) ? kwsRole.getPersonalDataFlag() : Global.NO;
        try {
            RedissonUtils.put(cacheKey, flag, CACHE_EXPIRE);
        } catch (Exception e) {
            log.warn("写入个人数据权限缓存异常, roleId={}", roleId, e);
        }
        return Objects.equals(flag, Global.YES);
    }

    /**
     * 清除角色数据权限缓存
     */
    public void clearCache(Long roleId) {
        try {
            RedissonUtils.delete(REDIS_DATA_PERM_PREFIX + roleId);
            RedissonUtils.delete(REDIS_PERSONAL_FLAG_PREFIX + roleId);
        } catch (Exception e) {
            log.warn("清除数据权限缓存异常, roleId={}", roleId, e);
        }
    }

    // ==================== 私有方法 ====================

    /**
     * 构建企业树（平台端，从全量企业列表构建）
     */
    private List<DataPermissionEntTreeResVo> buildEntTree(List<KwsEnterprise> entList, Long rootPid) {
        if (CollectionUtils.isEmpty(entList)) {
            return new ArrayList<>();
        }
        Map<Long, List<KwsEnterprise>> pidMap = entList.stream()
                .collect(Collectors.groupingBy(e -> e.getPid() != null ? e.getPid() : 0L));

        return buildChildren(pidMap, rootPid);
    }

    private List<DataPermissionEntTreeResVo> buildChildren(Map<Long, List<KwsEnterprise>> pidMap, Long parentId) {
        List<KwsEnterprise> children = pidMap.get(parentId);
        if (CollectionUtils.isEmpty(children)) {
            return null;
        }
        List<DataPermissionEntTreeResVo> result = new ArrayList<>();
        for (KwsEnterprise ent : children) {
            DataPermissionEntTreeResVo node = new DataPermissionEntTreeResVo();
            node.setId(ent.getId());
            node.setPid(ent.getPid());
            node.setFirmName(ent.getFirmName());
            node.setChildren(buildChildren(pidMap, ent.getId()));
            result.add(node);
        }
        return result;
    }

    /**
     * 构建企业树（客户端，从CTE递归结果构建）
     */
    private List<DataPermissionEntTreeResVo> buildEntTreeFromCte(List<EntBaseInfo> entBaseInfos, Long rootEntId) {
        Map<Long, List<EntBaseInfo>> pidMap = entBaseInfos.stream()
                .collect(Collectors.groupingBy(e -> e.getPid() != null ? e.getPid() : 0L));

        // 根节点是当前企业
        List<DataPermissionEntTreeResVo> result = new ArrayList<>();
        for (EntBaseInfo info : entBaseInfos) {
            if (Objects.equals(info.getId(), rootEntId)) {
                DataPermissionEntTreeResVo root = new DataPermissionEntTreeResVo();
                root.setId(info.getId());
                root.setPid(info.getPid());
                root.setFirmName(info.getFirmName());
                root.setChildren(buildCteChildren(pidMap, info.getId()));
                result.add(root);
                break;
            }
        }
        return result;
    }

    private List<DataPermissionEntTreeResVo> buildCteChildren(Map<Long, List<EntBaseInfo>> pidMap, Long parentId) {
        List<EntBaseInfo> children = pidMap.get(parentId);
        if (CollectionUtils.isEmpty(children)) {
            return null;
        }
        List<DataPermissionEntTreeResVo> result = new ArrayList<>();
        for (EntBaseInfo info : children) {
            DataPermissionEntTreeResVo node = new DataPermissionEntTreeResVo();
            node.setId(info.getId());
            node.setPid(info.getPid());
            node.setFirmName(info.getFirmName());
            node.setChildren(buildCteChildren(pidMap, info.getId()));
            result.add(node);
        }
        return result;
    }

}
