import { useState, useCallback, useRef, useEffect } from 'react';

const useFaderHelpers = (options = {}) => {
  const {
    orientation = 'vertical',
    initialValue = 50,
    value: controlledValue,
    onChange,
    floaterConverter,
    snap = false,
    minValue = 0,
    maxValue = 100,
  } = options;

  const isControlled = controlledValue !== undefined;
  const [internalValue, setInternalValue] = useState(isControlled ? controlledValue : initialValue);
  const [isDragging, setIsDragging] = useState(false);
  const [floaterValue, setFloaterValue] = useState('');

  const faderRef = useRef(null);
  const handleRef = useRef(null);

  const currentValue = isControlled ? controlledValue : internalValue;

  // Calculate percentage from value
  const getPercentage = useCallback((val) => {
    return ((val - minValue) / (maxValue - minValue)) * 100;
  }, [minValue, maxValue]);

  // Calculate value from percentage
  const getValueFromPercentage = useCallback((percentage) => {
    return Math.round(minValue + (maxValue - minValue) * (percentage / 100));
  }, [minValue, maxValue]);

  // Calculate percentage from mouse position
  const getPercentageFromPosition = useCallback((clientPos) => {
    if (!faderRef.current) return currentValue;

    const rect = faderRef.current.getBoundingClientRect();
    let position, size;

    if (orientation === 'horizontal') {
      position = clientPos - rect.left;
      size = rect.width;
    } else {
      position = rect.bottom - clientPos;
      size = rect.height;
    }

    const percentage = Math.max(0, Math.min(100, (position / size) * 100));
    return percentage;
  }, [orientation, currentValue]);

  // Handle value change
  const handleValueChange = useCallback((newValue, dragging = false) => {
    const clampedValue = Math.max(minValue, Math.min(maxValue, newValue));

    if (isControlled) {
      onChange && onChange(clampedValue, dragging);
    } else {
      setInternalValue(clampedValue);
    }

    // Update floater if converter provided
    if (floaterConverter) {
      setFloaterValue(floaterConverter(getPercentage(clampedValue)));
    }
  }, [minValue, maxValue, isControlled, onChange, floaterConverter, getPercentage]);

  // Mouse move handler
  const handleMouseMove = useCallback((e) => {
    const percentage = getPercentageFromPosition(orientation === 'vertical' ? e.clientY : e.clientX);

    // Snap to center if enabled
    let finalPercentage = percentage;
    if (snap && percentage > 46 && percentage < 54) {
      finalPercentage = 50;
    }

    const newValue = getValueFromPercentage(finalPercentage);
    handleValueChange(newValue, true);
  }, [getPercentageFromPosition, orientation, snap, getValueFromPercentage, handleValueChange]);

  // Mouse up handler
  const handleMouseUp = useCallback(() => {
    setIsDragging(false);
    window.removeEventListener('mousemove', handleMouseMove);
    window.removeEventListener('mouseup', handleMouseUp);
  }, [handleMouseMove]);

  // Mouse down handler
  const handleMouseDown = useCallback((e) => {
    e.preventDefault();
    setIsDragging(true);
    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseup', handleMouseUp);
  }, [handleMouseMove, handleMouseUp]);

  // Click handler for jumping to position
  const handleClick = useCallback((e) => {
    const percentage = getPercentageFromPosition(orientation === 'vertical' ? e.clientY : e.clientX);
    const newValue = getValueFromPercentage(percentage);
    handleValueChange(newValue, false);
  }, [getPercentageFromPosition, orientation, getValueFromPercentage, handleValueChange]);

  // Set value programmatically
  const setValue = useCallback((newValue) => {
    handleValueChange(newValue, false);
  }, [handleValueChange]);

  // Get handle position style
  const getHandleStyle = useCallback(() => {
    const percentage = getPercentage(currentValue);
    const position = orientation === 'horizontal'
      ? { left: `${percentage}%` }
      : { bottom: `${percentage}%` };
    return position;
  }, [currentValue, getPercentage, orientation]);

  // Update floater on value change
  useEffect(() => {
    if (floaterConverter) {
      setFloaterValue(floaterConverter(getPercentage(currentValue)));
    }
  }, [currentValue, floaterConverter, getPercentage]);

  // Utility functions
  const convertLinearToDb = (input) => {
    if (input <= 1) return -80;
    if (input >= 99) return 20;

    const a = -8.0013990435159329E+01;
    const b = 4.1755639785242042E+00;
    const c = -1.4036729740086906E-01;
    const d = 3.1788545454166156E-03;
    const f = -3.5148685730880861E-05;
    const g = 1.4221429222004657E-07;

    return a + b * input + c * Math.pow(input, 2) + d * Math.pow(input, 3) +
           f * Math.pow(input, 4) + g * Math.pow(input, 5);
  };

  const convertPercentToAudioTaper = (input) => {
    if (input <= 1) return -80;
    if (input <= 28) return Math.round(2 * input - 80);
    if (input <= 79) return Math.round(0.5 * input - 38);
    if (input < 99) return Math.round(0.875 * input - 67.5);
    return 20;
  };

  const convertAudioTaperToPercent = (db) => {
    //console.log("convertAudioTaperToPercent: db", db);
    if (db <= -78) return 0;
    if (db <= -24) return (db + 80) / 2;
    if (db <= 1.5) return (db + 38) / 0.5;
    if (db <= 19.125) return (db + 67.5) / 0.875;
    return 100;
  };

  return {
    value: currentValue,
    percentage: getPercentage(currentValue),
    isDragging,
    floaterValue,
    faderRef,
    handleRef,
    handleMouseDown,
    handleClick,
    setValue,
    getHandleStyle,
    convertLinearToDb,
    convertPercentToAudioTaper,
    convertAudioTaperToPercent,
  };
};

export default useFaderHelpers;
