import React, { forwardRef } from 'react'

// ─── Input ────────────────────────────────────────────────────────────────────

export interface InputProps {
  type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'
  label?: string | React.ReactNode
  placeholder?: string
  error?: string
  helpText?: string
  disabled?: boolean
  required?: boolean
  leftIcon?: string
  rightIcon?: string
  leftSlot?: React.ReactNode
  rightSlot?: React.ReactNode
  className?: string
  labelClassName?: string
  inputClassName?: string
  value?: string
  defaultValue?: string
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
  id?: string
  name?: string
  pattern?: string
  minLength?: number
  maxLength?: number
  step?: number
}

export const Input = forwardRef<HTMLInputElement, InputProps>(
  (
    {
      type = 'text',
      label,
      placeholder,
      error,
      helpText,
      disabled = false,
      required = false,
      leftIcon,
      rightIcon,
      leftSlot,
      rightSlot,
      className = '',
      labelClassName = '',
      inputClassName = '',
      value,
      defaultValue,
      onChange,
      id,
      name,
      pattern,
      minLength,
      maxLength,
      step,
    },
    ref
  ) => {
    const hasLeft = leftIcon || leftSlot
    const hasRight = rightIcon || rightSlot

    return (
      <div className={className}>
        {label && (
          <label htmlFor={id} className={`block text-xs font-semibold text-slate-800 mb-1 ${labelClassName}`}>
            {label}
            {required && <span className="text-red-500 ml-1">*</span>}
          </label>
        )}

        <div className="relative">
          {leftIcon && (
            <span className="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-body-lg pointer-events-none">
              {leftIcon}
            </span>
          )}
          {leftSlot && (
            <div className="absolute left-3 top-1/2 -translate-y-1/2">{leftSlot}</div>
          )}
          {rightIcon && (
            <span className="material-symbols-outlined absolute right-3.5 top-1/2 -translate-y-1/2 text-slate-400 text-body-lg pointer-events-none">
              {rightIcon}
            </span>
          )}
          {rightSlot && (
            <div className="absolute right-3.5 top-1/2 -translate-y-1/2 pointer-events-none">
              {rightSlot}
            </div>
          )}

          <input
            ref={ref}
            type={type}
            placeholder={placeholder}
            disabled={disabled}
            required={required}
            value={value}
            defaultValue={defaultValue}
            onChange={onChange}
            id={id}
            name={name}
            pattern={pattern}
            minLength={minLength}
            maxLength={maxLength}
            step={step}
            className={`
              w-full bg-slate-50 rounded-[10px]
              ${hasLeft ? 'pl-9' : 'pl-3.5'} ${hasRight ? 'pr-9' : 'pr-3.5'} py-2.5
              text-body-sm text-slate-800 placeholder:text-slate-400
              transition-all duration-150 outline-none
              disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed
              ${error
                ? 'bg-red-50 border-[1.5px] border-red-300'
                : 'border-[1.5px] border-slate-200 focus:ring-1 focus:ring-teal-500 focus:border-teal-300'
              }
              ${inputClassName}
            `}
          />
        </div>

        {error && (
          <p className="mt-1 text-caption font-semibold text-red-500">{error}</p>
        )}
        {helpText && !error && (
          <p className="mt-1 text-caption text-slate-500">{helpText}</p>
        )}
      </div>
    )
  }
)
Input.displayName = 'Input'

// ─── SearchInput ──────────────────────────────────────────────────────────────

export const SearchInput = forwardRef<HTMLInputElement, {
  placeholder?: string
  error?: string
  helpText?: string
  disabled?: boolean
  className?: string
  value?: string
  defaultValue?: string
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
  id?: string
  name?: string
}>(
  (
    {
      placeholder = '검색...',
      error,
      helpText,
      disabled = false,
      className = '',
      value,
      defaultValue,
      onChange,
      id,
      name,
    },
    ref
  ) => (
    <div className={className}>
      <div className="relative">
        <span className="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 text-body-lg pointer-events-none">
          search
        </span>
        <input
          ref={ref}
          type="text"
          placeholder={placeholder}
          disabled={disabled}
          value={value}
          defaultValue={defaultValue}
          onChange={onChange}
          id={id}
          name={name}
          className={`
            w-full bg-slate-50 rounded-[10px]
            pl-9 pr-3.5 py-2.5 text-body-sm text-slate-800
            placeholder:text-slate-400 transition-all duration-150 outline-none
            disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed
            ${error ? 'bg-red-50 border-[1.5px] border-red-300' : 'border-[1.5px] border-slate-200 focus:ring-1 focus:ring-teal-500 focus:border-teal-300'}
          `}
        />
      </div>
      {error && <p className="mt-1 text-caption font-semibold text-red-500">{error}</p>}
      {helpText && !error && <p className="mt-1 text-caption text-slate-500">{helpText}</p>}
    </div>
  )
)
SearchInput.displayName = 'SearchInput'

