package com.sckw.system.service;

import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.system.api.model.dto.res.DataPermissionDTO;
import com.sckw.system.model.KwsRole;
import com.sckw.system.model.KwsUser;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 数据权限过滤工具类
 * <p>
 * 用于业务查询拦截，在查询贸易合同/订单/运单等业务数据时，
 * 根据当前用户角色的数据权限配置过滤可见数据范围。
 * <p>
 * 企业数据权限 + 个人数据权限为并集（组合）关系：
 * <ul>
 *     <li>企业数据权限：限制可见企业范围 → SQL: ent_id IN (已选企业)</li>
 *     <li>个人数据权限开启后：在企业范围内仅查看销售人员=本人的数据
 *         → SQL: ent_id IN (已选企业) AND salesman_id = 当前用户</li>
 *     <li>覆盖范围：贸易合同及其衍生的贸易订单、物流订单、运单</li>
 * </ul>
 * <p>
 *
 * @author system
 * @date 2026-03-26
 */
@Slf4j
@Component
public class DataPermissionHelper {

    @Autowired
    private KwsDataPermissionService kwsDataPermissionService;

    @Autowired
    private KwsRoleService kwsRoleService;

    @Autowired
    private KwsUserService kwsUserService;

    /**
     * 获取当前登录用户的数据权限过滤条件
     * <p>
     * 规则：
     * - 平台端管理员：仅管理平台自身创建的角色，数据权限按角色配置
     * - 客户端主账号：可管理本企业+下级企业的角色
     * - 所有用户：企业数据权限 + 个人数据权限为并集关系
     * - 个人数据权限开启后：在已勾选企业范围内，仅查看销售人员=当前用户的数据
     *
     * @return 数据权限过滤条件
     */
    public DataPermissionFilter getPermissionFilter() {
        Long userId = LoginUserHolder.getUserId();
        log.info("开始计算数据权限过滤条件, userId={}", userId);

        DataPermissionFilter filter = new DataPermissionFilter();
        filter.setUserId(userId);

        // 平台管理员默认可见全部
        if (LoginUserHolder.isManager()) {
            Long roleId = LoginUserHolder.getCurrentRoleId();
            log.info("当前用户为平台管理员, userId={}, roleId={}", userId, roleId);
            if (Objects.isNull(roleId)) {
                log.info("平台管理员未指定角色ID，默认拥有全部数据权限, userId={}", userId);
                filter.setAllVisible(true);
                return filter;
            }
            DataPermissionFilter result = buildFilterByRole(roleId, userId, false);
            log.info("平台管理员基于角色构建权限完成, userId={}, roleId={}, allVisible={}, entIdsSize={}",
                    userId, roleId, result.isAllVisible(),
                    result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
            return result;
        }

        // 客户端用户：获取当前使用的角色
        Long roleId = LoginUserHolder.getCurrentRoleId();
        log.info("当前用户为客户端用户, userId={}, currentRoleId={}", userId, roleId);

        if (Objects.isNull(roleId)) {
            // 无角色，查询用户所有角色取并集
            log.info("当前用户未指定角色ID，尝试获取用户所有角色并集, userId={}", userId);
            List<KwsRole> roles = kwsRoleService.queryRoleByUserId(userId);
            if (CollectionUtils.isEmpty(roles)) {
                log.warn("用户无任何角色关联，设置为无数据权限, userId={}", userId);
                filter.setAllVisible(false);
                filter.setVisibleEntIds(Collections.emptySet());
                return filter;
            }
            DataPermissionFilter result = buildFilterByRoles(roles, userId, true);
            log.info("基于用户多角色并集构建权限完成, userId={}, roleCount={}, allVisible={}, entIdsSize={}",
                    userId, roles.size(), result.isAllVisible(),
                    result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
            return result;
        }

        DataPermissionFilter result = buildFilterByRole(roleId, userId, true);
        log.info("基于单角色构建权限完成, userId={}, roleId={}, allVisible={}, entIdsSize={}",
                userId, roleId, result.isAllVisible(),
                result.getVisibleEntIds() != null ? result.getVisibleEntIds().size() : 0);
        return result;
    }

    /**
     * 解析受限的企业ID集合
     * <p>
     * 确保返回的企业ID在当前用户所属企业或角色所属企业的合法范围内。
     *
     * @param role           角色信息
     * @param userId         用户ID
     * @param configuredEntIds 配置的企业ID集合
     * @return 经过校验后的企业ID集合
     */
    private Set<Long> resolveScopedEntIds(KwsRole role, Long userId, Set<Long> configuredEntIds) {
        if (Objects.isNull(role) || Objects.isNull(role.getEntId())) {
            log.warn("角色信息不完整，无法解析企业权限, userId={}, roleId={}", userId, role != null ? role.getId() : null);
            return Collections.emptySet();
        }

        Long userEntId = resolveUserEntId(userId);
        // 校验用户所属企业与角色所属企业是否一致（防止跨企业越权）
        if (Objects.nonNull(userEntId) && !Objects.equals(userEntId, role.getEntId())) {
            log.warn("数据权限企业不匹配，可能存在越权风险, userId={}, userEntId={}, roleId={}, roleEntId={}",
                    userId, userEntId, role.getId(), role.getEntId());
            return Collections.emptySet();
        }

        // 如果未配置具体企业ID，则默认仅允许访问角色所属企业
        if (CollectionUtils.isEmpty(configuredEntIds)) {
            log.debug("未配置具体企业权限，默认限制为角色所属企业, userId={}, roleId={}, entId={}",
                    userId, role.getId(), role.getEntId());
            return new HashSet<>(Collections.singleton(role.getEntId()));
        }

        // 保留配置中与角色所属企业一致的ID（通常配置中只包含角色所属企业或其子企业，此处做交集校验）
        // 注意：retainAll会修改原集合，这里假设configuredEntIds是副本或允许修改
        configuredEntIds.retainAll(Collections.singleton(role.getEntId()));
        log.debug("解析受限企业ID完成, userId={}, roleId={}, finalEntIds={}", userId, role.getId(), configuredEntIds);
        return configuredEntIds;
    }

    /**
     * 解析用户所属的企业ID
     *
     * @param userId 用户ID
     * @return 企业ID，若用户不存在则返回null
     */
    private Long resolveUserEntId(Long userId) {
        if (Objects.isNull(userId)) {
            return null;
        }
        KwsUser user = kwsUserService.selectByKey(userId);
        if (user == null) {
            log.warn("未找到用户信息, userId={}", userId);
            return null;
        }
        return user.getEntId();
    }

    /**
     * 根据单个角色构建过滤条件
     *
     * @param roleId          角色ID
     * @param userId          用户ID
     * @param restrictToOwnedEnt 是否限制在用户所属企业范围内
     * @return 数据权限过滤条件
     */
    private DataPermissionFilter buildFilterByRole(Long roleId, Long userId, boolean restrictToOwnedEnt) {
        log.debug("开始构建单角色权限过滤, userId={}, roleId={}, restrictToOwnedEnt={}", userId, roleId, restrictToOwnedEnt);

        DataPermissionFilter filter = new DataPermissionFilter();
        filter.setUserId(userId);

        // 获取角色配置的企业ID列表
        Set<Long> entIds = new HashSet<>(kwsDataPermissionService.getCachedEntIds(roleId));
        // 获取是否开启个人数据权限（仅看本人）
        boolean personalFlag = kwsDataPermissionService.getCachedPersonalFlag(roleId);
        log.debug("读取角色缓存权限, roleId={}, configuredEntIdsSize={}, personalFlag={}",
                roleId, entIds.size(), personalFlag);

        // 如果需要限制在所属企业范围内，进行二次校验
        if (restrictToOwnedEnt) {
            KwsRole role = kwsRoleService.selectByKey(roleId);
            entIds = resolveScopedEntIds(role, userId, entIds);
        }

        if (CollectionUtils.isEmpty(entIds)) {
            // 未配置企业数据权限或校验后为空，设置为不可见任何企业数据（除非allVisible为true，但此处显式设为false）
            log.info("角色无有效企业数据权限，设置为空权限, userId={}, roleId={}", userId, roleId);
            filter.setAllVisible(false);
            filter.setVisibleEntIds(Collections.emptySet());
        } else {
            filter.setAllVisible(false);
            filter.setVisibleEntIds(entIds);
        }

        filter.setPersonalDataEnabled(personalFlag);
        return filter;
    }

    /**
     * 根据多个角色构建过滤条件（取并集）
     *
     * @param roles           角色列表
     * @param userId          用户ID
     * @param restrictToOwnedEnt 是否限制在用户所属企业范围内
     * @return 数据权限过滤条件
     */
    private DataPermissionFilter buildFilterByRoles(List<KwsRole> roles, Long userId, boolean restrictToOwnedEnt) {
        log.debug("开始构建多角色权限过滤(并集), userId={}, roleCount={}, restrictToOwnedEnt={}",
                userId, roles.size(), restrictToOwnedEnt);

        DataPermissionFilter filter = new DataPermissionFilter();
        filter.setUserId(userId);

        Set<Long> allEntIds = new HashSet<>();
        boolean anyPersonalFlag = false;

        for (KwsRole role : roles) {
            // 获取当前角色配置的企业ID
            Set<Long> entIds = new HashSet<>(kwsDataPermissionService.getCachedEntIds(role.getId()));

            // 如果需要限制在所属企业范围内，进行二次校验
            if (restrictToOwnedEnt) {
                entIds = resolveScopedEntIds(role, userId, entIds);
            }

            // 合并企业ID
            if (CollectionUtils.isNotEmpty(entIds)) {
                allEntIds.addAll(entIds);
            }

            // 只要有一个角色开启了个人数据权限，最终结果即开启
            if (kwsDataPermissionService.getCachedPersonalFlag(role.getId())) {
                anyPersonalFlag = true;
            }
        }

        if (allEntIds.isEmpty()) {
            log.info("多角色合并后无有效企业数据权限，设置为空权限, userId={}", userId);
            filter.setAllVisible(false);
            filter.setVisibleEntIds(Collections.emptySet());
        } else {
            filter.setAllVisible(false);
            filter.setVisibleEntIds(allEntIds);
            log.debug("多角色权限合并完成, userId={}, totalEntIdsSize={}, anyPersonalFlag={}",
                    userId, allEntIds.size(), anyPersonalFlag);
        }

        filter.setPersonalDataEnabled(anyPersonalFlag);
        return filter;
    }



    /**
     * 根据显式参数获取数据权限过滤条件（不依赖LoginUserHolder，适用于Feign远程调用）
     *
     * @param userId    用户ID
     * @param roleId    当前使用的角色ID，null时取用户所有角色的并集
     * @param isManager 是否平台管理员
     * @return 数据权限过滤条件
     */
    public DataPermissionFilter getPermissionFilter(Long userId, Long roleId, boolean isManager) {
        log.info("通过显式参数计算数据权限过滤条件, userId={}, roleId={}, isManager={}", userId, roleId, isManager);

        DataPermissionFilter filter = new DataPermissionFilter();
        filter.setUserId(userId);

        if (isManager) {
            if (Objects.isNull(roleId)) {
                log.info("平台管理员未指定角色ID，默认拥有全部数据权限, userId={}", userId);
                filter.setAllVisible(true);
                return filter;
            }
            DataPermissionFilter result = buildFilterByRole(roleId, userId, false);
            log.info("平台管理员基于角色构建权限完成(远程调用), userId={}, roleId={}", userId, roleId);
            return result;
        }

        if (Objects.isNull(roleId)) {
            log.info("客户端用户未指定角色ID，尝试获取用户所有角色并集(远程调用), userId={}", userId);
            List<KwsRole> roles = kwsRoleService.queryRoleByUserId(userId);
            if (CollectionUtils.isEmpty(roles)) {
                log.warn("用户无任何角色关联，设置为无数据权限(远程调用), userId={}", userId);
                filter.setAllVisible(false);
                filter.setVisibleEntIds(Collections.emptySet());
                return filter;
            }
            DataPermissionFilter result = buildFilterByRoles(roles, userId, true);
            log.info("基于用户多角色并集构建权限完成(远程调用), userId={}, roleCount={}", userId, roles.size());
            return result;
        }

        DataPermissionFilter result = buildFilterByRole(roleId, userId, true);
        log.info("基于单角色构建权限完成(远程调用), userId={}, roleId={}", userId, roleId);
        return result;
    }

    /**
     * 构建数据权限DTO（供Feign远程接口返回给其他模块）
     * <p>
     * 其他模块通过 DataPermissionFeignService.getDataPermissionFilter() 间接调用本方法，
     * 获取可序列化的 DataPermissionDTO，然后调用 dto.applyTo(params) 注入查询参数。
     *
     * @param userId    用户ID
     * @param roleId    当前使用的角色ID
     * @param isManager 是否平台管理员
     * @return 可序列化的数据权限过滤DTO
     */
    public DataPermissionDTO buildPermissionDTO(Long userId, Long roleId, boolean isManager) {
        log.info("构建数据权限DTO, userId={}, roleId={}, isManager={}", userId, roleId, isManager);
        DataPermissionFilter filter = getPermissionFilter(userId, roleId, isManager);
        DataPermissionDTO dto = new DataPermissionDTO();
        dto.setUserId(filter.getUserId());
        dto.setAllVisible(filter.isAllVisible());
        dto.setVisibleEntIds(filter.getVisibleEntIds());
        dto.setPersonalDataEnabled(filter.isPersonalDataEnabled());
        log.info("数据权限DTO构建完成, allVisible={}, entIdsSize={}, personalEnabled={}",
                dto.isAllVisible(),
                dto.getVisibleEntIds() != null ? dto.getVisibleEntIds().size() : 0,
                dto.isPersonalDataEnabled());
        return dto;
    }

    /**
     * 数据权限过滤条件
     */
    @Data
    public static class DataPermissionFilter {
        /** 当前用户ID */
        private Long userId;
        /** 是否可见全部数据（未配置数据权限时为true） */
        private boolean allVisible;
        /** 可见的企业ID集合 */
        private Set<Long> visibleEntIds;
        /** 是否开启个人数据权限（仅查看本人作为销售的数据） */
        private boolean personalDataEnabled;
    }

}