/**
 * OtpInput - 6-digit OTP code input
 *
 * Auto-focuses next input on entry, handles paste, backspace navigation.
 */

"use client";

import {
  useRef,
  useState,
  useCallback,
  useEffect,
  type KeyboardEvent,
  type ClipboardEvent,
} from "react";
import { cn } from "@/shared/utils";

interface OtpInputProps {
  length?: number | undefined;
  value: string;
  onChange: (value: string) => void;
  onComplete?: ((value: string) => void) | undefined;
  disabled?: boolean | undefined;
  error?: string | undefined;
  autoFocus?: boolean | undefined;
}

export function OtpInput({
  length = 6,
  value,
  onChange,
  onComplete,
  disabled = false,
  error,
  autoFocus = true,
}: OtpInputProps) {
  const inputRefs = useRef<(HTMLInputElement | null)[]>([]);
  const [activeIndex, setActiveIndex] = useState(0);

  // Split value into array of characters
  const digits = value.split("").slice(0, length);
  while (digits.length < length) {
    digits.push("");
  }

  // Focus first empty input on mount
  useEffect(() => {
    if (autoFocus && !disabled) {
      const firstEmptyIndex = digits.findIndex(d => !d);
      const targetIndex = firstEmptyIndex === -1 ? 0 : firstEmptyIndex;
      inputRefs.current[targetIndex]?.focus();
    }
  }, [autoFocus, disabled, digits]);

  const focusInput = useCallback(
    (index: number) => {
      const clampedIndex = Math.max(0, Math.min(index, length - 1));
      inputRefs.current[clampedIndex]?.focus();
      setActiveIndex(clampedIndex);
    },
    [length]
  );

  const handleChange = useCallback(
    (index: number, char: string) => {
      if (!/^\d?$/.test(char)) return;

      const newDigits = [...digits];
      newDigits[index] = char;
      const newValue = newDigits.join("");
      onChange(newValue);

      // Move to next input if character entered
      if (char && index < length - 1) {
        focusInput(index + 1);
      }

      // Check if complete
      if (newValue.length === length && !newValue.includes("")) {
        onComplete?.(newValue);
      }
    },
    [digits, length, onChange, onComplete, focusInput]
  );

  const handleKeyDown = useCallback(
    (index: number, e: KeyboardEvent<HTMLInputElement>) => {
      if (e.key === "Backspace") {
        e.preventDefault();
        if (digits[index]) {
          handleChange(index, "");
        } else if (index > 0) {
          focusInput(index - 1);
          handleChange(index - 1, "");
        }
      } else if (e.key === "ArrowLeft" && index > 0) {
        e.preventDefault();
        focusInput(index - 1);
      } else if (e.key === "ArrowRight" && index < length - 1) {
        e.preventDefault();
        focusInput(index + 1);
      }
    },
    [digits, focusInput, handleChange, length]
  );

  const handlePaste = useCallback(
    (e: ClipboardEvent<HTMLInputElement>) => {
      e.preventDefault();
      const pastedData = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
      if (pastedData) {
        onChange(pastedData);
        const nextIndex = Math.min(pastedData.length, length - 1);
        focusInput(nextIndex);

        if (pastedData.length === length) {
          onComplete?.(pastedData);
        }
      }
    },
    [length, onChange, onComplete, focusInput]
  );

  return (
    <div className="space-y-2">
      <div className="flex justify-center gap-2">
        {digits.map((digit, index) => (
          <input
            key={index}
            ref={el => {
              inputRefs.current[index] = el;
            }}
            type="text"
            inputMode="numeric"
            autoComplete="one-time-code"
            maxLength={1}
            value={digit}
            disabled={disabled}
            onChange={e => handleChange(index, e.target.value)}
            onKeyDown={e => handleKeyDown(index, e)}
            onPaste={handlePaste}
            onFocus={() => setActiveIndex(index)}
            className={cn(
              "w-12 h-14 text-center text-xl font-semibold",
              "rounded-lg border bg-card text-foreground",
              "focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary",
              "transition-all duration-150",
              "disabled:opacity-50 disabled:cursor-not-allowed",
              error
                ? "border-danger focus:ring-danger focus:border-danger"
                : activeIndex === index
                  ? "border-primary"
                  : "border-border hover:border-muted-foreground/50"
            )}
            aria-label={`Digit ${index + 1}`}
          />
        ))}
      </div>
      {error && (
        <p className="text-sm text-danger text-center" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}
