"use client";

import { useState } from "react";
import { useSession } from "next-auth/react";
import { useTranslations, useLocale } from "next-intl";
import { Card } from "@/components/ui/card";

interface Props {
  initial: {
    firstName: string;
    lastName: string;
    email: string;
    /** Current ZITADEL preferredLanguage; "" if never set. */
    language: string;
  };
  /**
   * Personal-account flag. Drives a small hint about how the ZITADEL
   * name relates (or doesn't) to invoice identity — see the page
   * server component for the long explanation.
   */
  isPersonal: boolean;
  /**
   * For company accounts: the display org name. Shown in a small
   * read-only "Member of <org>" hint so the user understands which
   * identity they're editing. Ignored for personals (orgName is an
   * opaque "personal-XXXX" string in that case).
   */
  orgName: string;
}

/**
 * Edits first/last name in ZITADEL via PUT /api/settings/profile.
 * Email is shown read-only — changing email requires verification
 * flow that ZITADEL's own self-service UI handles.
 *
 * On save, we trigger NextAuth's `update()` from useSession() with
 * the new display name. That routes through our jwt callback
 * (trigger='update' branch) which overlays token.name without a
 * logout/login. After the cookie is updated we trigger a full page
 * reload — every server-rendered surface (nav-shell, dashboard
 * welcome, instance cards) re-reads the cookie on the next request
 * and renders with the new name. router.refresh() alone wasn't
 * enough: it re-runs only the current route's server components,
 * leaving outer-tree segments stale until the user navigates.
 */
export function ProfileSettingsForm({ initial, isPersonal, orgName }: Props) {
  const t = useTranslations("settingsProfile");
  const locale = useLocale();
  const { update } = useSession();
  const [form, setForm] = useState({
    firstName: initial.firstName,
    lastName: initial.lastName,
    // Fall back to the current UI locale when the profile has no stored
    // preference yet (older accounts), so the selector shows something
    // sensible rather than blank.
    language: initial.language || locale,
  });
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [savedFlash, setSavedFlash] = useState(false);

  const submit = async () => {
    setError(null);
    setSavedFlash(false);
    if (!form.firstName.trim() || !form.lastName.trim()) {
      setError(t("missingRequired"));
      return;
    }
    setBusy(true);
    try {
      const res = await fetch("/api/settings/profile", {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          firstName: form.firstName.trim(),
          lastName: form.lastName.trim(),
          language: form.language,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        throw new Error(data.error ?? `HTTP ${res.status}`);
      }
      // Phase 6 fix5: push the new display name into the session
      // token. The jwt callback handles trigger='update' and overlays
      // token.name; the next session callback maps token.name back
      // to session.user.name. No re-login needed.
      await update({ name: data.displayName });
      setSavedFlash(true);
      // If the language changed, land the user on the new locale (a
      // full navigation so every server-rendered surface re-renders in
      // the new language). Otherwise just reload so the new name
      // propagates. The 800ms delay lets the "Saved" flash show first.
      const localeChanged = form.language && form.language !== locale;
      const target = localeChanged ? localePath(form.language) : null;
      setTimeout(() => {
        if (target) window.location.assign(target);
        else window.location.reload();
      }, 800);
    } catch (e: any) {
      setError(e?.message ?? String(e));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Card>
      <div className="space-y-4">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <Field label={t("firstNameLabel")} required>
            <input
              type="text"
              value={form.firstName}
              onChange={(e) =>
                setForm((f) => ({ ...f, firstName: e.target.value }))
              }
              maxLength={100}
              className="w-full px-3 py-2 rounded-md bg-surface-2 border border-border focus:border-accent focus:outline-none text-sm"
            />
          </Field>
          <Field label={t("lastNameLabel")} required>
            <input
              type="text"
              value={form.lastName}
              onChange={(e) =>
                setForm((f) => ({ ...f, lastName: e.target.value }))
              }
              maxLength={100}
              className="w-full px-3 py-2 rounded-md bg-surface-2 border border-border focus:border-accent focus:outline-none text-sm"
            />
          </Field>
        </div>
        <Field label={t("emailLabel")} hint={t("emailReadOnlyHint")}>
          <input
            type="email"
            value={initial.email}
            readOnly
            disabled
            className="w-full px-3 py-2 rounded-md bg-surface-2 border border-border text-sm text-text-muted cursor-not-allowed"
          />
        </Field>
        <Field label={t("languageLabel")} hint={t("languageHint")}>
          <select
            value={form.language}
            onChange={(e) =>
              setForm((f) => ({ ...f, language: e.target.value }))
            }
            className="w-full px-3 py-2 rounded-md bg-surface-2 border border-border focus:border-accent focus:outline-none text-sm"
          >
            <option value="de">Deutsch</option>
            <option value="en">English</option>
            <option value="fr">Français</option>
            <option value="it">Italiano</option>
          </select>
        </Field>
        {/* Personal vs company hint. Personals get the
            "this won't change your invoice name" warning since their
            ZITADEL name and their invoice identity are intentionally
            decoupled. Company accounts get a benign "member of"
            context line so they know which org's identity they're
            editing. */}
        {isPersonal ? (
          <p className="text-xs text-text-muted italic">
            {t("personalAccountHint")}
          </p>
        ) : (
          <p className="text-xs text-text-muted italic">
            {t("companyAccountHint", { orgName })}
          </p>
        )}
        {error && <p className="text-sm text-error">{error}</p>}
        {savedFlash && <p className="text-sm text-success">{t("saved")}</p>}
        <div className="flex justify-end">
          <button
            onClick={submit}
            disabled={busy}
            className="px-4 py-2 rounded-md bg-accent text-surface-0 text-sm font-medium hover:bg-accent-dim transition-colors disabled:opacity-50 cursor-pointer"
          >
            {busy ? t("saving") : t("saveChanges")}
          </button>
        </div>
      </div>
    </Card>
  );
}

// Build the as-needed-prefixed path for a target locale from the
// current URL (default locale `de` is unprefixed). Client-only — uses
// window; called from the save handler.
function localePath(lang: string): string {
  const p =
    window.location.pathname.replace(/^\/(de|fr|it|en)(?=\/|$)/, "") || "/";
  return lang === "de" ? p : `/${lang}${p === "/" ? "" : p}`;
}

function Field({
  label,
  required,
  hint,
  children,
}: {
  label: string;
  required?: boolean;
  hint?: string;
  children: React.ReactNode;
}) {
  return (
    <div>
      <label className="block text-xs uppercase tracking-wider text-text-muted mb-1">
        {label}
        {required && <span className="text-error ml-1">*</span>}
      </label>
      {children}
      {hint && <p className="text-xs text-text-muted mt-1 italic">{hint}</p>}
    </div>
  );
}
