/**
 * Neutral, non-enumerating response decisions for the auth API.
 *
 * Every decision here is pure so the anti-enumeration guarantees are
 * unit-testable without a database or any I/O. The routes translate these
 * decisions into HTTP responses; this module itself never imports server-only
 * code.
 *
 * The core rule: no credential-less auth endpoint may answer differently based
 * on whether an email address is registered. Either every outcome looks the
 * same, or the distinguishing branch requires a secret only the account owner
 * knows (e.g. the correct password).
 */

export type SignupAccountState = "new" | "unverified" | "verified" | "google_only";

export interface SignupDecision {
  /** The wire status — identical for every account state. */
  status: "verification_sent";
  /**
   * True when a fresh confirmation link should really be issued and mailed
   * (brand-new or never-confirmed accounts). False for already-verified and
   * Google-only accounts: no new mail is produced, but the response stays
   * byte-for-byte the same — `devLink` only ever appears in the development
   * fallback, and only when a mail was actually produced.
   */
  sendMail: boolean;
}

export function signupDecision(state: SignupAccountState): SignupDecision {
  return {
    status: "verification_sent",
    sendMail: state === "new" || state === "unverified",
  };
}

/**
 * The response body for the signup / resend endpoints. Identical for every
 * account state; only the development mail fallback can add a `devLink`, and
 * only when the decision actually produced a mail.
 */
export function signupResponseBody(
  decision: SignupDecision,
  devLink: string | null | undefined
): { status: "verification_sent"; devLink?: string } {
  if (decision.sendMail && devLink) {
    return { status: "verification_sent", devLink };
  }
  return { status: "verification_sent" };
}

export type LoginUserKind =
  /** No account exists for the address. */
  | "none"
  /** Verified account with a local password. */
  | "local"
  /** Account exists but only as a Google identity (no local password). */
  | "google_only"
  /** Local account whose address was never confirmed. */
  | "unverified_local";

export type LoginDecision =
  | { kind: "sign_in" }
  | { kind: "invalid_credentials" }
  | { kind: "email_not_verified" };

/**
 * Decides what login must answer for a given account state and password check.
 *
 * Google-only accounts are deliberately folded into `invalid_credentials`: a
 * dedicated "use Google" answer would let an attacker armed only with an email
 * address and any password tell which addresses are registered. A missing
 * account and a Google-only account therefore produce the exact same outcome.
 *
 * `email_not_verified` is only reachable when the password matched — the caller
 * already proved knowledge of the account secret — so keeping it distinct
 * cannot be used to enumerate addresses.
 */
export function loginDecision(kind: LoginUserKind, passwordMatches: boolean): LoginDecision {
  if (kind === "none" || kind === "google_only") return { kind: "invalid_credentials" };
  if (!passwordMatches) return { kind: "invalid_credentials" };
  if (kind === "unverified_local") return { kind: "email_not_verified" };
  return { kind: "sign_in" };
}

/**
 * Error codes that used to reveal account existence. They remain in the shared
 * vocabulary for compatibility (stale clients, old messages), but no auth route
 * may emit them anymore. The static test suite asserts that the route sources
 * never contain these literals.
 */
export const DISCONTINUED_ENUMERATION_CODES = [
  "email_taken",
  "email_taken_google",
  "use_google",
] as const;
