"use client";

import { useRef, useState, type FormEvent } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
  authRoles,
  resolveOtpContext,
  toAuthRole,
} from "./model";
import { authDestination, postAuthRequest } from "./auth-client";

export function OtpForm({ apiEnabled }: { apiEnabled: boolean }) {
  const router = useRouter();
  const params = useSearchParams();
  const pending = useRef(false);
  const context = resolveOtpContext(
    new URLSearchParams(params.toString()),
    apiEnabled,
  );
  const email = context?.email ?? "";
  const role = context?.role ?? "admin";
  const [code, setCode] = useState("");
  const [error, setError] = useState("");
  const [notice, setNotice] = useState("");
  const [busy, setBusy] = useState(false);

  async function verify(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (pending.current || !context) return;
    setError("");
    setNotice("");
    if (!apiEnabled) return;

    pending.current = true;
    setBusy(true);
    const result = await postAuthRequest("verify", { email, code: code.trim() });
    pending.current = false;
    setBusy(false);
    if (!result.ok) {
      setError(result.error);
      return;
    }
    if (!result.session) {
      setError(
        "The authentication service did not return a valid session. Please try again.",
      );
      return;
    }
    setCode("");
    router.replace(authDestination(result.session));
    router.refresh();
  }

  async function resend() {
    if (pending.current || !context) return;
    setError("");
    setNotice("");
    if (!apiEnabled) return;

    pending.current = true;
    setBusy(true);
    const result = await postAuthRequest("otp", {
      email,
      role: toAuthRole(role),
    });
    pending.current = false;
    setBusy(false);
    if (!result.ok) {
      setError(result.error);
      return;
    }
    setCode("");
    setNotice("A new verification code was requested.");
  }

  if (!apiEnabled) {
    return (
      <div className="space-y-4">
        <p role="alert" className="text-sm leading-6 text-destructive">
          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 (!context) {
    return (
      <div className="space-y-4">
        <p role="alert" className="text-sm leading-6 text-destructive">
          Verification details are missing or invalid. Return to sign in to
          request a new code.
        </p>
        <Button asChild variant="outline" className="w-full">
          <Link href="/signin" prefetch={false}>
            Back to sign in
          </Link>
        </Button>
      </div>
    );
  }

  const selectedRole = authRoles.find(({ value }) => value === role)?.label;

  return (
    <div className="space-y-5">
      <p className="break-words text-sm text-muted-foreground">
        Verification for <strong className="text-foreground">{email}</strong>
        {selectedRole ? (
          <>
            {" "}as <strong className="text-foreground">{selectedRole}</strong>
          </>
        ) : null}
      </p>
      <form className="space-y-5" onSubmit={verify} noValidate>
        <div>
          <label htmlFor="verification-code" className="field-label">
            Verification code <span className="text-destructive">*</span>
          </label>
          <input
            id="verification-code"
            name="code"
            className="form-input text-center text-xl font-semibold tracking-[0.3em]"
            value={code}
            onChange={(event) => {
              setCode(
                event.target.value
                  .toUpperCase()
                  .replace(/[^A-Z0-9]/g, "")
                  .slice(0, 6),
              );
              setError("");
            }}
            autoComplete="one-time-code"
            inputMode="numeric"
            maxLength={6}
            aria-invalid={Boolean(error)}
            aria-describedby={error ? "verification-code-error" : undefined}
            required
            disabled={busy}
          />
          {error && (
            <p
              id="verification-code-error"
              role="alert"
              className="mt-1 text-sm text-destructive"
            >
              {error}
            </p>
          )}
        </div>
        <Button variant="auth" className="w-full" disabled={busy}>
          {busy ? "Verifying…" : "Verify OTP"}
        </Button>
      </form>
      {notice && (
        <p role="status" className="text-sm text-muted-foreground">
          {notice}
        </p>
      )}
      <div className="flex flex-wrap justify-between gap-3 text-sm">
        <Link
          className="text-auth-action hover:underline"
          href={
            "/signin?" + new URLSearchParams({ email, role })
          }
          prefetch={false}
        >
          Back to sign in
        </Link>
        <button
          type="button"
          className="text-auth-action hover:underline disabled:opacity-50"
          onClick={() => void resend()}
          disabled={busy}
        >
          Resend code
        </button>
      </div>
      <p className="text-xs leading-5 text-muted-foreground">
        If the code has expired, request a new one. OTPs are never saved on
        this device.
      </p>
    </div>
  );
}
