"use client";

/**
 * UnifiedInput
 * 
 * 통합 입력 컴포넌트
 * - text: 텍스트 입력
 * - number: 숫자 입력
 * - password: 비밀번호 입력
 * - slider: 슬라이더 입력
 * - color: 색상 선택
 * - button: 버튼 (입력이 아닌 액션)
 */

import React, { forwardRef, useCallback, useMemo, useState } from "react";
import { Input } from "@/components/ui/input";
import { Slider } from "@/components/ui/slider";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import { UnifiedInputProps, UnifiedInputType, UnifiedInputFormat } from "@/types/unified-components";

// 형식별 입력 마스크 및 검증 패턴
const FORMAT_PATTERNS: Record<UnifiedInputFormat, { pattern: RegExp; placeholder: string }> = {
  none: { pattern: /.*/, placeholder: "" },
  email: { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, placeholder: "example@email.com" },
  tel: { pattern: /^\d{2,3}-\d{3,4}-\d{4}$/, placeholder: "010-1234-5678" },
  url: { pattern: /^https?:\/\/.+/, placeholder: "https://example.com" },
  currency: { pattern: /^[\d,]+$/, placeholder: "1,000,000" },
  biz_no: { pattern: /^\d{3}-\d{2}-\d{5}$/, placeholder: "123-45-67890" },
};

// 통화 형식 변환
function formatCurrency(value: string | number): string {
  const num = typeof value === "string" ? parseFloat(value.replace(/,/g, "")) : value;
  if (isNaN(num)) return "";
  return num.toLocaleString("ko-KR");
}

