"use client";

import { useId, useState } from "react";
import Icon from "@/components/ui/Icon";
import { ApiError } from "@/lib/api/client";

export type FieldErrors = Record<string, string[]>;

/** Splits an API failure into per-field messages (422) and one message for everything else. */
export function readError(err: unknown): { fields: FieldErrors; message: string | null } {
  if (err instanceof ApiError) {
    const fields = err.errors && err.status === 422 ? err.errors : {};
    return { fields, message: Object.keys(fields).length ? null : err.message };
  }
  return { fields: {}, message: "Something went wrong. Please try again." };
}

/** Page frame for the account screens: title, one-line lead, then a white card holding the form. */
export function AuthCard({ title, lead, children, aside }: { title: string; lead?: React.ReactNode; children: React.ReactNode; aside?: React.ReactNode }) {
  return (
    <section className="wrap acct">
      <div className="acct-card">
        <h1 className="acct-title">{title}</h1>
        {lead && <p className="acct-lead">{lead}</p>}
        {children}
      </div>
      {aside && <div className="acct-aside">{aside}</div>}
    </section>
  );
}

type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "value"> & {
  label: string;
  value: string;
  onChange: (v: string) => void;
  error?: string[];
  hint?: string;
};

/** Label above, input, then a hint or the first error. Errors are tied to the input for screen readers. */
export function Field({ label, value, onChange, error, hint, ...rest }: InputProps) {
  const id = useId();
  const note = error?.[0] ?? hint;
  return (
    <div className="acct-field">
      <label htmlFor={id} className="lf-label">
        {label}
      </label>
      <input
        id={id}
        className="lf-input"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        aria-invalid={error ? true : undefined}
        aria-describedby={note ? `${id}-n` : undefined}
        {...rest}
      />
      {note && (
        <small id={`${id}-n`} className={error ? "iv-err" : "acct-hint"}>
          {note}
        </small>
      )}
    </div>
  );
}

/** Password input with a show/hide toggle. */
export function PasswordField(props: Omit<InputProps, "type">) {
  const [show, setShow] = useState(false);
  return (
    <div className="acct-pw">
      <Field {...props} type={show ? "text" : "password"} />
      <button type="button" className="acct-eye" onClick={() => setShow((s) => !s)} aria-label={show ? "Hide password" : "Show password"} aria-pressed={show}>
        <Icon name={show ? "visibility_off" : "visibility"} />
      </button>
    </div>
  );
}

/** Six-digit code from the email. Digits only; phones offer the code from the message. */
export function CodeField(props: Omit<InputProps, "type" | "onChange"> & { onChange: (v: string) => void }) {
  return (
    <Field
      {...props}
      onChange={(v) => props.onChange(v.replace(/\D/g, "").slice(0, 6))}
      inputMode="numeric"
      autoComplete="one-time-code"
      pattern="\d{6}"
      maxLength={6}
      className="lf-input acct-code"
    />
  );
}

export function FormAlert({ children, tone = "error" }: { children: React.ReactNode; tone?: "error" | "ok" }) {
  return (
    <p className={`acct-alert acct-alert-${tone}`} role={tone === "error" ? "alert" : "status"}>
      <Icon name={tone === "error" ? "error" : "check_circle"} />
      <span>{children}</span>
    </p>
  );
}

export function Submit({ busy, children }: { busy: boolean; children: React.ReactNode }) {
  return (
    <button type="submit" className="btn btn-rose acct-submit" disabled={busy} aria-busy={busy}>
      {busy ? "Please wait" : children}
    </button>
  );
}
