package com.pangu.framework.aspectj;

import cn.hutool.core.util.StrUtil;
import com.pangu.common.annotation.DataScope;
import com.pangu.common.core.domain.BaseEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

/**
 * 数据过滤切面
 * 用于实现数据权限控制，根据当前登录用户的角色动态拼接SQL
 * 
 * 权限规则：
 * - admin用户：查看全部数据
 * - 分公司用户（带region_前缀的角色）：只能查看所属区域数据
 * - 学校用户（带school_前缀的角色）：只能查看本校数据
 * 
 * @author 湖北新华业务中台研发团队
 */
@Slf4j
@Aspect
@Component
public class DataScopeAspect {

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScope";

    /**
     * 全部数据权限（超级管理员）
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 区域数据权限（按区域过滤）
     */
    public static final String DATA_SCOPE_REGION = "2";

    /**
     * 本校数据权限（学校用户）
     */
    public static final String DATA_SCOPE_SCHOOL = "3";

    /**
     * 数据权限过滤
     *
     * @param point     切点
     * @param dataScope 注解
     */
    @Before("@annotation(dataScope)")
    public void doBefore(JoinPoint point, DataScope dataScope) {
        clearDataScope(point);
        handleDataScope(point, dataScope);
    }

    /**
     * 处理数据权限
     */
    protected void handleDataScope(JoinPoint joinPoint, DataScope dataScope) {
        // 获取当前的用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            log.debug("数据权限过滤 - 未获取到认证信息，跳过");
            return;
        }

        String username = authentication.getName();
        
        // 超级管理员不过滤数据
        if ("admin".equals(username) || "anonymousUser".equals(username)) {
            log.debug("数据权限过滤 - 管理员或匿名用户，不过滤");
            return;
        }

        // 获取用户角色
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        
        StringBuilder sqlString = new StringBuilder();
        String deptAlias = dataScope.deptAlias();
        String schoolAlias = dataScope.schoolAlias();

        // 解析用户角色，获取数据权限范围
        String dataScopeType = DATA_SCOPE_ALL;
        Long regionId = null;
        Long schoolId = null;

        for (GrantedAuthority authority : authorities) {
            String role = authority.getAuthority();
            
            // 检查是否有管理员角色
            if ("ROLE_admin".equals(role) || "ROLE_ADMIN".equals(role)) {
                log.debug("数据权限过滤 - 检测到管理员角色，不过滤");
                return;
            }
            
            // 区域角色格式: ROLE_region_区域ID（如ROLE_region_101）
            if (role.startsWith("ROLE_region_")) {
                dataScopeType = DATA_SCOPE_REGION;
                try {
                    regionId = Long.parseLong(role.substring("ROLE_region_".length()));
                } catch (NumberFormatException e) {
                    log.warn("解析区域ID失败: {}", role);
                }
            }
            
            // 学校角色格式: ROLE_school_学校ID（如ROLE_school_1）
            if (role.startsWith("ROLE_school_")) {
                dataScopeType = DATA_SCOPE_SCHOOL;
                try {
                    schoolId = Long.parseLong(role.substring("ROLE_school_".length()));
                } catch (NumberFormatException e) {
                    log.warn("解析学校ID失败: {}", role);
                }
            }
        }

        // 根据数据权限类型生成过滤SQL
        if (DATA_SCOPE_REGION.equals(dataScopeType) && regionId != null && StrUtil.isNotBlank(deptAlias)) {
            // 区域过滤
            sqlString.append(" AND ").append(deptAlias).append(".region_id = ").append(regionId);
            log.debug("数据权限过滤 - 区域过滤, regionId={}", regionId);
        }

        if (DATA_SCOPE_SCHOOL.equals(dataScopeType) && schoolId != null && StrUtil.isNotBlank(schoolAlias)) {
            // 学校过滤
            sqlString.append(" AND ").append(schoolAlias).append(".school_id = ").append(schoolId);
            log.debug("数据权限过滤 - 学校过滤, schoolId={}", schoolId);
        }

        // 如果生成了过滤条件，设置到参数中
        if (StrUtil.isNotBlank(sqlString.toString())) {
            setDataScopeToParam(joinPoint, sqlString.toString());
        }
    }

    /**
     * 设置数据权限到参数中
     * 支持BaseEntity及包含params字段的DTO
     */
    private void setDataScopeToParam(JoinPoint joinPoint, String dataScopeValue) {
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }

        Object params = args[0];
        
        // 尝试设置到BaseEntity
        if (params instanceof BaseEntity) {
            ((BaseEntity) params).getParams().put(DATA_SCOPE, dataScopeValue);
            return;
        }

        // 尝试通过反射获取params字段并设置
        try {
            Method getParamsMethod = params.getClass().getMethod("getParams");
            Object paramsMap = getParamsMethod.invoke(params);
            if (paramsMap instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> map = (Map<String, Object>) paramsMap;
                map.put(DATA_SCOPE, dataScopeValue);
            }
        } catch (Exception e) {
            log.debug("无法设置数据权限参数: {}", e.getMessage());
        }
    }

    /**
     * 清理数据权限参数
     */
    private void clearDataScope(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }

        Object params = args[0];
        
        // 尝试清理BaseEntity
        if (params instanceof BaseEntity) {
            ((BaseEntity) params).getParams().put(DATA_SCOPE, "");
            return;
        }

        // 尝试通过反射清理params字段
        try {
            Method getParamsMethod = params.getClass().getMethod("getParams");
            Object paramsMap = getParamsMethod.invoke(params);
            if (paramsMap instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> map = (Map<String, Object>) paramsMap;
                map.put(DATA_SCOPE, "");
            }
        } catch (Exception e) {
            // 忽略清理错误
        }
    }
}