// 사업자번호 형식 변환
function formatBizNo(value: string): string {
  const digits = value.replace(/\D/g, "");
  if (digits.length <= 3) return digits;
  if (digits.length <= 5) return `${digits.slice(0, 3)}-${digits.slice(3)}`;
  return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5, 10)}`;
}

// 전화번호 형식 변환
function formatTel(value: string): string {
  const digits = value.replace(/\D/g, "");
  if (digits.length <= 3) return digits;
  if (digits.length <= 7) return `${digits.slice(0, 3)}-${digits.slice(3)}`;
  if (digits.length <= 11) return `${digits.slice(0, 3)}-${digits.slice(3, 7)}-${digits.slice(7)}`;
  return `${digits.slice(0, 3)}-${digits.slice(3, 7)}-${digits.slice(7, 11)}`;
}

/**
 * 텍스트 입력 컴포넌트
 */
const TextInput = forwardRef<HTMLInputElement, {
  value?: string | number;
  onChange?: (value: string) => void;
  format?: UnifiedInputFormat;
  mask?: string;
  placeholder?: string;
  readonly?: boolean;
  disabled?: boolean;
  className?: string;
}>(({ value, onChange, format = "none", placeholder, readonly, disabled, className }, ref) => {
  // 형식에 따른 값 포맷팅
  const formatValue = useCallback((val: string): string => {
    switch (format) {
      case "currency":
        return formatCurrency(val);
      case "biz_no":
        return formatBizNo(val);
      case "tel":
        return formatTel(val);
      default:
        return val;
    }
  }, [format]);

  const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    let newValue = e.target.value;
    
    // 형식에 따른 자동 포맷팅
    if (format === "currency") {
      // 숫자와 쉼표만 허용
      newValue = newValue.replace(/[^\d,]/g, "");
      newValue = formatCurrency(newValue);
    } else if (format === "biz_no") {
      newValue = formatBizNo(newValue);
    } else if (format === "tel") {
      newValue = formatTel(newValue);
    }
    
    onChange?.(newValue);
  }, [format, onChange]);

  const displayValue = useMemo(() => {
    if (value === undefined || value === null) return "";
    return formatValue(String(value));
  }, [value, formatValue]);

  const inputPlaceholder = placeholder || FORMAT_PATTERNS[format].placeholder;

  return (
    <Input
      ref={ref}
      type="text"
      value={displayValue}
      onChange={handleChange}
      placeholder={inputPlaceholder}
      readOnly={readonly}
      disabled={disabled}
      className={cn("h-full w-full", className)}
    />
  );
});
TextInput.displayName = "TextInput";

/**
 * 숫자 입력 컴포넌트
 */
const NumberInput = forwardRef<HTMLInputElement, {
  value?: number;
  onChange?: (value: number | undefined) => void;
  min?: number;
  max?: number;
  step?: number;
  placeholder?: string;
  readonly?: boolean;
  disabled?: boolean;
  className?: string;
}>(({ value, onChange, min, max, step = 1, placeholder, readonly, disabled, className }, ref) => {
  const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const val = e.target.value;
    if (val === "") {
      onChange?.(undefined);
      return;
    }
    
    let num = parseFloat(val);
    
    // 범위 제한
    if (min !== undefined && num < min) num = min;
    if (max !== undefined && num > max) num = max;
    
    onChange?.(num);
  }, [min, max, onChange]);

  return (
    <Input
      ref={ref}
      type="number"
      value={value ?? ""}
      onChange={handleChange}
      min={min}
      max={max}
      step={step}
      placeholder={placeholder || "숫자 입력"}
      readOnly={readonly}
      disabled={disabled}
      className={cn("h-full w-full", className)}
    />
  );
});
NumberInput.displayName = "NumberInput";

/**
 * 비밀번호 입력 컴포넌트
 */
const PasswordInput = forwardRef<HTMLInputElement, {
  value?: string;
  onChange?: (value: string) => void;
  placeholder?: string;
  readonly?: boolean;
  disabled?: boolean;
  className?: string;
}>(({ value, onChange, placeholder, readonly, disabled, className }, ref) => {
  const [showPassword, setShowPassword] = useState(false);

  return (
    <div className="relative">
      <Input
        ref={ref}
        type={showPassword ? "text" : "password"}
        value={value ?? ""}
        onChange={(e) => onChange?.(e.target.value)}
        placeholder={placeholder || "비밀번호 입력"}
        readOnly={readonly}
        disabled={disabled}
        className={cn("h-full w-full pr-10", className)}
      />
      <button
        type="button"
        onClick={() => setShowPassword(!showPassword)}
        className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground text-xs"
      >
        {showPassword ? "숨김" : "보기"}
      </button>
    </div>
  );
});
PasswordInput.displayName = "PasswordInput";

/**
 * 슬라이더 입력 컴포넌트
 */
const SliderInput = forwardRef<HTMLDivElement, {
  value?: number;
  onChange?: (value: number) => void;
  min?: number;
  max?: number;
  step?: number;
  disabled?: boolean;
  className?: string;
}>(({ value, onChange, min = 0, max = 100, step = 1, disabled, className }, ref) => {
  return (
    <div ref={ref} className={cn("flex items-center gap-4", className)}>
      <Slider
        value={[value ?? min]}
        onValueChange={(values) => onChange?.(values[0])}
        min={min}
        max={max}
        step={step}
        disabled={disabled}
        className="flex-1"
      />
      <span className="text-sm font-medium w-12 text-right">{value ?? min}</span>
    </div>
  );
});
SliderInput.displayName = "SliderInput";

/**
 * 색상 선택 컴포넌트
 */
const ColorInput = forwardRef<HTMLInputElement, {
  value?: string;
  onChange?: (value: string) => void;
  disabled?: boolean;
  className?: string;
}>(({ value, onChange, disabled, className }, ref) => {
  return (
    <div className={cn("flex items-center gap-2", className)}>
      <Input
        ref={ref}
        type="color"
        value={value || "#000000"}
        onChange={(e) => onChange?.(e.target.value)}
        disabled={disabled}
        className="w-12 h-full p-1 cursor-pointer"
      />
      <Input
        type="text"
        value={value || "#000000"}
        onChange={(e) => onChange?.(e.target.value)}
        disabled={disabled}
        className="h-full flex-1 uppercase"
        maxLength={7}
      />
    </div>
  );
});
ColorInput.displayName = "ColorInput";

/**
 * 여러 줄 텍스트 입력 컴포넌트
 */
const TextareaInput = forwardRef<HTMLTextAreaElement, {
  value?: string;
  onChange?: (value: string) => void;
  placeholder?: string;
  rows?: number;
  readonly?: boolean;
  disabled?: boolean;
  className?: string;
}>(({ value = "", onChange, placeholder, rows = 3, readonly, disabled, className }, ref) => {
  return (
    <textarea
      ref={ref}
      value={value}
      onChange={(e) => onChange?.(e.target.value)}
      placeholder={placeholder}
      rows={rows}
      readOnly={readonly}
      disabled={disabled}
      className={cn(
        "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
        className
      )}
    />
  );
});
TextareaInput.displayName = "TextareaInput";

/**
 * 메인 UnifiedInput 컴포넌트
 */
export const UnifiedInput = forwardRef<HTMLDivElement, UnifiedInputProps>(
  (props, ref) => {
    const {
      id,
      label,
      required,
      readonly,
      disabled,
      style,
      size,
      config: configProp,
      value,
      onChange,
    } = props;

    // config가 없으면 기본값 사용
    const config: UnifiedInputConfig = configProp || { type: "text" };

    // 조건부 렌더링 체크
    // TODO: conditional 처리 로직 추가
    
    // 타입별 입력 컴포넌트 렌더링
    const renderInput = () => {
      const inputType = config.type || "text";
      switch (inputType) {
        case "text":
          return (
            <TextInput
              value={value}
              onChange={(v) => onChange?.(v)}
              format={config.format}
              mask={config.mask}
              placeholder={config.placeholder}
              readonly={readonly}
              disabled={disabled}
            />
          );

        case "number":
          return (
            <NumberInput
              value={typeof value === "number" ? value : undefined}
              onChange={(v) => onChange?.(v ?? 0)}
              min={config.min}
              max={config.max}
              step={config.step}
              placeholder={config.placeholder}
              readonly={readonly}
              disabled={disabled}
            />
          );

        case "password":
          return (
            <PasswordInput
              value={typeof value === "string" ? value : ""}
              onChange={(v) => onChange?.(v)}
              placeholder={config.placeholder}
              readonly={readonly}
              disabled={disabled}
            />
          );

        case "slider":
          return (
            <SliderInput
              value={typeof value === "number" ? value : config.min ?? 0}
              onChange={(v) => onChange?.(v)}
              min={config.min}
              max={config.max}
              step={config.step}
              disabled={disabled}
            />
          );

        case "color":
          return (
            <ColorInput
              value={typeof value === "string" ? value : "#000000"}
              onChange={(v) => onChange?.(v)}
              disabled={disabled}
            />
          );

        case "textarea":
          return (
            <TextareaInput
              value={value}
              onChange={(v) => onChange?.(v)}
              placeholder={config.placeholder}
              rows={config.rows}
              readonly={readonly}
              disabled={disabled}
            />
          );

        default:
          return (
            <TextInput
              value={value}
              onChange={(v) => onChange?.(v)}
              placeholder={config.placeholder}
              readonly={readonly}
              disabled={disabled}
            />
          );
      }
    };

    // 라벨이 표시될 때 입력 필드가 차지할 높이 계산
    const showLabel = label && style?.labelDisplay !== false;
    // size에서 우선 가져오고, 없으면 style에서 가져옴
    const componentWidth = size?.width || style?.width;
    const componentHeight = size?.height || style?.height;

    return (
      <div
        ref={ref}
        id={id}
        className="flex flex-col"
        style={{
          width: componentWidth,
          height: componentHeight,
        }}
      >
        {showLabel && (
          <Label
            htmlFor={id}
            style={{
              fontSize: style?.labelFontSize,
              color: style?.labelColor,
              fontWeight: style?.labelFontWeight,
              marginBottom: style?.labelMarginBottom,
            }}
            className="text-sm font-medium flex-shrink-0"
          >
            {label}
            {required && <span className="text-orange-500 ml-0.5">*</span>}
          </Label>
        )}
        <div className="flex-1 min-h-0">
          {renderInput()}
        </div>
      </div>
    );
  }
);

UnifiedInput.displayName = "UnifiedInput";

export default UnifiedInput;

