import { type NextRequest } from "next/server";
import {
  getTrustedOriginDiagnostics,
  recordTrustedOriginViolationAttempt,
  type TrustedOriginDiagnostics,
  type TrustedOriginViolationPhase,
} from "./trusted-origin-debug";
export { getTrustedOriginDiagnostics, type TrustedOriginDiagnostics } from "./trusted-origin-debug";

const DEFAULT_ALLOWED_METHODS = "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS";
const DEFAULT_ALLOWED_HEADERS = [
  "content-type",
  "authorization",
  "x-requested-with",
  "x-athena-tenant",
  "x-athena-client",
  "x-athena-proxy-request-id",
  "x-request-id",
].join(", ");

function appendVary(headers: Headers, value: string): void {
  const current = headers.get("vary");
  if (!current) {
    headers.set("vary", value);
    return;
  }
  const normalizedValues = current
    .split(",")
    .map((part) => part.trim().toLowerCase())
    .filter(Boolean);
  if (normalizedValues.includes(value.toLowerCase())) return;
  headers.set("vary", `${current}, ${value}`);
}

function addCommonCorsVary(headers: Headers): void {
  appendVary(headers, "Origin");
  appendVary(headers, "Access-Control-Request-Method");
  appendVary(headers, "Access-Control-Request-Headers");
}

function applyAllowOrigin(headers: Headers, origin: string): void {
  headers.set("access-control-allow-origin", origin);
  headers.set("access-control-allow-credentials", "true");
}

function buildPreflightHeaders(request: NextRequest): Headers {
  const headers = new Headers();
  addCommonCorsVary(headers);
  headers.set("access-control-allow-methods", DEFAULT_ALLOWED_METHODS);
  headers.set(
    "access-control-allow-headers",
    request.headers.get("access-control-request-headers")?.trim() || DEFAULT_ALLOWED_HEADERS,
  );
  headers.set("access-control-max-age", "86400");
  return headers;
}

function buildOriginRejectedHeaders(request: NextRequest, phase: TrustedOriginViolationPhase): Headers {
  const headers = phase === "proxy_preflight" ? buildPreflightHeaders(request) : new Headers();
  addCommonCorsVary(headers);
  return headers;
}

export function buildOriginRejectionResponse(
  request: NextRequest,
  phase: TrustedOriginViolationPhase,
): Response | null {
  const origin = request.headers.get("origin");
  if (!origin) return null;

  const diagnostics = getTrustedOriginDiagnostics(origin);
  if (diagnostics.allowed) return null;

  const violation = recordTrustedOriginViolationAttempt(request, diagnostics, phase);
  const headers = buildOriginRejectedHeaders(request, phase);
  console.warn("[athena-proxy] request origin rejected", {
    id: violation.id,
    phase: violation.phase,
    method: violation.method,
    requestPath: violation.requestPath,
    deliveredOrigin: violation.deliveredOrigin,
    normalizedDeliveredOrigin: violation.normalizedDeliveredOrigin,
    expectedTrustedOrigins: violation.expectedTrustedOrigins,
    suggestedTrustedOrigin: violation.suggestedTrustedOrigin,
  });

  return Response.json(
    {
      code: "ORIGIN_NOT_TRUSTED",
      message: "Request origin is not allowed by TRUSTED_ORIGINS.",
      phase: violation.phase,
      method: violation.method,
      requestPath: violation.requestPath,
      requestUrl: violation.requestUrl,
      referer: violation.referer,
      deliveredOrigin: violation.deliveredOrigin,
      normalizedDeliveredOrigin: violation.normalizedDeliveredOrigin,
      trustedOriginsConfigured: violation.trustedOriginsConfigured,
      expectedTrustedOrigins: violation.expectedTrustedOrigins,
      expectedTrustedOriginsRaw: violation.expectedTrustedOriginsRaw,
      suggestedTrustedOrigin: violation.suggestedTrustedOrigin,
      suggestedTrustedOriginsRaw: violation.suggestedTrustedOriginsRaw,
      suggestedTrustedOriginsEnvLine: violation.suggestedTrustedOriginsEnvLine,
      suggestionReason: violation.suggestionReason,
    },
    { status: 403, headers },
  );
}

export function applyCorsHeadersForRequest(request: NextRequest, headers: Headers): void {
  addCommonCorsVary(headers);
  const origin = request.headers.get("origin");
  if (!origin) return;

  const diagnostics = getTrustedOriginDiagnostics(origin);
  if (!diagnostics.allowed) return;
  applyAllowOrigin(headers, origin);
}

export function buildPreflightResponse(request: NextRequest): Response | null {
  const origin = request.headers.get("origin");
  if (!origin) return null;

  const rejection = buildOriginRejectionResponse(request, "proxy_preflight");
  if (rejection) return rejection;

  const headers = buildPreflightHeaders(request);
  applyAllowOrigin(headers, origin);
  return new Response(null, { status: 200, headers });
}
