import type {
  CaptchaChallengeGenerator,
  CaptchaChallengeType,
  CaptchaGeneratorContext,
  GeneratedCaptchaChallenge,
} from "../types.ts";
import { renderTextChallenge } from "./visual.ts";

const NUMBERS = "23456789";
const ALPHA = "ABCDEFGHJKMNPQRSTUVWXYZ";
const ALPHANUMERIC = `${ALPHA}${NUMBERS}`;

function defaultLength(context: CaptchaGeneratorContext): number {
  return (
    context.length ?? (context.difficulty === "easy" ? 4 : context.difficulty === "hard" ? 7 : 6)
  );
}

function charset(type: CaptchaChallengeType): string {
  if (type === "number") return NUMBERS;
  if (type === "alpha") return ALPHA;
  return ALPHANUMERIC;
}

function generateText(
  type: "number" | "alpha" | "alphanumeric",
  context: CaptchaGeneratorContext,
): GeneratedCaptchaChallenge {
  const source = charset(type);
  const length = Math.max(3, Math.min(10, defaultLength(context)));
  let answer = "";
  for (let index = 0; index < length; index++)
    answer += source[context.randomInt(0, source.length - 1)];
  return {
    type,
    presentation: "visual",
    prompt: type === "number" ? "Enter the numbers shown" : "Enter the characters shown",
    answer,
    answerKind: "text",
    image: renderTextChallenge(answer, context),
    inputMode: type === "number" ? "numeric" : "text",
    audioSequence: [...answer.toLowerCase()],
    metadata: { length, excludedAmbiguousCharacters: true, imageStyle: context.imageStyle },
  };
}

export class TextCaptchaGenerator implements CaptchaChallengeGenerator {
  readonly type: "number" | "alpha" | "alphanumeric";

  constructor(type: "number" | "alpha" | "alphanumeric") {
    this.type = type;
  }

  generate(context: CaptchaGeneratorContext): GeneratedCaptchaChallenge {
    return generateText(this.type, context);
  }
}

export const numberCaptchaGenerator = new TextCaptchaGenerator("number");
export const alphaCaptchaGenerator = new TextCaptchaGenerator("alpha");
export const alphanumericCaptchaGenerator = new TextCaptchaGenerator("alphanumeric");
