import type { Context } from "@wrnexus/core";
import type {
  CaptchaEngine,
  CaptchaProvider,
  CaptchaVerificationResult,
  VerifyCaptchaInput,
} from "./types.ts";
import { selfHostedProvider } from "./providers/self-hosted.ts";

export function captchaTokenFrom(
  value: Request | Headers | FormData | URLSearchParams | Record<string, unknown>,
  field = "wrn-captcha-response",
): Promise<string | undefined> | string | undefined {
  if (value instanceof Request) {
    const header = value.headers.get("x-wrn-captcha-token");
    if (header) return header;
    return value
      .clone()
      .formData()
      .then((form) => {
        const token = form.get(field) ?? form.get("captchaToken") ?? form.get("responseToken");
        return typeof token === "string" ? token : undefined;
      })
      .catch(async () => {
        try {
          const body = (await value.clone().json()) as Record<string, unknown>;
          const token = body[field] ?? body.captchaToken ?? body.responseToken;
          return token === undefined ? undefined : String(token);
        } catch {
          return undefined;
        }
      });
  }
  if (value instanceof Headers) {
    return value.get("x-wrn-captcha-token") ?? value.get("x-captcha-token") ?? undefined;
  }
  if (value instanceof FormData || value instanceof URLSearchParams) {
    const token = value.get(field) ?? value.get("captchaToken") ?? value.get("responseToken");
    return typeof token === "string" ? token : undefined;
  }
  const token = value[field] ?? value.captchaToken ?? value.responseToken;
  return token === undefined ? undefined : String(token);
}

export function captchaHeaders(token: string): HeadersInit {
  return { "x-wrn-captcha-token": token };
}

export function captchaFields(
  token: string,
  field = "wrn-captcha-response",
): Record<string, string> {
  return { [field]: token };
}

export async function verifyCaptcha(
  providerOrEngine: CaptchaProvider | CaptchaEngine,
  input: VerifyCaptchaInput,
): Promise<CaptchaVerificationResult> {
  const provider: CaptchaProvider =
    "client" in providerOrEngine
      ? (providerOrEngine as CaptchaProvider)
      : selfHostedProvider(providerOrEngine as CaptchaEngine);
  return provider.verify(input);
}

export async function verifyCaptchaOrThrow(
  providerOrEngine: CaptchaProvider | CaptchaEngine,
  input: VerifyCaptchaInput,
): Promise<CaptchaVerificationResult> {
  const result = await verifyCaptcha(providerOrEngine, input);
  if (!result.success) {
    throw new Error(
      `WRN-CAPTCHA-${String(result.code ?? "FAILED").toUpperCase()}: ${result.message ?? "CAPTCHA verification failed"}`,
    );
  }
  return result;
}

export function captchaResultResponse(result: CaptchaVerificationResult): Response {
  return Response.json(result, {
    status: result.success ? 200 : 403,
    headers: { "cache-control": "no-store", "x-content-type-options": "nosniff" },
  });
}

export function captchaContext(ctx: Context): CaptchaVerificationResult | null {
  const result = ctx.locals.captcha;
  return result && typeof result === "object" ? (result as CaptchaVerificationResult) : null;
}
