package com.ttstd.signaling.config;

import com.ttstd.signaling.security.AuthException;
import com.ttstd.signaling.service.AdminService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 后台管理接口鉴权过滤器：校验 {@code Authorization: Bearer admt_...} 管理员令牌。
 *
 * <p>与主控端用户体系完全独立，使用 {@link AdminService} 专用令牌（前缀 admt_）。
 * 仅对 {@code /api/admin/**} 生效；免鉴权路径（如登录、健康检查）统一由
 * {@link PublicEndpoints} 管理。
 */
@Component
@Order(2)
public class AdminAuthFilter extends OncePerRequestFilter {

    private final AdminService adminService;

    public AdminAuthFilter(AdminService adminService) {
        this.adminService = adminService;
    }

    private static final String PREFIX = "/api/admin/";

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getServletPath();
        if (path == null || !path.startsWith(PREFIX)) {
            return true;
        }
        // 免鉴权路径（由 PublicEndpoints 统一管理，例如登录接口）放行
        return PublicEndpoints.isPublic(request);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (header == null || !header.startsWith("Bearer ")) {
            writeUnauthorized(response, "缺少管理员令牌");
            return;
        }
        String token = header.substring("Bearer ".length()).trim();
        if (token.isEmpty()) {
            writeUnauthorized(response, "管理员令牌为空");
            return;
        }
        AdminAuthPrincipal principal;
        try {
            Map<String, Object> claims = adminService.verifyToken(token);
            String sub = com.ttstd.signaling.security.JwtService.claimAsString(claims, "sub");
            principal = new AdminAuthPrincipal(sub);
        } catch (AuthException e) {
            writeUnauthorized(response, e.getPublicMessage());
            return;
        } catch (Exception e) {
            writeUnauthorized(response, "令牌校验失败");
            return;
        }

        // 令牌校验通过后才放行。注意：doFilter 必须在 try/catch 之外，
        // 否则下游 Controller/Service 抛出的业务异常（如密码强度不足的 400）
        // 会被误捕获并改写成 401，导致前端清除令牌、管理员被强制下线。
        request.setAttribute("adminPrincipal", principal);
        filterChain.doFilter(request, response);
    }

    private void writeUnauthorized(HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String body = "{\"error\":\"unauthorized\",\"message\":\""
                + escape(message) + "\"}";
        response.getWriter().write(body);
    }

    private static String escape(String s) {
        if (s == null) {
            return "";
        }
        return s.replace("\\", "\\\\").replace("\"", "\\\"");
    }
}
