package com.starry.admin.common.filter;

import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.service.impl.PlayClerkUserInfoServiceImpl;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.custom.service.impl.PlayCustomUserInfoServiceImpl;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.common.context.CustomSecurityContextHolder;
import java.io.IOException;
import java.util.UUID;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 请求关联ID过滤器，为每个HTTP请求生成唯一的跟踪ID
 * 用于日志关联和请求链路追踪
 *
 * @author Claude
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorrelationFilter implements Filter {

    @Resource
    @Lazy
    private WxTokenService wxTokenService;

    @Resource
    @Lazy
    private PlayClerkUserInfoServiceImpl clerkUserInfoService;

    @Resource
    @Lazy
    private PlayCustomUserInfoServiceImpl customUserInfoService;

    public static final String CORRELATION_ID_HEADER = "X-Correlation-ID";
    public static final String CORRELATION_ID_MDC_KEY = "correlationId";
    public static final String USER_ID_MDC_KEY = "userId";
    public static final String TENANT_ID_MDC_KEY = "tenantId";
    public static final String TENANT_KEY_MDC_KEY = "tenantKey";
    public static final String REQUEST_URI_MDC_KEY = "requestUri";
    public static final String REQUEST_METHOD_MDC_KEY = "requestMethod";

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        if (!(request instanceof HttpServletRequest)) {
            chain.doFilter(request, response);
            return;
        }

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        try {
            // 生成或获取关联ID
            String correlationId = getOrGenerateCorrelationId(httpRequest);

            // 设置MDC上下文
            MDC.put(CORRELATION_ID_MDC_KEY, correlationId);
            MDC.put(REQUEST_URI_MDC_KEY, httpRequest.getRequestURI());
            MDC.put(REQUEST_METHOD_MDC_KEY, httpRequest.getMethod());

            // 提取并设置租户信息
            String tenantKey = httpRequest.getHeader("tenantkey");
            if (tenantKey != null && !tenantKey.trim().isEmpty()) {
                MDC.put(TENANT_KEY_MDC_KEY, tenantKey);
            }

            // 尝试从安全上下文获取租户ID
            try {
                String tenantId = CustomSecurityContextHolder.getTenantId();
                if (tenantId != null && !tenantId.trim().isEmpty() && !"9999".equals(tenantId)) {
                    MDC.put(TENANT_ID_MDC_KEY, tenantId);
                }
            } catch (Exception e) {
                // 忽略获取租户ID的异常
            }

            // 尝试获取用户ID（可能来自JWT或其他认证信息）
            String userId = extractUserId(httpRequest);
            if (userId != null) {
                MDC.put(USER_ID_MDC_KEY, userId);
            }

            // 将关联ID添加到响应头
            httpResponse.setHeader(CORRELATION_ID_HEADER, correlationId);

            // 继续过滤器链
            chain.doFilter(request, response);

        } finally {
            // 清理MDC上下文
            MDC.clear();
        }
    }

    /**
     * 获取或生成关联ID
     * 优先从请求头获取，如果没有则生成新的
     */
    private String getOrGenerateCorrelationId(HttpServletRequest request) {
        String correlationId = request.getHeader(CORRELATION_ID_HEADER);
        if (correlationId == null || correlationId.trim().isEmpty()) {
            correlationId = "REQ-" + UUID.randomUUID().toString().substring(0, 8);
        }
        return correlationId;
    }

    /**
     * 尝试从请求中提取用户ID
     * 根据项目的认证机制：支持微信端(clerk/custom token)和管理端(Authorization header)
     */
    private String extractUserId(HttpServletRequest request) {
        try {
            // 1. 微信端 - Clerk用户认证
            String clerkToken = request.getHeader("clerkusertoken");
            if (clerkToken != null && !clerkToken.trim().isEmpty()) {
                return extractUserIdFromWxToken(clerkToken, "clerk");
            }

            // 2. 微信端 - Custom用户认证
            String customToken = request.getHeader("customusertoken");
            if (customToken != null && !customToken.trim().isEmpty()) {
                return extractUserIdFromWxToken(customToken, "custom");
            }

            // 3. 管理端 - JWT Bearer token认证
            String authHeader = request.getHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                return extractUserIdFromJwtToken(authHeader);
            }

        } catch (Exception e) {
            // 如果解析失败，不影响主流程，只是记录日志时没有用户ID
            // 可以选择记录debug日志，但不抛异常
        }

        return null;
    }

    /**
     * 从微信token中提取真实用户ID
     */
    private String extractUserIdFromWxToken(String token, String userType) {
        try {
            // 使用WxTokenService解析JWT token获取真实用户ID
            String userId = wxTokenService.getWxUserIdByToken(token);

            if (userId != null) {
                // 根据用户类型获取更多用户信息（可选）
                if ("clerk".equals(userType)) {
                    PlayClerkUserInfoEntity clerkUser = clerkUserInfoService.selectById(userId);
                    if (clerkUser != null) {
                        // 返回格式: clerk_userId 或者可以包含昵称等信息
                        return "clerk_" + userId;
                    }
                } else if ("custom".equals(userType)) {
                    PlayCustomUserInfoEntity customUser = customUserInfoService.selectById(userId);
                    if (customUser != null) {
                        return "custom_" + userId;
                    }
                }

                // 如果查询用户详情失败，至少返回基础用户ID
                return userType + "_" + userId;
            }

        } catch (Exception e) {
            // Token解析失败，可能是过期或无效token，不影响主流程
        }

        return null;
    }

    /**
     * 从管理端JWT token中提取用户ID
     */
    private String extractUserIdFromJwtToken(String authHeader) {
        try {
            // 管理端的JWT解析比较复杂，这里先返回标识
            // 实际应该通过JwtToken组件或SecurityUtils获取当前登录用户信息
            return "admin_user";

        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑
    }

    @Override
    public void destroy() {
        // 清理逻辑
    }
}
