import { NextRequest, NextResponse } from "next/server";
import { handleDevOneIdCallback, shouldFallbackToDevMock } from "@/lib/dev-api-mock";
import { apiErrorResponse } from "@/lib/api-errors";
import { getOrCreateCorrelationId } from "@/lib/correlation-id";
import { fetchUpstream } from "@/lib/proxy-upstream";
import { handleCallback, isOneIdEnabled } from "@/lib/oneid";

const ONBOARDING_PATH = "/farmers/onboarding";

function redirectToOnboarding(
  req: NextRequest,
  params: Record<string, string>,
  correlationId: string,
): NextResponse {
  const url = new URL(ONBOARDING_PATH, req.nextUrl.origin);
  url.searchParams.set("step", "KYC");
  url.searchParams.set("correlationId", correlationId);
  for (const [key, value] of Object.entries(params)) {
    url.searchParams.set(key, value);
  }
  return NextResponse.redirect(url);
}

export async function GET(req: NextRequest) {
  const correlationId = getOrCreateCorrelationId(req);
  const code = req.nextUrl.searchParams.get("code");
  const state = req.nextUrl.searchParams.get("state");
  const error = req.nextUrl.searchParams.get("error");

  if (error) {
    return redirectToOnboarding(req, { oneid: "error", message: error }, correlationId);
  }

  if (!code || !state) {
    return apiErrorResponse(
      400,
      "BAD_REQUEST",
      "code and state are required",
      correlationId,
    );
  }

  if (shouldFallbackToDevMock() || (isOneIdEnabled() && code.startsWith("mock_"))) {
    const result = handleDevOneIdCallback(code, state);
    if (result.status !== 200) {
      const message =
        typeof result.data === "object" &&
        result.data !== null &&
        "message" in result.data
          ? String((result.data as { message: string }).message)
          : "OneID verification failed";
      return redirectToOnboarding(req, { oneid: "error", message }, correlationId);
    }

    const payload = result.data as {
      kycPayload: Record<string, unknown>;
    };
    return redirectToOnboarding(
      req,
      {
        oneid: "success",
        kyc: Buffer.from(JSON.stringify(payload.kycPayload)).toString("base64url"),
      },
      correlationId,
    );
  }

  if (!isOneIdEnabled()) {
    return apiErrorResponse(503, "SERVICE_UNAVAILABLE", "OneID is not configured", correlationId);
  }

  const upstream = await fetchUpstream(
    `/kyc/oneid/callback?${req.nextUrl.searchParams.toString()}`,
    { correlationId },
  );

  if (upstream?.ok) {
    const data = (await upstream.json().catch(() => ({}))) as {
      kycPayload?: Record<string, unknown>;
    };
    if (data.kycPayload) {
      return redirectToOnboarding(
        req,
        {
          oneid: "success",
          kyc: Buffer.from(JSON.stringify(data.kycPayload)).toString("base64url"),
        },
        correlationId,
      );
    }
  }

  if (!upstream) {
    try {
      await handleCallback(
        { code, state },
        async () => {
          throw new Error("OneID token exchange is not implemented");
        },
      );
    } catch (err) {
      const message = err instanceof Error ? err.message : "OneID verification failed";
      return redirectToOnboarding(req, { oneid: "error", message }, correlationId);
    }

    return apiErrorResponse(
      503,
      "SERVICE_UNAVAILABLE",
      "OneID service unavailable",
      correlationId,
    );
  }

  const data = await upstream.json().catch(() => ({}));
  const message =
    typeof data === "object" && data !== null && "message" in data
      ? String((data as { message: string }).message)
      : "OneID verification failed";
  return redirectToOnboarding(req, { oneid: "error", message }, correlationId);
}
