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

export interface ParseWithCaptchaOptions {
  action: string;
  provider?: CaptchaProvider;
  engine?: CaptchaEngine;
  responseField?: string;
  bindHostname?: boolean;
  bindSession?: boolean;
  bindIp?: boolean;
}

export interface CaptchaParseResult<T = Record<string, unknown>> extends ParseResult<T> {
  captcha: CaptchaVerificationResult;
}

export async function parseWithCaptcha<T = Record<string, unknown>>(
  schema: ObjectSchema,
  input: Record<string, unknown>,
  ctx: Context,
  options: ParseWithCaptchaOptions,
): Promise<CaptchaParseResult<T>> {
  const parsed = schema.parse(input) as ParseResult<T>;
  const provider =
    options.provider ?? (options.engine ? selfHostedProvider(options.engine) : undefined);
  if (!provider) throw new TypeError("parseWithCaptcha requires provider or engine");
  const field = options.responseField ?? provider.client.responseField;
  const token = input[field] ?? input.captchaToken ?? input.responseToken;
  const captcha = await provider.verify({
    action: options.action,
    providerToken: token === undefined ? undefined : String(token),
    responseToken: token === undefined ? undefined : String(token),
    hostname: options.bindHostname === false ? undefined : ctx.url.hostname,
    sessionId: options.bindSession === false ? undefined : ctx.session.id(),
    ip: options.bindIp ? ctx.ip : undefined,
  });
  const errors = { ...parsed.errors };
  if (!captcha.success) errors[field] = captcha.message ?? "CAPTCHA verification failed";
  return {
    ...parsed,
    ok: parsed.ok && captcha.success,
    errors,
    captcha,
  };
}
