import { NextRequest, NextResponse } from "next/server";
import {
  canFailoverToDevMock,
  handleDevOneIdStart,
  handleDevPilotKycBypass,
  shouldFailoverFromUpstream,
  shouldFallbackToDevMock,
} from "@/lib/dev-api-mock";
import { apiErrorResponse } from "@/lib/api-errors";
import { getOrCreateCorrelationId, withCorrelationId } from "@/lib/correlation-id";
import { fetchUpstream } from "@/lib/proxy-upstream";
import {
  isOneIdEnabled,
  isPilotKycBypassAllowed,
  isValidPinfl,
  startSession,
  type KycAssistMode,
} from "@/lib/oneid";

function resolveRedirectUri(req: NextRequest): string {
  const configured = process.env.ONEID_REDIRECT_URI;
  if (configured) return configured;
  const origin = req.nextUrl.origin;
  return `${origin}/api/kyc/oneid/callback`;
}

export async function GET(req: NextRequest) {
  const correlationId = getOrCreateCorrelationId(req);
  return withCorrelationId(
    NextResponse.json({
      oneIdEnabled: isOneIdEnabled(),
      pilotBypassAllowed: isPilotKycBypassAllowed(),
    }),
    correlationId,
  );
}

export async function POST(req: NextRequest) {
  const correlationId = getOrCreateCorrelationId(req);

  let body: { pinfl?: string; kycAssistMode?: KycAssistMode; action?: string };
  try {
    body = await req.json();
  } catch {
    return apiErrorResponse(400, "BAD_REQUEST", "Invalid JSON body", correlationId);
  }

  if (body.action === "pilot_bypass") {
    if (!isPilotKycBypassAllowed()) {
      return apiErrorResponse(
        403,
        "FORBIDDEN",
        "Pilot KYC bypass is only available in mock mode",
        correlationId,
      );
    }

    const pinfl = body.pinfl?.trim() ?? "";
    if (!isValidPinfl(pinfl)) {
      return apiErrorResponse(400, "BAD_REQUEST", "PINFL must be 14 digits", correlationId);
    }

    const result = handleDevPilotKycBypass(pinfl, "national_id", body.kycAssistMode);
    return withCorrelationId(NextResponse.json(result.data, { status: result.status }), correlationId);
  }

  const pinfl = body.pinfl?.trim() ?? "";
  if (!isValidPinfl(pinfl)) {
    return apiErrorResponse(400, "BAD_REQUEST", "PINFL must be 14 digits", correlationId);
  }

  const redirectUri = resolveRedirectUri(req);

  const respondWithMockStart = () => {
    const mockResult = handleDevOneIdStart(pinfl, redirectUri, body.kycAssistMode);
    return withCorrelationId(
      NextResponse.json(mockResult.data, { status: mockResult.status }),
      correlationId,
    );
  };

  if (shouldFallbackToDevMock()) {
    return respondWithMockStart();
  }

  if (isOneIdEnabled()) {
    try {
      const upstream = await fetchUpstream("/kyc/oneid/start", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          pinfl,
          redirectUri,
          kycAssistMode: body.kycAssistMode,
        }),
        correlationId,
      });

      if (upstream?.ok) {
        const data = await upstream.json().catch(() => ({}));
        return withCorrelationId(NextResponse.json(data, { status: upstream.status }), correlationId);
      }

      if (canFailoverToDevMock() && shouldFailoverFromUpstream(upstream)) {
        return respondWithMockStart();
      }

      if (!upstream) {
        try {
          const session = await startSession({
            pinfl,
            redirectUri,
            kycAssistMode: body.kycAssistMode,
          });
          return withCorrelationId(NextResponse.json(session, { status: 200 }), correlationId);
        } catch (err) {
          const message = err instanceof Error ? err.message : "OneID service unavailable";
          return apiErrorResponse(503, "SERVICE_UNAVAILABLE", message, correlationId);
        }
      }

      const data = await upstream.json().catch(() => ({}));
      return withCorrelationId(NextResponse.json(data, { status: upstream.status }), correlationId);
    } catch {
      if (canFailoverToDevMock()) {
        return respondWithMockStart();
      }

      return apiErrorResponse(
        503,
        "SERVICE_UNAVAILABLE",
        "OneID service unavailable",
        correlationId,
      );
    }
  }

  if (canFailoverToDevMock()) {
    return respondWithMockStart();
  }

  return apiErrorResponse(
    503,
    "SERVICE_UNAVAILABLE",
    "OneID is not configured",
    correlationId,
  );
}