// ─── Select ───────────────────────────────────────────────────────────────────

export const Select = forwardRef<HTMLSelectElement, {
  label?: string | React.ReactNode
  children?: React.ReactNode
  error?: string
  helpText?: string
  disabled?: boolean
  required?: boolean
  className?: string
  selectClassName?: string
  defaultValue?: string
  value?: string
  onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void
  id?: string
  name?: string
}>(
  (
    {
      label,
      children,
      error,
      helpText,
      disabled = false,
      required = false,
      className = '',
      selectClassName = '',
      defaultValue,
      value,
      onChange,
      id,
      name,
    },
    ref
  ) => (
    <div className={className}>
      {label && (
        <label htmlFor={id} className="block text-xs font-semibold text-slate-800 mb-1">
          {label}
          {required && <span className="text-red-500 ml-1">*</span>}
        </label>
      )}
      <div className="relative">
        <select
          ref={ref}
          value={value}
          defaultValue={defaultValue}
          onChange={onChange}
          disabled={disabled}
          required={required}
          id={id}
          name={name}
          className={`
            w-full bg-slate-50 rounded-[10px]
            pl-3.5 pr-9 py-2.5 text-body-sm text-slate-800 appearance-none outline-none
            disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed
            ${error ? 'bg-red-50 border-[1.5px] border-red-300' : 'border-[1.5px] border-slate-200 focus:ring-1 focus:ring-teal-500 focus:border-teal-300'}
            ${selectClassName}
          `}
        >
          {children}
        </select>
        <span className="material-symbols-outlined absolute right-3.5 top-1/2 -translate-y-1/2 text-slate-400 text-body-lg pointer-events-none">
          expand_more
        </span>
      </div>
      {error && <p className="mt-1 text-caption font-semibold text-red-500">{error}</p>}
      {helpText && !error && <p className="mt-1 text-caption text-slate-500">{helpText}</p>}
    </div>
  )
)
Select.displayName = 'Select'

// ─── Toggle ───────────────────────────────────────────────────────────────────

export const Toggle: React.FC<{
  checked: boolean
  onChange?: (checked: boolean) => void
  disabled?: boolean
  label?: string | React.ReactNode
  className?: string
  labelClassName?: string
}> = ({ checked, onChange, disabled = false, label, className = '', labelClassName = '' }) => (
  <div className="flex items-center gap-2.5">
    <button
      type="button"
      role="switch"
      aria-checked={checked}
      onClick={() => !disabled && onChange?.(!checked)}
      disabled={disabled}
      className={`
        relative w-11 h-6 rounded-full transition-colors duration-150
        ${checked ? 'bg-teal-500' : 'bg-slate-200'}
        ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
        ${className}
      `}
    >
      <span
        className={`
          absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow-soft-sm
          transition-transform duration-150
          ${checked ? 'translate-x-5' : 'translate-x-0'}
        `}
      />
    </button>
    {label && (
      <span className={`text-body-sm font-semibold text-slate-800 ${labelClassName}`}>
        {label}
      </span>
    )}
  </div>
)

// ─── Checkbox ─────────────────────────────────────────────────────────────────

