import { IconButton, Input, Typography } from "@material-tailwind/react";
import {
  startTransition,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { FiMinus, FiPlus } from "react-icons/fi";
export type InputCartQuantityProps = {
  size: string;
  quantity?: number;
  maximumUserCanPurchase: number;
  isLoading?: boolean;
  canProductBeRemoved?: boolean;
  onQuantityChange?: (qty: number) => void;
  onErrorChange?: (hasError: boolean) => void;
  maxCartQuantity?: number | null;
  quantityStepper?: number | null;
};

export default function InputCartQuantity({
  size = "sm",
  quantity,
  maximumUserCanPurchase,
  isLoading,
  canProductBeRemoved,
  maxCartQuantity,
  quantityStepper = 1,
  onQuantityChange,
  onErrorChange,
}: InputCartQuantityProps) {
  //
  const [currentQty, setCurrentQty] = useState<number>();
  const [inputValue, setInputValue] = useState<string>("");
  const [hasError, setHasError] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string>("");
  const prevQuantityRef = useRef<number | undefined>(undefined);

  // Calculate min and max quantities
  const minQuantity = useMemo(() => {
    return 1 * (quantityStepper ?? 1);
  }, [quantityStepper]);

  const maxQuantity = useMemo(() => {
    return maximumUserCanPurchase === Infinity
      ? Infinity
      : maximumUserCanPurchase;
  }, [maximumUserCanPurchase]);

  // Update input value when quantity prop changes (from parent)
  useEffect(() => {
    if (quantity !== undefined && quantity !== prevQuantityRef.current) {
      prevQuantityRef.current = quantity;
      startTransition(() => {
        setCurrentQty(quantity);
        setInputValue(quantity.toString());
        setHasError(false);
        setErrorMessage("");
        onErrorChange?.(false);
      });
    }
  }, [quantity, onErrorChange]);

  const validateAndSetQuantity = useCallback(
    (value: string) => {
      // Allow empty string while typing
      if (value === "") {
        setInputValue("");
        setHasError(false);
        setErrorMessage("");
        onErrorChange?.(false);
        return;
      }

      // Check if it's a valid number
      const numValue = Number(value);
      if (isNaN(numValue) || !Number.isInteger(numValue)) {
        setHasError(true);
        setErrorMessage("Please enter a valid number");
        onErrorChange?.(true);
        return;
      }

      // Prevent typing 0 in the input (0 can only be set via decrement button)
      if (numValue === 0) {
        setHasError(true);
        setErrorMessage(`Minimum quantity is ${minQuantity}`);
        onErrorChange?.(true);
        // Reset to current quantity
        if (currentQty !== undefined) {
          setInputValue(currentQty.toString());
        }
        return;
      }

      // Check if value is less than minimum
      if (numValue < minQuantity) {
        setHasError(true);
        setErrorMessage(`Minimum quantity is ${minQuantity}`);
        onErrorChange?.(true);
        return;
      }

      // Check if value exceeds maximum
      if (maxQuantity !== Infinity && numValue > maxQuantity) {
        setHasError(true);
        setErrorMessage(`Maximum quantity is ${maxQuantity}`);
        onErrorChange?.(true);
        return;
      }

      // Check if value is a multiple of quantityStepper
      const stepper = quantityStepper ?? 1;
      if (stepper > 1 && numValue % stepper !== 0) {
        const nearestValid = Math.round(numValue / stepper) * stepper;
        setHasError(true);
        setErrorMessage(
          `Quantity must be a multiple of ${stepper}. Nearest valid: ${nearestValid}`,
        );
        onErrorChange?.(true);
        return;
      }

      // Check maxCartQuantity constraint
      if (maxCartQuantity && numValue > maxCartQuantity) {
        setHasError(true);
        setErrorMessage(`Maximum cart quantity is ${maxCartQuantity}`);
        onErrorChange?.(true);
        return;
      }

      // Valid value - update quantity
      setHasError(false);
      setErrorMessage("");
      onErrorChange?.(false);
      setCurrentQty(numValue);
      onQuantityChange?.(numValue);
    },
    [
      minQuantity,
      maxQuantity,
      quantityStepper,
      maxCartQuantity,
      currentQty,
      onQuantityChange,
      onErrorChange,
    ],
  );

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

    // Allow only digits and empty string, but prevent typing 0
    if (value === "" || (value !== "0" && /^\d+$/.test(value))) {
      setInputValue(value);

      // If empty, clear error
      if (value === "") {
        setHasError(false);
        setErrorMessage("");
        onErrorChange?.(false);
      }
    }
  };

  const handleInputBlur = () => {
    // If input is empty, reset to current quantity
    if (inputValue === "" && currentQty !== undefined) {
      setInputValue(currentQty.toString());
      setHasError(false);
      setErrorMessage("");
      onErrorChange?.(false);
      return;
    }

    // Validate and apply the value
    validateAndSetQuantity(inputValue);
  };

  const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    // Allow Enter key to trigger validation
    if (e.key === "Enter") {
      e.currentTarget.blur();
    }

    // Allow Escape to cancel and revert
    if (e.key === "Escape" && currentQty !== undefined) {
      setInputValue(currentQty.toString());
      setHasError(false);
      setErrorMessage("");
      onErrorChange?.(false);
      e.currentTarget.blur();
    }
  };

  const handleAddQty = useCallback(() => {
    if (!currentQty) return;
    if (maxCartQuantity && maxCartQuantity <= currentQty) return;

    const stepper = quantityStepper ?? 1;
    const newQuantity = Math.min(
      currentQty + stepper,
      maxQuantity === Infinity ? Infinity : maxQuantity,
    );

    // Check maxCartQuantity constraint
    const finalQuantity =
      maxCartQuantity && newQuantity > maxCartQuantity
        ? maxCartQuantity
        : newQuantity;

    setCurrentQty(finalQuantity);
    setInputValue(finalQuantity.toString());
    setHasError(false);
    setErrorMessage("");
    onErrorChange?.(false);
    onQuantityChange?.(finalQuantity);
  }, [
    currentQty,
    maxCartQuantity,
    quantityStepper,
    maxQuantity,
    onQuantityChange,
    onErrorChange,
  ]);

  const handleRemoveQty = useCallback(() => {
    if (!currentQty) return;

    const stepper = quantityStepper ?? 1;
    const newQuantity = currentQty - stepper;

    if (newQuantity < minQuantity) {
      if (!canProductBeRemoved) return;
      // If can be removed and newQuantity is 0 or less, allow 0
      const finalQuantity = Math.max(0, newQuantity);
      setCurrentQty(finalQuantity);
      setInputValue(finalQuantity.toString());
      setHasError(false);
      setErrorMessage("");
      onErrorChange?.(false);
      onQuantityChange?.(finalQuantity);
      return;
    }

    setCurrentQty(newQuantity);
    setInputValue(newQuantity.toString());
    setHasError(false);
    setErrorMessage("");
    onErrorChange?.(false);
    onQuantityChange?.(newQuantity);
  }, [
    currentQty,
    quantityStepper,
    minQuantity,
    canProductBeRemoved,
    onQuantityChange,
    onErrorChange,
  ]);

  const isIncrementDisabled = useMemo(() => {
    if (!currentQty) return true;
    if (isLoading || hasError) return true;
    if (maxCartQuantity && maxCartQuantity <= currentQty) return true;
    if (maxQuantity !== Infinity && currentQty >= maxQuantity) return true;
    return false;
  }, [currentQty, isLoading, hasError, maxCartQuantity, maxQuantity]);

  const isDecrementDisabled = useMemo(() => {
    if (currentQty === undefined || currentQty === null) return true;
    if (isLoading || hasError) return true;
    if (currentQty <= 0) return true; // Can't go below 0
    if (!canProductBeRemoved && currentQty <= minQuantity) return true;
    return false;
  }, [currentQty, isLoading, hasError, canProductBeRemoved, minQuantity]);

  const inputWidth = size === "lg" ? "w-[60px]" : "w-[35px]";
  const inputPadding = size === "lg" ? "py-[5px]" : "py-[2px]";
  const inputTextSize = size === "lg" ? "text-base" : "text-sm";

  return (
    <>
      <div className="flex flex-col gap-2 items-center justify-center ">
        <div
          className={`flex gap-1 items-center justify-end ${size === "lg" ? "gap-2 md:gap-2.5" : "md:gap-1.5"}`}
        >
          <IconButton
            variant="outlined"
            className={`flex border-slate-100 hover:border-slate-400 hover:bg-gray-100/20 focus:!border-slate-300 focus:ring-gray-300/30 text-slate-500 hover:text-black-500
                        ${size === "lg" ? "w-6 h-6 md:w-9 md:h-9" : "w-7 h-6"}
                        ${isDecrementDisabled ? "opacity-50 cursor-not-allowed" : ""}`}
            onClick={handleRemoveQty}
            disabled={isDecrementDisabled}
          >
            <FiMinus className="w-4 h-5" />
          </IconButton>
          <div className={`!min-w-0 ${inputWidth}`}>
            <Input
              type="text"
              value={inputValue || ""}
              onChange={handleInputChange}
              onBlur={handleInputBlur}
              onKeyDown={handleInputKeyDown}
              className={`!py-2 text-center ${inputTextSize} ${inputWidth} !border bg-white text-gray-900 shadow-gray-200/5 ring-4 ring-transparent placeholder:text-gray-500 placeholder:opacity-100 focus:ring-gray-300/10 shadow-none ${inputPadding} ${
                hasError
                  ? "!border-red-300 focus:!border-red-400 focus:!border-t-red-400"
                  : "!border-slate-100 focus:!border-slate-300 focus:!border-t-slate-300"
              }`}
              labelProps={{
                className: "hidden",
              }}
              containerProps={{ className: "!min-w-0" }}
              crossOrigin={undefined}
              tabIndex={0}
              disabled={isLoading}
            />
          </div>
          <IconButton
            variant="outlined"
            className={`flex border-slate-100 hover:border-slate-400 hover:bg-gray-100/20 focus:!border-slate-300 focus:ring-gray-300/30 text-slate-500 hover:text-black-500
                    ${size === "lg" ? "w-6 h-6 md:w-9 md:h-9" : "w-7 h-6"}
                    ${isIncrementDisabled ? "opacity-50 cursor-not-allowed" : ""}`}
            onClick={handleAddQty}
            disabled={isIncrementDisabled}
          >
            <FiPlus className="w-4 h-5" />
          </IconButton>
        </div>
        {hasError && errorMessage && (
          <Typography
            variant="small"
            className="text-xs font-medium text-red-500 text-right"
          >
            {errorMessage}
          </Typography>
        )}
      </div>
    </>
  );
}
