"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import { formatNumber, removeLeadingZeros } from "@/lib/formatters";

export interface NumberInputProps
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "type"> {
  value: number | string | undefined;
  onChange: (value: number | undefined) => void;
  error?: boolean;
  /** 소수점 허용 (기본: false) */
  allowDecimal?: boolean;
  /** 소수점 자릿수 제한 */
  decimalPlaces?: number;
  /** 음수 허용 (기본: false) */
  allowNegative?: boolean;
  /** 천단위 콤마 표시 (기본: false, 포커스 해제 시 적용) */
  useComma?: boolean;
  /** 접미사 (원, 개, % 등) */
  suffix?: string;
  /** 최소값 */
  min?: number;
  /** 최대값 */
  max?: number;
  /** 빈 값 허용 (기본: true, false면 빈 값 시 0 반환) */
  allowEmpty?: boolean;
}

/**
 * NumberInput - 개선된 숫자 입력 컴포넌트
 *
 * 특징:
 * - Leading zero 자동 제거 (01 → 1)
 * - 소수점 허용/자릿수 제한 옵션
 * - 음수 허용 옵션
 * - 천단위 콤마 표시 (포커스 해제 시)
 * - 접미사 지원 (원, 개, % 등)
 * - min/max 범위 제한
 * - onChange에는 항상 number 타입 반환
 *
 * @example
 * // 정수만 (수량)
 * <NumberInput value={qty} onChange={setQty} />
 *
 * // 금액 (천단위 콤마)
 * <NumberInput value={price} onChange={setPrice} useComma suffix="원" />
 *
 * // 소수점 2자리 (비율)
 * <NumberInput value={rate} onChange={setRate} allowDecimal decimalPlaces={2} />
 *
 * // 퍼센트 (0-100 제한)
 * <NumberInput value={percent} onChange={setPercent} min={0} max={100} suffix="%" />
 */
