"use client";

import { useState } from "react";
import { Controller } from "react-hook-form";
import { AlertCircle, ArrowUpRight, Check, Circle, Eye, EyeOff, FlaskConical, LockKeyhole } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "@/components/ui/input-group";
import { cn } from "@/lib/utils";
import { PASSWORD_RULES, passwordStrength } from "./password-rules";

/** Title block of an auth screen: optional status icon, one heading, one sentence. */
export function AuthHeading({ icon: Icon, tone = "neutral", title, children }) {
  const tones = { neutral: "bg-muted text-foreground", success: "bg-success/10 text-success", danger: "bg-destructive/10 text-destructive", info: "bg-info/10 text-info" };
  return <div className="mb-8 grid gap-3">
    {Icon && <span className={cn("flex size-11 items-center justify-center rounded-xl", tones[tone])}><Icon className="size-5" aria-hidden="true" /></span>}
    <div className="grid gap-2">
      <h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
      {children && <p className="text-sm text-muted-foreground">{children}</p>}
    </div>
  </div>;
}

/** Root (server) error of a form as an alert; `action` adds a link or button under the message. */
export function AuthError({ message, action }) {
  if (!message) return null;
  return <Alert variant="destructive"><AlertCircle /><AlertDescription>{message}{action}</AlertDescription></Alert>;
}

/** Text input with a leading icon, used by every auth form. */
export function IconField({ control, name, id, label, icon: Icon, type = "text", placeholder, autoComplete, description, onType, inputProps }) {
  return <Controller control={control} name={name} render={({ field, fieldState }) => <Field data-invalid={fieldState.invalid}>
    <FieldLabel htmlFor={id}>{label}</FieldLabel>
    <InputGroup className="h-10">
      <InputGroupAddon><Icon /></InputGroupAddon>
      <InputGroupInput id={id} type={type} autoComplete={autoComplete} placeholder={placeholder} aria-invalid={fieldState.invalid} {...field} value={field.value ?? ""} {...inputProps} onChange={(event) => { field.onChange(event); onType?.(); }} />
    </InputGroup>
    {fieldState.error ? <FieldError>{fieldState.error.message}</FieldError> : description && <FieldDescription>{description}</FieldDescription>}
  </Field>} />;
}

/**
 * Password input with show/hide and a Caps Lock warning. `labelAction` sits beside the label ("Forgot password?");
 * `rules` adds the live policy checklist and strength hint for a new password.
 */
export function PasswordField({ control, name, id, label = "Password", placeholder, autoComplete = "current-password", description, labelAction, rules = false, onType, className }) {
  const [visible, setVisible] = useState(false);
  const [capsLock, setCapsLock] = useState(false);
  const readCaps = (event) => setCapsLock(Boolean(event.getModifierState?.("CapsLock")));

  return <Controller control={control} name={name} render={({ field, fieldState }) => <Field data-invalid={fieldState.invalid} className={className}>
    <div className="flex items-center justify-between gap-3">
      <FieldLabel htmlFor={id}>{label}</FieldLabel>
      {labelAction}
    </div>
    <InputGroup className="h-10">
      <InputGroupAddon><LockKeyhole /></InputGroupAddon>
      <InputGroupInput id={id} type={visible ? "text" : "password"} autoComplete={autoComplete} placeholder={placeholder} aria-invalid={fieldState.invalid} aria-describedby={rules ? `${id}-rules` : undefined}
        {...field} value={field.value ?? ""} onChange={(event) => { field.onChange(event); onType?.(); }} onKeyUp={readCaps} onKeyDown={readCaps} onBlur={() => { field.onBlur(); setCapsLock(false); }} />
      <InputGroupAddon align="inline-end">
        <InputGroupButton size="icon-xs" aria-label={visible ? "Hide password" : "Show password"} aria-pressed={visible} onClick={() => setVisible((value) => !value)}>{visible ? <EyeOff /> : <Eye />}</InputGroupButton>
      </InputGroupAddon>
    </InputGroup>
    {capsLock && <p className="text-xs font-medium text-warning" role="status">Caps Lock is on.</p>}
    {fieldState.error ? <FieldError>{fieldState.error.message}</FieldError> : description && <FieldDescription>{description}</FieldDescription>}
    {rules && <PasswordRules id={`${id}-rules`} value={field.value || ""} />}
  </Field>} />;
}

// Live checklist of the password policy plus a four-step strength meter (text label included, never colour alone).
export function PasswordRules({ id, value }) {
  const { score, label } = passwordStrength(value);
  const barTone = score >= 4 ? "bg-success" : score === 3 ? "bg-info" : score === 2 ? "bg-warning" : "bg-destructive";

  return <div id={id} className="grid gap-2.5 rounded-lg border bg-muted/40 p-3">
    <div className="flex items-center gap-3">
      <div className="grid flex-1 grid-cols-4 gap-1" aria-hidden="true">
        {[1, 2, 3, 4].map((step) => <span key={step} className={cn("h-1 rounded-full", step <= score ? barTone : "bg-border")} />)}
      </div>
      <span className="min-w-0 text-xs text-muted-foreground" aria-live="polite">{label || "Password strength"}</span>
    </div>
    <ul className="flex flex-wrap gap-x-4 gap-y-1">
      {PASSWORD_RULES.map((rule) => {
        const met = rule.test(value);
        return <li key={rule.key} className={cn("flex items-center gap-1.5 whitespace-nowrap text-xs", met ? "text-success" : "text-muted-foreground")}>
          {met ? <Check className="size-3.5 shrink-0" aria-hidden="true" /> : <Circle className="size-3.5 shrink-0" aria-hidden="true" />}
          <span>{rule.label}<span className="sr-only">{met ? " (met)" : " (not met yet)"}</span></span>
        </li>;
      })}
    </ul>
  </div>;
}

/**
 * Local development only: the API returns `devMailPreviewUrl` when APP_ENV=local (mail goes to the log file there),
 * so the emailed link can be opened without an SMTP server. Renders nothing in production, where it is never sent.
 */
export function DevMailLink({ url, className }) {
  if (!url) return null;
  return <Alert className={cn("border-dashed", className)}>
    <FlaskConical />
    <AlertTitle>Development only</AlertTitle>
    <AlertDescription>
      <span>Emails are written to the log on this machine. Open the link from the email here:</span>
      <Button variant="link" size="sm" className="h-auto justify-start p-0" asChild><a href={url}>Open the email link <ArrowUpRight /></a></Button>
    </AlertDescription>
  </Alert>;
}
