"use client";

import { getFormFieldErrors } from "@better-auth-ui/core";
import type { UsernameAuthClient } from "@better-auth-ui/core/plugins/username";
import { useAuth, useAuthPlugin } from "@better-auth-ui/react";
import { useIsUsernameAvailable } from "@better-auth-ui/react/plugins/username";
import { useDebouncer } from "@tanstack/react-pacer";
import { Check, X } from "lucide-react";
import { useState } from "react";
import type { AdditionalFieldProps } from "@/components/auth/additional-field";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
} from "@/components/ui/input-group";
import { Spinner } from "@/components/ui/spinner";
import { usernamePlugin } from "@/lib/auth/username-plugin";

/** Renderer for the `username` additional field. Owns availability checking, length limits, and visual indicators. `isInvalid` reflects only browser validation (minLength, required, etc.) - availability feedback is shown via the icon and `aria-label` without affecting the field's invalid state. */
export function UsernameField({
  name,
  field,
  value,
  onBlur,
  onChange,
  isInvalid,
  errors,
  isPending,
}: AdditionalFieldProps) {
  const { authClient, localization: authLocalization } =
    useAuth<UsernameAuthClient>();
  const {
    localization,
    minUsernameLength,
    maxUsernameLength,
    isUsernameAvailable: checkAvailability,
    usernamePrefix,
  } = useAuthPlugin(usernamePlugin);

  const currentUsername = String(field.defaultValue ?? "");
  const username = typeof value === "string" ? value : "";
  const [nativeError, setNativeError] = useState<string>();
  const fieldErrors = getFormFieldErrors(errors ?? []);

  const {
    mutate: requestAvailability,
    data: availability,
    error: availabilityError,
    reset: resetAvailability,
  } = useIsUsernameAvailable(authClient, {
    onError: () => {},
  });

  const debouncer = useDebouncer(
    (next: string) => {
      const trimmed = next.trim();
      if (!trimmed || trimmed === currentUsername) {
        resetAvailability();
        return;
      }

      requestAvailability({ username: trimmed });
    },
    { wait: 500 },
  );

  function handleChange(next: string) {
    onChange(next || null);
    setNativeError(undefined);
    resetAvailability();

    if (checkAvailability) {
      debouncer.maybeExecute(next);
    }
  }

  const isCheckingAvailability =
    !!checkAvailability &&
    !!username.trim() &&
    username.trim() !== currentUsername;

  return (
    <Field data-invalid={isInvalid || !!nativeError}>
      <FieldLabel htmlFor={name}>{field.label}</FieldLabel>

      <InputGroup>
        {usernamePrefix && (
          <InputGroupAddon align="inline-start">
            {usernamePrefix}
          </InputGroupAddon>
        )}

        <InputGroupInput
          id={name}
          name={name}
          type="text"
          autoComplete="username"
          minLength={minUsernameLength}
          maxLength={maxUsernameLength}
          disabled={isPending}
          required={field.required}
          readOnly={field.readOnly}
          value={username}
          onBlur={onBlur}
          onChange={(e) => handleChange(e.target.value)}
          onInvalid={(e) => {
            e.preventDefault();
            const el = e.target as HTMLInputElement;
            const msg = el.validity.valueMissing
              ? authLocalization.auth.fieldRequired
              : el.validity.tooShort
                ? authLocalization.auth.tooShort.replace(
                    "{{min}}",
                    String(minUsernameLength),
                  )
                : authLocalization.auth.tooLong.replace(
                    "{{max}}",
                    String(maxUsernameLength),
                  );
            setNativeError(msg);
          }}
          aria-invalid={isInvalid || !!nativeError}
          placeholder={field.placeholder}
        />

        {isCheckingAvailability && (
          <InputGroupAddon
            align="inline-end"
            aria-label={
              availability?.available
                ? localization.usernameAvailable
                : availability?.available === false
                  ? localization.usernameTaken
                  : undefined
            }
          >
            {availability?.available ? (
              <Check className="size-4 text-foreground" />
            ) : availabilityError || availability?.available === false ? (
              <X className="size-4 text-destructive" />
            ) : (
              <Spinner />
            )}
          </InputGroupAddon>
        )}
      </InputGroup>

      <FieldError errors={fieldErrors}>{nativeError}</FieldError>
    </Field>
  );
}