const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
  (
    {
      className,
      value,
      onChange,
      error,
      allowDecimal = false,
      decimalPlaces,
      allowNegative = false,
      useComma = false,
      suffix,
      min,
      max,
      allowEmpty = true,
      onFocus,
      onBlur,
      ...props
    },
    ref
  ) => {
    const [isFocused, setIsFocused] = React.useState(false);
    const [displayValue, setDisplayValue] = React.useState<string>("");

    // 외부 value 변경 시 displayValue 동기화
    React.useEffect(() => {
      if (!isFocused) {
        if (value === undefined || value === null || value === "") {
          setDisplayValue("");
        } else {
          const numValue = typeof value === "string" ? parseFloat(value) : value;
          if (!isNaN(numValue)) {
            setDisplayValue(
              formatNumber(numValue, {
                useComma,
                decimalPlaces,
              })
            );
          } else {
            setDisplayValue("");
          }
        }
      }
    }, [value, isFocused, useComma, decimalPlaces]);

    // 입력값 유효성 검사 및 정제
    const sanitizeInput = (input: string): string => {
      let result = input;

      // 허용 문자만 남기기
      if (allowDecimal && allowNegative) {
        result = result.replace(/[^\d.\-]/g, "");
      } else if (allowDecimal) {
        result = result.replace(/[^\d.]/g, "");
      } else if (allowNegative) {
        result = result.replace(/[^\d\-]/g, "");
      } else {
        result = result.replace(/\D/g, "");
      }

      // 음수 기호는 맨 앞에만
      if (allowNegative && result.includes("-")) {
        const isNegative = result.startsWith("-");
        result = result.replace(/-/g, "");
        if (isNegative) result = "-" + result;
      }

      // 소수점은 하나만
      if (allowDecimal && result.includes(".")) {
        const parts = result.split(".");
        result = parts[0] + "." + parts.slice(1).join("");

        // 소수점 자릿수 제한
        if (decimalPlaces !== undefined && parts[1]) {
          result = parts[0] + "." + parts[1].slice(0, decimalPlaces);
        }
      }

      // Leading zero 제거 (소수점 앞 제외)
      if (result && !result.startsWith("0.") && !result.startsWith("-0.")) {
        result = removeLeadingZeros(result);
      }

      return result;
    };

    // 값을 숫자로 변환하고 범위 적용
    const parseAndClamp = (input: string): number | undefined => {
      if (!input || input === "-" || input === ".") {
        return allowEmpty ? undefined : 0;
      }

      let num = parseFloat(input);

      if (isNaN(num)) {
        return allowEmpty ? undefined : 0;
      }

      // 범위 제한
      if (min !== undefined && num < min) num = min;
      if (max !== undefined && num > max) num = max;

      return num;
    };

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      const rawValue = e.target.value;

      // 콤마 제거 (붙여넣기 대응)
      const withoutComma = rawValue.replace(/,/g, "");
      const sanitized = sanitizeInput(withoutComma);

      setDisplayValue(sanitized);

      // 입력 중에는 "-", ".", "-." 같은 중간 상태 허용
      if (sanitized === "-" || sanitized === "." || sanitized === "-.") {
        return;
      }

      const numValue = parseAndClamp(sanitized);
      onChange(numValue);
    };

    const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
      setIsFocused(true);

      // 포커스 시 콤마 제거된 순수 숫자로 표시
      if (value !== undefined && value !== null && value !== "") {
        const numValue = typeof value === "string" ? parseFloat(value) : value;
        if (!isNaN(numValue)) {
          setDisplayValue(String(numValue));
        }
      }

      onFocus?.(e);
    };

    const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
      setIsFocused(false);

      // 블러 시 최종 값 정리 및 포맷팅
      const sanitized = sanitizeInput(displayValue);
      const numValue = parseAndClamp(sanitized);

      onChange(numValue);

      // 포맷팅된 값으로 표시
      if (numValue !== undefined) {
        setDisplayValue(
          formatNumber(numValue, {
            useComma,
            decimalPlaces,
          })
        );
      } else {
        setDisplayValue("");
      }

      onBlur?.(e);
    };

    const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
      // 허용되는 키들
      const allowedKeys = [
        "Backspace", "Delete", "Tab", "Escape", "Enter",
        "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown",
        "Home", "End"
      ];

      if (allowedKeys.includes(e.key)) return;

      // Ctrl/Cmd + A, C, V, X 허용
      if ((e.ctrlKey || e.metaKey) && ["a", "c", "v", "x"].includes(e.key.toLowerCase())) {
        return;
      }

      // 숫자 허용
      if (/^\d$/.test(e.key)) return;

      // 소수점 허용 (한 번만)
      if (allowDecimal && e.key === "." && !displayValue.includes(".")) return;

      // 음수 허용 (맨 앞에만)
      if (allowNegative && e.key === "-" && !displayValue.includes("-")) {
        const input = e.target as HTMLInputElement;
        if (input.selectionStart === 0) return;
      }

      // 그 외 차단
      e.preventDefault();
    };

    return (
      <div className="relative">
        <input
          type="text"
          inputMode={allowDecimal ? "decimal" : "numeric"}
          ref={ref}
          data-slot="input"
          className={cn(
            "file:text-foreground placeholder:text-muted-foreground/50 selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base bg-input-background transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
            "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
            error && "border-red-500 focus-visible:border-red-500 focus-visible:ring-red-500/20",
            suffix && "pr-10",
            className
          )}
          value={displayValue}
          onChange={handleChange}
          onFocus={handleFocus}
          onBlur={handleBlur}
          onKeyDown={handleKeyDown}
          {...props}
        />
        {suffix && !isFocused && displayValue && (
          <span className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground text-sm pointer-events-none">
            {suffix}
          </span>
        )}
      </div>
    );
  }
);

NumberInput.displayName = "NumberInput";

export { NumberInput };