"use client";

import { useEffect, useRef, useState, type FormEvent } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { passwordFieldErrors } from "./model";
import { PasswordField } from "./password-field";
import { authDestination, postAuthRequest } from "./auth-client";

type PasswordMode = "set" | "reset";

export function PasswordForm({
  mode,
  apiEnabled,
  token = "",
  unavailableMessage = "",
}: {
  mode: PasswordMode;
  apiEnabled: boolean;
  token?: string;
  unavailableMessage?: string;
}) {
  const router = useRouter();
  const pending = useRef(false);
  const [password, setPassword] = useState("");
  const [confirmation, setConfirmation] = useState("");
  const [fieldErrors, setFieldErrors] = useState<
    ReturnType<typeof passwordFieldErrors>
  >({});
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    if (mode !== "reset" || !token) return;
    const url = new URL(window.location.href);
    url.searchParams.delete("token");
    window.history.replaceState(
      window.history.state,
      "",
      `${url.pathname}${url.search}${url.hash}`,
    );
  }, [mode, token]);

  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (pending.current || !apiEnabled || unavailableMessage) return;
    setError("");
    setFieldErrors({});
    const nextFieldErrors = passwordFieldErrors(password, confirmation);
    if (nextFieldErrors.password || nextFieldErrors.confirmation) {
      setFieldErrors(nextFieldErrors);
      return;
    }
    if (mode === "reset" && !token) {
      setError("The reset token is missing. Open the complete link from your reset email.");
      return;
    }

    pending.current = true;
    setBusy(true);
    const result = await postAuthRequest(
      mode === "reset" ? "reset-password" : "set-password",
      {
        new_password: password,
        confirm_password: confirmation,
        ...(mode === "reset" ? { token } : {}),
      },
    );
    pending.current = false;
    setBusy(false);
    if (!result.ok) {
      setError(result.error);
      return;
    }
    setPassword("");
    setConfirmation("");
    if (mode === "reset") {
      router.replace("/signin");
      router.refresh();
      return;
    }
    if (!result.session) {
      setError(
        "The authentication service did not return a valid session. Please try again.",
      );
      return;
    }
    router.replace(authDestination(result.session));
    router.refresh();
  }

  if (unavailableMessage || !apiEnabled) {
    return (
      <div className="space-y-5">
        <p role="alert" className="rounded-lg border border-destructive/30 bg-card p-3 text-sm">
          {unavailableMessage ||
            "Authentication is unavailable because the authentication service is not configured."}
        </p>
        <Button asChild variant="outline" className="w-full">
          <Link href="/signin" prefetch={false}>
            Back to sign in
          </Link>
        </Button>
      </div>
    );
  }

  if (mode === "reset" && !token) {
    return (
      <div className="space-y-5">
        <p role="alert" className="rounded-lg border border-destructive/30 bg-card p-3 text-sm">
          This reset link is missing its token. Request a new password reset
          link to continue.
        </p>
        <Button asChild variant="auth" className="w-full">
          <Link href="/forgot-password" prefetch={false}>
            Request a new link
          </Link>
        </Button>
      </div>
    );
  }

  return (
    <form onSubmit={submit} noValidate>
      <fieldset disabled={busy} className="space-y-5" aria-busy={busy}>
        <PasswordField
          label="New password"
          value={password}
          onChange={(value) => {
            setPassword(value);
            setFieldErrors({});
            setError("");
          }}
          error={fieldErrors.password}
        />
        <p className="text-xs leading-5 text-muted-foreground">
          Use a password no longer than 1024 characters. Your password is sent
          only to the authentication service and is never saved in browser storage.
        </p>
        <PasswordField
          label="Confirm new password"
          value={confirmation}
          onChange={(value) => {
            setConfirmation(value);
            setFieldErrors({});
            setError("");
          }}
          error={fieldErrors.confirmation}
        />
        {error && (
          <p role="alert" className="text-sm text-destructive">
            {error}
          </p>
        )}
        <Button variant="auth" className="w-full" disabled={busy}>
          {busy
            ? "Saving…"
            : mode === "reset"
              ? "Reset password"
              : "Set password"}
        </Button>
      </fieldset>
      <Link href="/signin" className="mt-5 block text-sm text-auth-action hover:underline">
        Back to sign in
      </Link>
    </form>
  );
}
