// src/components/account/username-prompt-dialog.tsx
"use client";

import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import {
  isValidUsername,
  MAX_USERNAME_LENGTH,
  MIN_USERNAME_LENGTH,
} from "@/lib/auth/username-policy";
import { authClient } from "@/lib/auth-client";

/**
 * Post-login "choose a username" prompt. Mounted by the (app) layout ONLY when
 * the signed-in user has no username (null/empty) — typically magic-link sign-ups
 * or legacy accounts, since email/password signup makes username required. The
 * server evaluates that condition, so this component just auto-opens on mount.
 *
 * Dismiss behaviour: deliberately NOT dismissable. Username is an identity
 * prerequisite (the product intent is that everyone has one), so the dialog has
 * no X / overlay-click / Esc escape — Radix `onEscapeKeyDown` and
 * `onInteractOutside` are prevented and `showCloseButton` is false. The ONLY way
 * out is to set a valid username, which closes it then `router.refresh()` re-runs
 * the layout (the condition flips false and this unmounts). This is NOT a hard
 * trap: if `updateUser` errors the dialog stays open with the error shown and the
 * user can retry. No signOut needed.
 */
export function UsernamePromptDialog() {
  const t = useTranslations("UsernamePrompt");
  const router = useRouter();
  const [open, setOpen] = useState(true);
  const [username, setUsername] = useState("");
  // Mirrors the signup / account-settings debounced availability flow.
  const [status, setStatus] = useState<
    "idle" | "invalid" | "checking" | "available" | "taken"
  >("idle");
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handle = username.trim();

  // Same debounced availability check as signup: validate the format locally
  // first (the rule the server enforces via usernameValidator), then only hit
  // isUsernameAvailable for well-formed, non-empty handles.
  useEffect(() => {
    if (!handle) {
      setStatus("idle");
      return;
    }
    if (
      handle.length < MIN_USERNAME_LENGTH ||
      handle.length > MAX_USERNAME_LENGTH ||
      !isValidUsername(handle)
    ) {
      setStatus("invalid");
      return;
    }
    setStatus("checking");
    const id = setTimeout(async () => {
      const res = await authClient.isUsernameAvailable({ username: handle });
      setStatus(res.data?.available ? "available" : "taken");
    }, 400);
    return () => clearTimeout(id);
  }, [handle]);

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    if (status !== "available") return;
    setError(null);
    setPending(true);
    // Pass the raw handle: the server lowercases `username` and keeps the
    // original casing as `displayUsername`.
    const res = await authClient.updateUser({ username: handle });
    setPending(false);
    if (res.error) {
      setError(res.error.message ?? t("error"));
      return;
    }
    // Close immediately for instant feedback, then refresh so the server layout
    // re-evaluates (username is now set → this component unmounts).
    setOpen(false);
    router.refresh();
  }

  return (
    <Dialog open={open}>
      <DialogContent
        showCloseButton={false}
        onEscapeKeyDown={(e) => e.preventDefault()}
        onInteractOutside={(e) => e.preventDefault()}
      >
        <DialogHeader>
          <DialogTitle>{t("title")}</DialogTitle>
          <DialogDescription>{t("description")}</DialogDescription>
        </DialogHeader>
        <form onSubmit={submit}>
          <FieldGroup>
            <Field>
              <FieldLabel htmlFor="prompt-username">{t("label")}</FieldLabel>
              <Input
                id="prompt-username"
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                autoComplete="username"
                placeholder={t("placeholder")}
                autoFocus
                aria-invalid={
                  status === "invalid" || status === "taken" || undefined
                }
              />
              {status === "invalid" ? (
                <p className="text-destructive text-xs">{t("invalid")}</p>
              ) : status === "taken" ? (
                <p className="text-destructive text-xs">{t("taken")}</p>
              ) : status === "checking" ? (
                <p className="text-muted-foreground text-xs">{t("checking")}</p>
              ) : status === "available" ? (
                <p className="text-xs text-emerald-600 dark:text-emerald-400">
                  {t("available")}
                </p>
              ) : (
                <p className="text-muted-foreground text-xs">{t("hint")}</p>
              )}
            </Field>
          </FieldGroup>
          {error ? (
            <p className="mt-4 text-destructive text-sm" role="alert">
              {error}
            </p>
          ) : null}
          <div className="mt-6 flex justify-end">
            <Button type="submit" disabled={pending || status !== "available"}>
              {pending ? t("submitting") : t("submit")}
            </Button>
          </div>
        </form>
      </DialogContent>
    </Dialog>
  );
}
