import { ref, onUnmounted } from 'vue';

/**
 * Creates a debounced version of a function
 * @param {Function} fn - The function to debounce
 * @param {number} delay - The delay in milliseconds
 * @returns {Function} - The debounced function
 */
export const useDebounceFn = (fn, delay = 300) => {
  if (typeof fn !== 'function') {
    throw new Error('First argument must be a function');
  }
  
  // Store the timeout ID for cleanup
  const timeoutId = ref(null);
  
  // Clean up any pending timeouts when the component is unmounted
  onUnmounted(() => {
    if (timeoutId.value) {
      clearTimeout(timeoutId.value);
    }
  });
  
  // Return the debounced function
  return (...args) => {
    // Clear previous timeout if exists
    if (timeoutId.value) {
      clearTimeout(timeoutId.value);
    }
    
    // Set a new timeout
    timeoutId.value = setTimeout(() => {
      fn(...args);
      timeoutId.value = null;
    }, delay);
  };
};

/**
 * Creates a throttled version of a function
 * @param {Function} fn - The function to throttle
 * @param {number} delay - The delay in milliseconds
 * @returns {Function} - The throttled function
 */
export const useThrottleFn = (fn, delay = 300) => {
  if (typeof fn !== 'function') {
    throw new Error('First argument must be a function');
  }
  
  // Store the last execution time
  const lastExecution = ref(0);
  // Store the timeout ID for cleanup
  const timeoutId = ref(null);
  
  // Clean up any pending timeouts when the component is unmounted
  onUnmounted(() => {
    if (timeoutId.value) {
      clearTimeout(timeoutId.value);
    }
  });
  
  // Return the throttled function
  return (...args) => {
    const now = Date.now();
    const elapsed = now - lastExecution.value;
    
    // Clear any existing timeout
    if (timeoutId.value) {
      clearTimeout(timeoutId.value);
    }
    
    // If enough time has passed, execute immediately
    if (elapsed >= delay) {
      lastExecution.value = now;
      fn(...args);
    } else {
      // Otherwise, schedule execution for when the delay has passed
      timeoutId.value = setTimeout(() => {
        lastExecution.value = Date.now();
        fn(...args);
        timeoutId.value = null;
      }, delay - elapsed);
    }
  };
};

export default useDebounceFn; 