// Mirrors apps/backend/app/Rules/StrongPassword.php exactly — keep both in
// sync, including the special-character set (! @ # $ % ^ & * ( ) - _ + = ?).

export interface PasswordRequirement {
  id: string;
  label: string;
  message: string;
  test: (password: string) => boolean;
}

export interface PasswordRequirementResult extends PasswordRequirement {
  met: boolean;
}

const SPECIAL_CHARS_PATTERN = /[!@#$%^&*()\-_+=?]/;

export const PASSWORD_REQUIREMENTS: PasswordRequirement[] = [
  {
    id: "length",
    label: "Minimum 8 characters",
    message: "Password must be at least 8 characters long.",
    test: (password) => password.length >= 8,
  },
  {
    id: "uppercase",
    label: "One uppercase letter",
    message: "Password must contain at least one uppercase letter.",
    test: (password) => /[A-Z]/.test(password),
  },
  {
    id: "lowercase",
    label: "One lowercase letter",
    message: "Password must contain at least one lowercase letter.",
    test: (password) => /[a-z]/.test(password),
  },
  {
    id: "number",
    label: "One number",
    message: "Password must contain at least one number.",
    test: (password) => /[0-9]/.test(password),
  },
  {
    id: "special",
    label: "One special character",
    message: "Password must contain at least one special character (! @ # $ % ^ & * ( ) - _ + = ?).",
    test: (password) => SPECIAL_CHARS_PATTERN.test(password),
  },
];

export function validatePassword(password: string): PasswordRequirementResult[] {
  return PASSWORD_REQUIREMENTS.map((requirement) => ({ ...requirement, met: requirement.test(password) }));
}

export function isPasswordValid(password: string): boolean {
  return PASSWORD_REQUIREMENTS.every((requirement) => requirement.test(password));
}

export type PasswordStrengthLabel = "Very Weak" | "Weak" | "Fair" | "Good" | "Strong" | "Very Strong";

export interface PasswordStrengthResult {
  score: number; // 0-5
  label: PasswordStrengthLabel;
}

const STRENGTH_LABELS: PasswordStrengthLabel[] = ["Very Weak", "Weak", "Fair", "Good", "Strong", "Very Strong"];

/**
 * Heuristic score (0-5) from length tiers + character-class variety + a
 * rough entropy estimate (length * log2(charsetSize)) — not a substitute for
 * a real strength library, but needs no new dependency for this form.
 */
export function calculatePasswordStrength(password: string): PasswordStrengthResult {
  if (!password) return { score: 0, label: STRENGTH_LABELS[0] };

  const classes = [/[a-z]/, /[A-Z]/, /[0-9]/, SPECIAL_CHARS_PATTERN];
  const variety = classes.filter((re) => re.test(password)).length;

  let charsetSize = 0;
  if (/[a-z]/.test(password)) charsetSize += 26;
  if (/[A-Z]/.test(password)) charsetSize += 26;
  if (/[0-9]/.test(password)) charsetSize += 10;
  if (SPECIAL_CHARS_PATTERN.test(password)) charsetSize += 14;
  if (/[^A-Za-z0-9!@#$%^&*()\-_+=?]/.test(password)) charsetSize += 20; // other symbols typed outside the required set

  const entropy = password.length * Math.log2(Math.max(charsetSize, 1));

  let score = 0;
  if (password.length >= 8) score += 1;
  if (password.length >= 12) score += 1;
  if (variety >= 3) score += 1;
  if (variety >= 4) score += 1;
  if (entropy >= 60) score += 1;

  return { score, label: STRENGTH_LABELS[score] };
}
