package com.bizzan.bitrade.interceptor;

import com.bizzan.bitrade.constant.SysConstant;
import com.bizzan.bitrade.core.DirectAdminToken;
import com.bizzan.bitrade.entity.Admin;
import com.bizzan.bitrade.util.RedisManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.json.JSONObject;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * 管理后台 Token 鉴权拦截器
 * 从请求头 Authorization 中读取 Token，校验 Redis 中是否存在对应的管理员信息。
 * 校验通过后将 Admin 对象写入 HttpSession，保证后续 @SessionAttribute 注解及
 * Shiro @RequiresPermissions 注解正常工作。
 *
 * @author system
 * @date 2026-05-11
 */
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {

    /** 前端请求头中携带 Token 的字段名 */
    private static final String TOKEN_HEADER = "Authorization";

    /**
     * 请求前置处理：验证 Redis Token
     *
     * @param request  HTTP 请求
     * @param response HTTP 响应
     * @param handler  处理器
     * @return true=放行，false=拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 从请求头中读取 Token
        String token = request.getHeader(TOKEN_HEADER);
        if (StringUtils.isBlank(token)) {
            ajaxReturn(response, 4000, "please login");
            return false;
        }

        // 2. 从 Redis 中获取对应的管理员信息
        BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        RedisManager redisManager = factory.getBean(RedisManager.class);

        Admin admin = redisManager.getAdminByToken(token);
        if (admin == null) {
            ajaxReturn(response, 4000, "token invalid or expired, please login again");
            return false;
        }

        // 3. 将 admin 写入 request attribute，供所有使用 @RequestAttribute(SysConstant.SESSION_ADMIN) 的接口读取
        request.setAttribute(SysConstant.SESSION_ADMIN, admin);

        // 4. 将当前 token 存入请求属性，方便后续接口（如更新 admin 信息后刷新 Redis）读取
        request.setAttribute("ADMIN_TOKEN", token);

        // 5. 通知 Shiro 当前用户已认证，保证 @RequiresPermissions 注解正常工作
        Subject subject = SecurityUtils.getSubject();
        if (!subject.isAuthenticated()) {
            subject.login(new DirectAdminToken(admin));
        }

        return true;
    }

    /**
     * 向客户端返回 JSON 错误响应
     *
     * @param response HTTP 响应
     * @param code     错误码
     * @param msg      错误信息
     */
    private void ajaxReturn(HttpServletResponse response, int code, String msg) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        JSONObject json = new JSONObject();
        json.put("code", code);
        json.put("message", msg);
        out.print(json.toString());
        out.flush();
        out.close();
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}
