import type { AuthRiskDecision, AuthRiskSignals, AuthRiskLevel } from "./types.ts";

export interface RiskPolicy {
  captchaThreshold: number;
  mfaThreshold: number;
  blockThreshold: number;
}

function finiteScore(value: unknown, fallback = 0): number {
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}

function threshold(value: number, fallback: number): number {
  return Math.min(100, Math.max(0, finiteScore(value, fallback)));
}

function level(score: number): AuthRiskLevel {
  if (score >= 90) return "critical";
  if (score >= 65) return "high";
  if (score >= 35) return "medium";
  return "low";
}

export function evaluateAuthRisk(
  signals: AuthRiskSignals = {},
  policy: RiskPolicy = { captchaThreshold: 35, mfaThreshold: 60, blockThreshold: 90 },
): AuthRiskDecision {
  let score = Math.max(0, finiteScore(signals.customScore));
  const reasons: string[] = [];
  const add = (condition: boolean | undefined, points: number, reason: string) => {
    if (!condition) return;
    score += points;
    reasons.push(reason);
  };
  const failedAttempts = Math.max(0, Math.floor(finiteScore(signals.failedAttempts)));
  if (failedAttempts > 0) {
    score += Math.min(45, failedAttempts * 10);
    reasons.push("failed-attempts");
  }
  add(signals.unfamiliarDevice, 18, "unfamiliar-device");
  add(signals.unusualIp, 20, "unusual-ip");
  add(signals.impossibleTravel, 35, "impossible-travel");
  add(signals.breachedPassword, 45, "breached-password");
  add(signals.automationSuspected, 40, "automation-suspected");
  add(signals.accountLocked, 100, "account-locked");
  score = Math.min(100, Math.max(0, score));

  const captchaThreshold = threshold(policy.captchaThreshold, 35);
  const mfaThreshold = threshold(policy.mfaThreshold, 60);
  const blockThreshold = threshold(policy.blockThreshold, 90);

  return {
    score,
    level: level(score),
    requireCaptcha: score >= captchaThreshold,
    requireMfa: score >= mfaThreshold,
    block: score >= blockThreshold,
    reasons,
  };
}
