"use client";

/**
 * MobileWaterPinScreen — PIN entry screen.
 *
 * Visual structure (Apple HIG):
 *   - Minimal nav bar with "TUXEDO WATER LOG" branding (system
 *     small-caps via tracking).
 *   - Centered droplet + lock icon pair as a brand anchor.
 *   - Headline ("Enter PIN") + supporting caption.
 *   - Four large digit boxes (64pt square) that mirror the value of
 *     a hidden <input>. Tapping the row focuses the hidden input —
 *     the native numeric keyboard rises from the bottom.
 *   - Full-width primary "Unlock" button (HIG success blue).
 *   - Inline error pill replaces the caption on failure, with a
 *     gentle shake.
 *
 * The hidden input is the source of truth so iOS's QuickType /
 * password-manager suggestions work correctly — we never rebuild
 * the digit boxes from a synthetic onChange.
 */
import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type FormEvent,
} from "react";
import { Droplet, Lock, Spinner } from "./icons";
import { useLang } from "@/lib/water-log/lang-context";

type Props = {
  /** Called when the user submits a 4-8 digit PIN. */
  onSubmit: (pin: string) => Promise<void>;
  /** PIN length, matches `PIN_MIN`/`PIN_MAX` from water-log-pin. */
  length?: 4 | 5 | 6 | 7 | 8;
};

