import { useCallback, useRef } from 'react';

interface NumberInputProps {
  label: string;
  value: number;
  onChange: (value: number) => void;
  min?: number;
  max?: number;
  step?: number;
  unit?: string;
  hint?: string;
  showSlider?: boolean;
}

export default function NumberInput({
  label,
  value,
  onChange,
  min = 0,
  max = 100,
  step = 1,
  unit = '',
  hint,
  showSlider = true,
}: NumberInputProps) {
  const holdTimer = useRef<ReturnType<typeof setInterval> | null>(null);

  const clamp = useCallback(
    (v: number) => Math.max(min, Math.min(max, v)),
    [min, max]
  );

  const increment = useCallback(() => {
    onChange(clamp(value + step));
  }, [value, step, onChange, clamp]);

  const decrement = useCallback(() => {
    onChange(clamp(value - step));
  }, [value, step, onChange, clamp]);

  // Hold-to-repeat for arrow buttons
  const startHold = useCallback(
    (fn: () => void) => {
      fn();
      holdTimer.current = setInterval(fn, 120);
    },
    []
  );

  const stopHold = useCallback(() => {
    if (holdTimer.current) {
      clearInterval(holdTimer.current);
      holdTimer.current = null;
    }
  }, []);

  const handleTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const raw = e.target.value;
    if (raw === '' || raw === '-') return;
    const v = Number(raw);
    if (!isNaN(v)) {
      onChange(clamp(v));
    }
  };

  // Format value for display — avoid long decimals
  const displayValue = Number.isInteger(step) ? value : Number(value.toFixed(1));

  return (
    <div className="space-y-1">
      {/* Label + value badge */}
      <div className="flex items-center justify-between">
        <label className="text-sm font-medium text-gray-700 dark:text-dark-text">
          {label}
        </label>
        <span className="text-sm font-semibold text-blue-600 dark:text-blue-400">
          {displayValue} {unit}
        </span>
      </div>

      {/* Text input + arrow buttons */}
      <div className="flex items-stretch gap-1">
        <input
          type="number"
          value={displayValue}
          onChange={handleTextChange}
          min={min}
          max={max}
          step={step}
          className="flex-1 px-2 py-1.5 border border-gray-300 dark:border-dark-border dark:bg-dark-bg dark:text-dark-text
            rounded-md text-sm text-center font-mono
            focus:outline-none focus:ring-2 focus:ring-blue-500
            [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
        />
        <div className="flex flex-col gap-px">
          <button
            type="button"
            onMouseDown={() => startHold(increment)}
            onMouseUp={stopHold}
            onMouseLeave={stopHold}
            className="px-1.5 py-0 text-[10px] leading-none bg-gray-100 dark:bg-dark-border
              hover:bg-gray-200 dark:hover:bg-dark-muted border border-gray-300 dark:border-dark-border
              rounded-t-md text-gray-600 dark:text-dark-text select-none flex-1 flex items-center justify-center"
            title={`+${step}${unit}`}
          >
            ▲
          </button>
          <button
            type="button"
            onMouseDown={() => startHold(decrement)}
            onMouseUp={stopHold}
            onMouseLeave={stopHold}
            className="px-1.5 py-0 text-[10px] leading-none bg-gray-100 dark:bg-dark-border
              hover:bg-gray-200 dark:hover:bg-dark-muted border border-gray-300 dark:border-dark-border
              rounded-b-md text-gray-600 dark:text-dark-text select-none flex-1 flex items-center justify-center"
            title={`-${step}${unit}`}
          >
            ▼
          </button>
        </div>
      </div>

      {/* Slider for visual feedback */}
      {showSlider && (
        <input
          type="range"
          value={value}
          onChange={(e) => onChange(Number(e.target.value))}
          min={min}
          max={max}
          step={step}
          className="w-full h-1.5 bg-gray-200 dark:bg-dark-border rounded-lg appearance-none cursor-pointer accent-blue-600"
        />
      )}

      {/* Min/max labels */}
      {showSlider && (
        <div className="flex justify-between text-xs text-gray-400 dark:text-dark-muted">
          <span>{min}{unit}</span>
          <span>{max}{unit}</span>
        </div>
      )}

      {hint && <p className="text-xs text-gray-400 dark:text-dark-muted">{hint}</p>}
    </div>
  );
}
