"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { Check, LogOut, ShieldCheck } from "lucide-react";

import { Alert, Field, Input } from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { apiFetch, ApiRequestError } from "@/lib/client/api";
import { useSession, type PublicUser } from "@/components/layout/session-provider";

/**
 * Profile + password forms for `/settings`.
 *
 * Both are plain Client Components driven by `apiFetch`, which already attaches
 * the CSRF header. Nothing here writes to client storage.
 */

export function ProfileForm({ user }: { user: PublicUser }) {
  const router = useRouter();
  const { refresh } = useSession();

  const [displayName, setDisplayName] = useState(user.displayName);
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [saved, setSaved] = useState(false);
  const [syncedFrom, setSyncedFrom] = useState(user.displayName);

  // Adopt a re-rendered server snapshot (e.g. after `router.refresh()`) by
  // adjusting during render rather than in an effect, which would cascade.
  if (syncedFrom !== user.displayName) {
    setSyncedFrom(user.displayName);
    setDisplayName(user.displayName);
  }

  const save = async (event: React.FormEvent) => {
    event.preventDefault();
    if (pending) return;

    setPending(true);
    setError(null);
    setSaved(false);

    try {
      // Only `displayName` is mutable. The route answers with the settings
      // object, not the user, so pull the authoritative user from /api/auth/me.
      await apiFetch("/api/settings", {
        method: "PATCH",
        body: JSON.stringify({ displayName }),
      });
      await refresh();
      setSaved(true);
      router.refresh();
    } catch (err) {
      setError(
        err instanceof ApiRequestError ? err.message : "Could not save your profile.",
      );
    } finally {
      setPending(false);
    }
  };

  return (
    <form onSubmit={save} noValidate className="space-y-5">
      {error ? <Alert tone="error">{error}</Alert> : null}
      {saved ? <Alert tone="success">Profile updated.</Alert> : null}

      <Field label="Username" htmlFor="profile-username" hint="Your username cannot be changed.">
        <Input
          id="profile-username"
          value={user.username}
          readOnly
          disabled
          className="opacity-60"
          autoComplete="username"
        />
      </Field>

      <Field label="Display name" htmlFor="profile-display-name">
        <Input
          id="profile-display-name"
          value={displayName}
          onChange={(e) => setDisplayName(e.target.value)}
          maxLength={80}
          required
          autoComplete="nickname"
        />
      </Field>

      <Field
        label="Email"
        htmlFor="profile-email"
        hint="Contact support to change the address on a verified account."
      >
        <Input
          id="profile-email"
          type="email"
          value={user.email}
          readOnly
          disabled
          className="opacity-60"
          autoComplete="email"
        />
      </Field>

      <Button type="submit" loading={pending}>
        Save changes
      </Button>
    </form>
  );
}

export function PasswordForm() {
  const router = useRouter();
  const { signOut, refresh } = useSession();

  const [currentPassword, setCurrentPassword] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");
  const [pending, setPending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [done, setDone] = useState(false);
  const [mismatch, setMismatch] = useState(false);

  const save = async (event: React.FormEvent) => {
    event.preventDefault();
    if (pending) return;

    if (password !== confirmPassword) {
      setMismatch(true);
      return;
    }
    setMismatch(false);
    setPending(true);
    setError(null);
    setDone(false);

    try {
      // POST, and `newPassword` — the route rotates this session server-side and
      // hands back a fresh cookie pair, so the visitor stays signed in.
      await apiFetch("/api/auth/password", {
        method: "POST",
        body: JSON.stringify({ currentPassword, newPassword: password, confirmPassword }),
      });
      setDone(true);
      setCurrentPassword("");
      setPassword("");
      setConfirmPassword("");
      await refresh();
      router.refresh();
    } catch (err) {
      setError(
        err instanceof ApiRequestError ? err.message : "Could not change your password.",
      );
    } finally {
      setPending(false);
    }
  };

  return (
    <form onSubmit={save} noValidate className="space-y-5">
      {error ? <Alert tone="error">{error}</Alert> : null}
      {done ? (
        <Alert tone="success">
          <span className="inline-flex items-center gap-1.5">
            <Check className="size-3.5" />
            Password changed and this session renewed.
          </span>
        </Alert>
      ) : null}

      <Field label="Current password" htmlFor="pw-current">
        <Input
          id="pw-current"
          type="password"
          value={currentPassword}
          onChange={(e) => setCurrentPassword(e.target.value)}
          autoComplete="current-password"
          required
        />
      </Field>

      <Field label="New password" htmlFor="pw-new" hint="Cannot be empty.">
        <Input
          id="pw-new"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          autoComplete="new-password"
          required
        />
      </Field>

      <Field
        label="Confirm new password"
        htmlFor="pw-confirm"
        error={mismatch ? "Passwords do not match" : undefined}
      >
        <Input
          id="pw-confirm"
          type="password"
          value={confirmPassword}
          onChange={(e) => setConfirmPassword(e.target.value)}
          autoComplete="new-password"
          required
          invalid={mismatch}
        />
      </Field>

      <div className="flex flex-wrap items-center gap-3">
        <Button type="submit" loading={pending}>
          Change password
        </Button>
        <Button
          type="button"
          variant="ghost"
          onClick={() => void signOut(true).then(() => router.push("/"))}
        >
          <LogOut className="size-3.5" />
          Sign out everywhere
        </Button>
      </div>

      <p className="flex items-start gap-2 text-[12px] leading-relaxed text-ink-faint">
        <ShieldCheck className="mt-0.5 size-3.5 shrink-0" />
        Changing your password renews this session immediately, so the copy you were using stops
        working. Other devices stay signed in — use the button above to end them.
      </p>
    </form>
  );
}