export function MobileWaterPinScreen({ onSubmit, length = 4 }: Props) {
  const { t } = useLang();
  const [pin, setPin] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [submitting, setSubmitting] = useState(false);
  const [shake, setShake] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  // Auto-focus the hidden input when the screen mounts so the
  // keyboard rises immediately. iOS sometimes needs a tiny delay
  // for the focus to take after the page transition.
  useEffect(() => {
    const t = window.setTimeout(() => inputRef.current?.focus(), 80);
    return () => window.clearTimeout(t);
  }, []);

  const handleChange = useCallback(
    (e: React.ChangeEvent<HTMLInputElement>) => {
      // Strip non-digits, clamp to `length`.
      const next = e.target.value.replace(/\D/g, "").slice(0, length);
      setPin(next);
      if (error) setError(null);
    },
    [error, length],
  );

  const submit = useCallback(
    async (e?: FormEvent) => {
      e?.preventDefault();
      if (pin.length !== length || submitting) return;
      setSubmitting(true);
      setError(null);
      try {
        await onSubmit(pin);
        // Don't reset here — the parent will navigate away.
      } catch (err) {
        // Network / unexpected error
        setError(
          err instanceof Error ? err.message : t.pin.genericError,
        );
        setShake(true);
        window.setTimeout(() => setShake(false), 420);
        setPin("");
      } finally {
        setSubmitting(false);
      }
    },
    [pin, length, submitting, onSubmit, t.pin.genericError],
  );

  const onFailureShake = useCallback(() => {
    setShake(true);
    window.setTimeout(() => setShake(false), 420);
    setPin("");
    inputRef.current?.focus();
  }, []);

  // Expose the shake trigger via a custom event so the parent can
  // fire it after a failed verify (parent owns the verify call).
  useEffect(() => {
    function onShake() {
      onFailureShake();
    }
    window.addEventListener("water-pin-shake", onShake);
    return () => window.removeEventListener("water-pin-shake", onShake);
  }, [onFailureShake]);

  return (
    <div className="flex h-full flex-col bg-[#F2F2F7]">
      {/* ── Branded header ───────────────────────────────────────── */}
      <header
        className="px-5 pb-3 pt-[max(env(safe-area-inset-top),1rem)]"
        style={{
          background:
            "linear-gradient(180deg, rgba(255,255,255,0.92) 0%, rgba(242,242,247,0) 100%)",
          backdropFilter: "blur(10px)",
          WebkitBackdropFilter: "blur(10px)",
        }}
      >
        <div className="mx-auto flex max-w-md items-center justify-center gap-2">
          <Droplet size={18} className="text-[#14532d]" />
          <span
            className="text-[12px] font-bold tracking-[0.22em] text-[#14532d]"
            style={{
              fontFamily:
                "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
            }}
          >
            {t.brand.waterLog}
          </span>
        </div>
      </header>

      {/* ── Centered content ─────────────────────────────────────── */}
      <main className="flex flex-1 flex-col items-center justify-center px-6 pb-[max(env(safe-area-inset-bottom),1.25rem)]">
        <div className="w-full max-w-sm">
          {/* Brand mark */}
          <div className="mb-7 flex justify-center">
            <div
              className="flex h-20 w-20 items-center justify-center rounded-[22px]"
              style={{
                background:
                  "linear-gradient(160deg, #ffffff 0%, #f0f7f2 60%, #e1efe5 100%)",
                boxShadow:
                  "0 1px 0 rgba(255,255,255,0.9) inset, 0 6px 16px rgba(20,83,45,0.18), 0 1px 3px rgba(0,0,0,0.06)",
              }}
            >
              <Lock size={32} className="text-[#14532d]" />
            </div>
          </div>

          <h1
            className="mb-2 text-center text-[28px] font-bold leading-[1.15] tracking-tight text-[#1d1d1f]"
            style={{
              fontFamily:
                "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
            }}
          >
            {t.pin.title}
          </h1>

          {/* Caption OR inline error */}
          <p
            className={[
              "mb-9 min-h-[20px] text-center text-[15px]",
              error ? "text-[#FF3B30]" : "text-[rgba(60,60,67,0.6)]",
            ].join(" ")}
            role={error ? "alert" : undefined}
            aria-live={error ? "assertive" : undefined}
          >
            {error ?? t.pin.caption}
          </p>

          {/* ── Digit boxes ────────────────────────────────────── */}
          {/* The hidden input is the source of truth and gives us
            *  native iOS numeric keyboard + autofill. The visible
            *  boxes mirror its value. */}
          <form onSubmit={submit}>
            <input
              ref={inputRef}
              type="password"
              inputMode="numeric"
              pattern="[0-9]*"
              autoComplete="one-time-code"
              maxLength={length}
              value={pin}
              onChange={handleChange}
              // Keep the hidden input in the layout flow so its
              // keyboard rises correctly. Visually hidden via the
              // standard "sr-only" technique.
              className="sr-only"
              aria-label={t.pin.a11yPin}
              disabled={submitting}
            />
            <button
              type="button"
              onClick={() => inputRef.current?.focus()}
              aria-label={t.pin.a11yPinEntry}
              className="mx-auto mb-8 flex w-full justify-center gap-3 outline-none"
            >
              {Array.from({ length }).map((_, i) => {
                const filled = i < pin.length;
                const active = i === pin.length;
                return (
                  <div
                    key={i}
                    className="relative flex h-[68px] w-[58px] items-center justify-center rounded-[14px] bg-white text-[34px] font-bold leading-none text-[#1d1d1f]"
                    style={{
                      boxShadow: active
                        ? "0 0 0 2px #14532d, 0 1px 2px rgba(0,0,0,0.04), 0 4px 14px rgba(20,83,45,0.18)"
                        : "0 0 0 1px rgba(60,60,67,0.18), 0 1px 2px rgba(0,0,0,0.04)",
                      transition: "box-shadow 180ms cubic-bezier(0.32,0.72,0,1)",
                    }}
                  >
                    {filled ? (
                      <span className="relative">
                        {/* Solid dot — never reveals the digit back */}
                        <span
                          aria-hidden
                          className="block h-[14px] w-[14px] rounded-full bg-[#1d1d1f]"
                        />
                      </span>
                    ) : null}
                    {/* Caret blink on the active box (iOS-style). */}
                    {active && !filled && (
                      <span
                        aria-hidden
                        className="block h-[28px] w-[2px] rounded-full bg-[#14532d]"
                        style={{
                          animation: "water-blink 1.05s steps(2, start) infinite",
                        }}
                      />
                    )}
                  </div>
                );
              })}
            </button>

            {/* Hidden submit so Enter from the keyboard triggers Unlock */}
            <button type="submit" className="sr-only" tabIndex={-1}>
              {t.pin.unlock}
            </button>
          </form>

          {/* ── Unlock button ─────────────────────────────────── */}
          <button
            type="button"
            onClick={() => submit()}
            disabled={pin.length !== length || submitting}
            className={[
              "flex h-[58px] w-full items-center justify-center gap-2 rounded-[14px] text-[17px] font-semibold",
              "transition-[transform,background-color,opacity] duration-200",
              "active:scale-[0.985]",
              pin.length === length && !submitting
                ? "bg-[#14532d] text-white shadow-[0_6px_18px_rgba(20,83,45,0.28),inset_0_1px_0_rgba(255,255,255,0.16)]"
                : "bg-[rgba(120,120,128,0.16)] text-[rgba(60,60,67,0.4)]",
            ].join(" ")}
            style={{
              // Pressable feedback — springy scale.
              transform: shake ? "translateX(0)" : undefined,
            }}
          >
            {submitting ? (
              <>
                <Spinner
                  size={20}
                  className="text-white"
                  style={{ animation: "spin 0.8s linear infinite" }}
                />
                {t.pin.verifying}
              </>
            ) : (
              <>{t.pin.unlock}</>
            )}
          </button>

          {/* Footer hint */}
          <p className="mt-7 text-center text-[12px] text-[rgba(60,60,67,0.45)]">
            {t.pin.forgot}
          </p>
        </div>
      </main>

      {/* Apply the shake via inline animation when `shake` is true.
        *  The `water-shake` keyframe lives in `src/app/globals.css`
        *  alongside the rest of the Water Log animation set. */}
      {shake && (
        <div
          aria-hidden
          className="pointer-events-none fixed inset-x-0 top-1/2 z-50 mx-auto max-w-sm"
          style={{
            animation: "water-shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97)",
          }}
        />
      )}
    </div>
  );
}

export default MobileWaterPinScreen;