import { Stack, Text, Group } from '@mantine/core';
import { IconCheck, IconX } from '@tabler/icons-react';
import { z } from 'zod';

const DEFAULT_LABELS = (minLength: number) => [
  `At least ${minLength} characters`,
  'One lowercase letter',
  'One uppercase letter',
  'One number',
  'One special character',
];

/** `labels`, when given, overrides the default English text in the same
 *  order — the caller's translated strings, so this stays a plain function
 *  usable from a zod schema with no i18n context of its own. */
export function passwordRules(minLength: number, labels?: string[]) {
  const text = labels ?? DEFAULT_LABELS(minLength);
  return [
    { label: text[0], test: (p: string) => p.length >= minLength },
    { label: text[1], test: (p: string) => /[a-z]/.test(p) },
    { label: text[2], test: (p: string) => /[A-Z]/.test(p) },
    { label: text[3], test: (p: string) => /\d/.test(p) },
    { label: text[4], test: (p: string) => /[^A-Za-z0-9]/.test(p) },
  ];
}

/** Zod field schema enforcing every rule; unmet rules surface as separate issues. */
export const passwordSchema = (minLength: number, labels?: string[]) =>
  z.string().superRefine((val, ctx) => {
    for (const rule of passwordRules(minLength, labels)) {
      if (!rule.test(val)) {
        ctx.addIssue({ code: 'custom', message: rule.label });
      }
    }
  });

export const passwordMeetsAll = (password: string, minLength: number) =>
  passwordRules(minLength).every((rule) => rule.test(password));

interface PasswordRequirementsProps {
  password: string;
  minLength: number;
  labels?: string[];
}

/** Live checklist of password requirements, ticking off as the user types. Hidden until the user starts typing. */
export function PasswordRequirements({ password, minLength, labels }: PasswordRequirementsProps) {
  if (!password) return null;
  const rules = passwordRules(minLength, labels);
  return (
    <Stack gap={6} mt={6}>
      {rules.map((rule) => {
        const met = rule.test(password);
        return (
          <Group key={rule.label} gap={6} wrap="nowrap">
            {met ? (
              <IconCheck size={14} color="var(--mantine-color-teal-6)" />
            ) : (
              <IconX size={14} color="var(--mantine-color-gray-5)" />
            )}
            <Text fz="xs" c={met ? 'teal' : 'dimmed'}>
              {rule.label}
            </Text>
          </Group>
        );
      })}
    </Stack>
  );
}