export const Checkbox: React.FC<{
  checked: boolean
  onChange?: (checked: boolean) => void
  disabled?: boolean
  label?: string | React.ReactNode
  className?: string
  labelClassName?: string
}> = ({ checked, onChange, disabled = false, label, className = '', labelClassName = '' }) => (
  <label className={`flex items-center gap-2 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
    <div
      onClick={() => !disabled && onChange?.(!checked)}
      className={`
        w-[18px] h-[18px] rounded flex items-center justify-center transition-colors duration-150
        ${checked ? 'bg-teal-500' : 'bg-white border-2 border-slate-200'}
        ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
        ${className}
      `}
    >
      {checked && (
        <svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="3">
          <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
        </svg>
      )}
    </div>
    {label && (
      <span className={`text-body-sm font-semibold ${checked ? 'text-slate-800' : 'text-slate-500'} ${labelClassName}`}>
        {label}
      </span>
    )}
  </label>
)

// ─── Radio ────────────────────────────────────────────────────────────────────

export const Radio: React.FC<{
  checked: boolean
  onChange?: (checked: boolean) => void
  disabled?: boolean
  label?: string | React.ReactNode
  labelClassName?: string
  name?: string
  value?: string
}> = ({ checked, onChange, disabled = false, label, labelClassName = '', name, value }) => (
  <label className={`flex items-center gap-2 ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
    <input
      type="radio"
      name={name}
      value={value}
      checked={checked}
      onChange={() => !disabled && onChange?.(true)}
      disabled={disabled}
      className="sr-only"
    />
    <div
      className={`
        w-[18px] h-[18px] rounded-full flex items-center justify-center
        border-2 transition-colors duration-150
        ${checked ? 'border-teal-500 bg-white' : 'border-slate-200 bg-white'}
        ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
      `}
    >
      {checked && <span className="w-2.5 h-2.5 bg-teal-500 rounded-full" />}
    </div>
    {label && (
      <span className={`text-body-sm font-semibold ${checked ? 'text-slate-800' : 'text-slate-500'} ${labelClassName}`}>
        {label}
      </span>
    )}
  </label>
)

// ─── NumberInput ──────────────────────────────────────────────────────────────

export const NumberInput = forwardRef<HTMLInputElement, {
  label?: string | React.ReactNode
  value?: number
  defaultValue?: number
  onChange?: (value: number) => void
  min?: number
  max?: number
  step?: number
  unit?: string
  error?: string
  helpText?: string
  disabled?: boolean
  required?: boolean
  className?: string
  id?: string
  name?: string
}>(
  (
    {
      label,
      value,
      defaultValue,
      onChange,
      min,
      max,
      step = 1,
      unit,
      error,
      helpText,
      disabled = false,
      required = false,
      className = '',
      id,
      name,
    },
    ref
  ) => {
    const handleStep = (dir: 1 | -1) => {
      if (disabled || onChange == null) return
      const current = value ?? defaultValue ?? 0
      const next = current + dir * step
      if (min != null && next < min) return
      if (max != null && next > max) return
      onChange(next)
    }

    return (
      <div className={className}>
        {label && (
          <label htmlFor={id} className="block text-xs font-semibold text-slate-800 mb-1">
            {label}
            {required && <span className="text-red-500 ml-1">*</span>}
          </label>
        )}
        <div className="relative w-32">
          <input
            ref={ref}
            type="number"
            min={min}
            max={max}
            step={step}
            value={value}
            defaultValue={defaultValue}
            onChange={(e) => onChange?.(parseFloat(e.target.value))}
            disabled={disabled}
            required={required}
            id={id}
            name={name}
            className={`
              w-full bg-slate-50 rounded-[10px]
              pl-3.5 ${unit ? 'pr-10' : 'pr-8'} py-2.5
              text-body-sm text-slate-800 outline-none
              [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none
              disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed
              ${error ? 'bg-red-50 border-[1.5px] border-red-300' : 'border-[1.5px] border-slate-200 focus:ring-1 focus:ring-teal-500 focus:border-teal-300'}
            `}
          />
          {unit ? (
            <span className="absolute right-3.5 top-1/2 -translate-y-1/2 text-caption font-semibold text-slate-400 pointer-events-none">
              {unit}
            </span>
          ) : (
            <div className="absolute right-1.5 top-1/2 -translate-y-1/2 flex flex-col">
              <button
                type="button"
                onClick={() => handleStep(1)}
                disabled={disabled}
                className="text-slate-400 hover:text-teal-500 transition-colors cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
                aria-label="증가"
              >
                <span className="material-symbols-outlined text-body-md">expand_less</span>
              </button>
              <button
                type="button"
                onClick={() => handleStep(-1)}
                disabled={disabled}
                className="text-slate-400 hover:text-teal-500 transition-colors -mt-1 cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"
                aria-label="감소"
              >
                <span className="material-symbols-outlined text-body-md">expand_more</span>
              </button>
            </div>
          )}
        </div>
        {error && <p className="mt-1 text-caption font-semibold text-red-500">{error}</p>}
        {helpText && !error && <p className="mt-1 text-caption text-slate-500">{helpText}</p>}
      </div>
    )
  }
)
NumberInput.displayName = 'NumberInput'

// ─── Slider ───────────────────────────────────────────────────────────────────

export const Slider: React.FC<{
  value: number
  onChange?: (value: number) => void
  min?: number
  max?: number
  step?: number
  disabled?: boolean
  showValue?: boolean
  label?: string
  className?: string
}> = ({
  value,
  onChange,
  min = 0,
  max = 100,
  step = 1,
  disabled = false,
  showValue = true,
  label,
  className = '',
}) => (
  <div className={className}>
    {(label || showValue) && (
      <div className="flex justify-between items-center mb-2">
        {label && <span className="text-xs font-semibold text-slate-800">{label}</span>}
        {showValue && (
          <span className={`text-body-sm font-bold text-teal-600 ${!label ? 'ml-auto' : ''}`}>
            {value}
          </span>
        )}
      </div>
    )}
    <input
      type="range"
      min={min}
      max={max}
      step={step}
      value={value}
      onChange={(e) => onChange?.(parseFloat(e.target.value))}
      disabled={disabled}
      className="
        w-full h-1.5 bg-slate-200 rounded-full appearance-none cursor-pointer
        disabled:opacity-50 disabled:cursor-not-allowed
        [&::-webkit-slider-thumb]:appearance-none
        [&::-webkit-slider-thumb]:w-4
        [&::-webkit-slider-thumb]:h-4
        [&::-webkit-slider-thumb]:rounded-full
        [&::-webkit-slider-thumb]:bg-teal-500
        [&::-webkit-slider-thumb]:shadow-soft-sm
        [&::-webkit-slider-thumb]:cursor-pointer
        [&::-webkit-slider-thumb]:border-2
        [&::-webkit-slider-thumb]:border-white
      "
    />
    <div className="flex justify-between mt-1">
      <span className="text-caption text-slate-400">{min}</span>
      <span className="text-caption text-slate-400">{max}</span>
    </div>
  </div>
)

// ─── Textarea ─────────────────────────────────────────────────────────────────

export const Textarea = forwardRef<HTMLTextAreaElement, {
  label?: string | React.ReactNode
  placeholder?: string
  error?: string
  helpText?: string
  disabled?: boolean
  required?: boolean
  rows?: number
  className?: string
  textareaClassName?: string
  value?: string
  defaultValue?: string
  onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void
  id?: string
  name?: string
  minLength?: number
  maxLength?: number
}>(
  (
    {
      label,
      placeholder,
      error,
      helpText,
      disabled = false,
      required = false,
      rows = 3,
      className = '',
      textareaClassName = '',
      value,
      defaultValue,
      onChange,
      id,
      name,
      minLength,
      maxLength,
    },
    ref
  ) => (
    <div className={className}>
      {label && (
        <label htmlFor={id} className="block text-xs font-semibold text-slate-800 mb-1">
          {label}
          {required && <span className="text-red-500 ml-1">*</span>}
        </label>
      )}
      <textarea
        ref={ref}
        placeholder={placeholder}
        disabled={disabled}
        required={required}
        rows={rows}
        value={value}
        defaultValue={defaultValue}
        onChange={onChange}
        id={id}
        name={name}
        minLength={minLength}
        maxLength={maxLength}
        className={`
          w-full bg-slate-50 rounded-[10px]
          px-3.5 py-3 text-body-sm text-slate-800
          placeholder:text-slate-400 transition-all duration-150 outline-none
          disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed
          resize-y min-h-[72px]
          ${error ? 'bg-red-50 border-[1.5px] border-red-300' : 'border-[1.5px] border-slate-200 focus:ring-1 focus:ring-teal-500 focus:border-teal-300'}
          ${textareaClassName}
        `}
      />
      {error && <p className="mt-1 text-caption font-semibold text-red-500">{error}</p>}
      {helpText && !error && <p className="mt-1 text-caption text-slate-500">{helpText}</p>}
    </div>
  )
)
Textarea.displayName = 'Textarea'
