/**
 * Server-side human / bot checks for registration APIs.
 * Complements OTP: rejects honeypots, zero-interaction scripts, and robotic scroll.
 */

export type HumanSignals = {
  /** Honeypot — must be empty (bots often autofill hidden fields) */
  website?: string;
  /** Client timestamp when wizard mounted (ms) */
  started_at?: number;
  pointer_moves?: number;
  scrolls?: number;
  keys?: number;
  touches?: number;
  focuses?: number;
  /** Scroll events with near-identical intervals (scripted scroll heuristic) */
  scroll_robotic?: number;
};

export type HumanCheckResult =
  | { ok: true; score: number }
  | { ok: false; reason: string; score: number };

const MIN_DWELL_MS = 1800;

export function evaluateHuman(raw: unknown): HumanCheckResult {
  const s = (raw && typeof raw === "object" ? raw : {}) as HumanSignals;

  if (typeof s.website === "string" && s.website.trim().length > 0) {
    return { ok: false, reason: "honeypot", score: 0 };
  }

  const started = Number(s.started_at || 0);
  const dwell = started > 0 ? Date.now() - started : 0;
  if (!started || dwell < MIN_DWELL_MS) {
    return { ok: false, reason: "too_fast", score: 0 };
  }

  const pointer = Math.max(0, Number(s.pointer_moves) || 0);
  const scrolls = Math.max(0, Number(s.scrolls) || 0);
  const keys = Math.max(0, Number(s.keys) || 0);
  const touches = Math.max(0, Number(s.touches) || 0);
  const focuses = Math.max(0, Number(s.focuses) || 0);
  const robotic = Math.max(0, Number(s.scroll_robotic) || 0);

  const interactions = pointer + keys + touches + focuses;
  const score =
    Math.min(pointer, 40) +
    Math.min(keys, 20) +
    Math.min(touches, 20) +
    Math.min(focuses, 10) +
    Math.min(scrolls, 15) -
    Math.min(robotic * 5, 40);

  // Scripted scroll: many scrolls, little/no pointer or touch, robotic intervals
  if (scrolls >= 8 && pointer + touches === 0 && robotic >= 3) {
    return { ok: false, reason: "scripted_scroll", score };
  }
  if (scrolls >= 20 && interactions === 0) {
    return { ok: false, reason: "scroll_only_bot", score };
  }

  // Require some real interaction (or longer dwell with at least one focus/key)
  if (interactions === 0 && scrolls === 0) {
    return { ok: false, reason: "no_interaction", score };
  }
  if (interactions === 0 && dwell < 12_000) {
    return { ok: false, reason: "insufficient_interaction", score };
  }

  if (score < 2) {
    return { ok: false, reason: "low_score", score };
  }

  return { ok: true, score };
}

export function humanRejectResponse(reason: string) {
  return {
    ok: false as const,
    error:
      "We could not verify this session as a normal visitor. Please reload the page and try again without automated tools.",
    code: "human_check_failed",
    reason,
  };
}
