package com.cameleer.server.app.interceptor;

import com.cameleer.server.core.admin.AuditCategory;
import com.cameleer.server.core.admin.AuditResult;
import com.cameleer.server.core.admin.AuditService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Map;
import java.util.Set;

/**
 * Safety-net audit interceptor that logs a basic entry for any state-changing
 * request (POST/PUT/DELETE) that was not explicitly audited by the controller.
 * <p>
 * Controllers that call {@link AuditService#log} set the {@code audit.logged}
 * request attribute, which this interceptor checks to avoid double-recording.
 */
@Component
public class AuditInterceptor implements HandlerInterceptor {

    private static final Set<String> AUDITABLE_METHODS = Set.of("POST", "PUT", "DELETE");
    private static final Set<String> EXCLUDED_PATHS = Set.of("/api/v1/search/executions");

    private final AuditService auditService;

    public AuditInterceptor(AuditService auditService) {
        this.auditService = auditService;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) {
        if (!AUDITABLE_METHODS.contains(request.getMethod())) {
            return;
        }
        if (Boolean.TRUE.equals(request.getAttribute("audit.logged"))) {
            return;
        }

        String path = request.getRequestURI();
        if (EXCLUDED_PATHS.contains(path)) {
            return;
        }
        AuditResult result = response.getStatus() < 400 ? AuditResult.SUCCESS : AuditResult.FAILURE;

        auditService.log(
                "HTTP " + request.getMethod() + " " + path,
                AuditCategory.INFRA,
                path,
                Map.of("status", response.getStatus()),
                result,
                request);
    }
}
