package com.spot.interceptor;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.spot.constant.SysConstant;
import com.spot.enums.MessageCode;
import com.spot.resp.ApiResultVo;
import com.spot.utils.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 登录鉴权拦截器，从 Session 中校验用户登录状态
 * Session 由 dage ucenter-api 写入（key=API_MEMBER，值为 dage 的 AuthMember 对象）
 * 为避免跨模块类型冲突，通过 JSON 序列化提取 id，存入 request attribute 供 Controller 使用
 *
 * @author jean
 * @date 2026-05-09
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

    /**
     * 请求前置拦截：从 Session 读取用户信息，将 memberId 写入 request attribute
     *
     * @param request  HTTP请求
     * @param response HTTP响应
     * @param handler  处理器
     * @return true=放行，false=拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 非 Controller 方法请求直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        // 从 Session 读取用户对象（dage 写入的 AuthMember，全限定名不同，不能直接强转）
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object user = session.getAttribute(SysConstant.SESSION_MEMBER);
            if (user != null) {
                // 通过 JSON 序列化提取 id，避免跨模块 ClassCastException
                Long memberId = extractMemberId(user);
                if (memberId != null) {
                    request.setAttribute(SysConstant.REQUEST_ATTR_MEMBER_ID, memberId);
                    return true;
                }
            }
        }

        log.warn("鉴权失败 - Session 中无用户信息, URI: {}", request.getRequestURI());
        writeUnauthorizedResponse(request, response);
        return false;
    }

    /**
     * 从 Session 中的用户对象提取 id（通过 JSON 序列化，兼容不同类加载器的同名类）
     *
     * @param user Session 中的用户对象
     * @return 用户ID，提取失败返回 null
     */
    private Long extractMemberId(Object user) {
        try {
            JSONObject json = JSON.parseObject(JSON.toJSONString(user));
            return json.getLong("id");
        } catch (Exception e) {
            log.error("提取 memberId 失败", e);
            return null;
        }
    }

    /**
     * 向响应写入未登录的 JSON 错误信息
     *
     * @param request  HTTP请求（用于读取语言标识）
     * @param response HTTP响应
     */
    private void writeUnauthorizedResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String lang = RequestUtils.getLangFromHeader(request);
        ApiResultVo<Void> result = ApiResultVo.fail(lang, MessageCode.USER_NOT_LOGIN);
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType("application/json");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.getWriter().write(JSON.toJSONString(result));
    }
}
