import { Minus, Plus } from "lucide-react";
import * as React from "react";
import { cn } from "../utils";

type Props = {
  value?: number;
  min?: number;
  max?: number;
  onChange?: (value: number) => void;
  onBlur?: () => void;
  onFocus?: () => void;
  className?: string;
  step?: number;
  placeholder?: string;
};

export function QuantityInput({
  value = 0,
  min = Number.NEGATIVE_INFINITY,
  max = Number.POSITIVE_INFINITY,
  onChange,
  onBlur,
  onFocus,
  className,
  step = 0.1,
  placeholder = "0",
}: Props) {
  const inputRef = React.useRef<HTMLInputElement>(null);
  const [rawValue, setRawValue] = React.useState(String(value));

  const handleInput = ({
    currentTarget: el,
  }: {
    currentTarget: HTMLInputElement;
  }) => {
    const input = el.value;
    setRawValue(input);

    // Check if input can be parsed as a valid number
    const num = Number.parseFloat(input);
    if (!Number.isNaN(num) && min <= num && num <= max) {
      onChange?.(num);
    }
  };

  const handlePointerDown =
    (diff: number) => (event: React.PointerEvent<HTMLButtonElement>) => {
      if (event.pointerType === "mouse") {
        event.preventDefault();
        inputRef.current?.focus();
      }
      const newVal = Math.min(Math.max(value + diff, min), max);
      onChange?.(newVal);
      setRawValue(String(newVal));
    };

  return (
    <div
      className={cn(
        "group flex items-stretch transition-[box-shadow] font-mono",
        className,
      )}
    >
      <button
        aria-label="Decrease"
        className="flex items-center pr-[.325em]"
        disabled={value <= min}
        onPointerDown={handlePointerDown(-1)}
        type="button"
        tabIndex={-1}
      >
        <Minus
          className="size-2"
          absoluteStrokeWidth
          strokeWidth={3.5}
          tabIndex={-1}
        />
      </button>
      <div className="relative grid items-center justify-items-center text-center">
        <input
          ref={inputRef}
          className="flex w-full max-w-full text-center transition-colors file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 p-0 border-0 h-6 text-xs !bg-transparent border-b border-transparent focus:border-border [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [-moz-appearance:textfield]"
          style={{ fontKerning: "none" }}
          type="number"
          min={min}
          max={max}
          autoComplete="off"
          step={step}
          value={rawValue === "0" ? "" : rawValue}
          placeholder={placeholder}
          onInput={handleInput}
          onBlur={onBlur}
          onFocus={onFocus}
          inputMode="decimal"
        />
      </div>
      <button
        aria-label="Increase"
        className="flex items-center pl-[.325em]"
        disabled={value >= max}
        onPointerDown={handlePointerDown(1)}
        type="button"
        tabIndex={-1}
      >
        <Plus
          className="size-2"
          absoluteStrokeWidth
          strokeWidth={3.5}
          tabIndex={-1}
        />
      </button>
    </div>
  );
}
