/**
 * useResizablePanels
 * 
 * Hook for creating resizable panel layouts with drag-divider.
 * Supports LocalStorage persistence and min/max constraints.
 */

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

interface UseResizablePanelsOptions {
  /** Key for LocalStorage persistence */
  storageKey: string;
  /** Default width of left panel in percent (0-100) */
  defaultLeftWidth: number;
  /** Minimum width of left panel in percent */
  minLeftWidth: number;
  /** Maximum width of left panel in percent */
  maxLeftWidth: number;
  /** Direction of resize - horizontal or vertical */
  direction?: 'horizontal' | 'vertical';
}

interface UseResizablePanelsReturn {
  /** Current width/height of left/top panel in percent */
  leftWidth: number;
  /** Whether user is currently dragging the divider */
  isDragging: boolean;
  /** Handler for mouse down on divider */
  handleMouseDown: (e: React.MouseEvent) => void;
  /** Programmatically set the left width */
  setLeftWidth: (width: number) => void;
  /** Reset to default width */
  resetToDefault: () => void;
  /** Container ref to attach to the parent container */
  containerRef: React.RefObject<HTMLDivElement>;
}

export function useResizablePanels({
  storageKey,
  defaultLeftWidth,
  minLeftWidth,
  maxLeftWidth,
  direction = 'horizontal',
}: UseResizablePanelsOptions): UseResizablePanelsReturn {
  // Initialize from LocalStorage or default
  const [leftWidth, setLeftWidthState] = useState<number>(() => {
    try {
      const stored = localStorage.getItem(storageKey);
      if (stored) {
        const parsed = parseFloat(stored);
        if (!isNaN(parsed) && parsed >= minLeftWidth && parsed <= maxLeftWidth) {
          return parsed;
        }
      }
    } catch {
      // Ignore localStorage errors
    }
    return defaultLeftWidth;
  });

  const [isDragging, setIsDragging] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);
  
  // Store start position and width for drag calculation
  const dragStartRef = useRef<{
    startPos: number;
    startWidth: number;
    containerSize: number;
  } | null>(null);

  // Set width with clamping and persistence
  const setLeftWidth = useCallback((width: number) => {
    const clampedWidth = Math.max(minLeftWidth, Math.min(maxLeftWidth, width));
    setLeftWidthState(clampedWidth);
    
    // Persist to LocalStorage
    try {
      localStorage.setItem(storageKey, clampedWidth.toString());
    } catch {
      // Ignore localStorage errors
    }
  }, [storageKey, minLeftWidth, maxLeftWidth]);

  // Reset to default
  const resetToDefault = useCallback(() => {
    setLeftWidth(defaultLeftWidth);
  }, [defaultLeftWidth, setLeftWidth]);

  // Mouse down handler for starting drag
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    
    const container = containerRef.current;
    if (!container) return;
    
    const containerRect = container.getBoundingClientRect();
    const containerSize = direction === 'horizontal' 
      ? containerRect.width 
      : containerRect.height;
    
    const startPos = direction === 'horizontal' ? e.clientX : e.clientY;
    
    dragStartRef.current = {
      startPos,
      startWidth: leftWidth,
      containerSize,
    };
    
    setIsDragging(true);
  }, [leftWidth, direction]);

  // Handle mouse move during drag
  useEffect(() => {
    if (!isDragging) return;

    const handleMouseMove = (e: MouseEvent) => {
      if (!dragStartRef.current || !containerRef.current) return;
      
      const { startPos, startWidth, containerSize } = dragStartRef.current;
      const currentPos = direction === 'horizontal' ? e.clientX : e.clientY;
      
      // Calculate delta in pixels and convert to percent
      const deltaPixels = currentPos - startPos;
      const deltaPercent = (deltaPixels / containerSize) * 100;
      
      // Calculate new width
      const newWidth = startWidth + deltaPercent;
      
      // Clamp between min and max
      const clampedWidth = Math.max(minLeftWidth, Math.min(maxLeftWidth, newWidth));
      setLeftWidthState(clampedWidth);
    };

    const handleMouseUp = () => {
      setIsDragging(false);
      dragStartRef.current = null;
      
      // Persist final width to LocalStorage
      try {
        localStorage.setItem(storageKey, leftWidth.toString());
      } catch {
        // Ignore localStorage errors
      }
    };

    // Add event listeners to document for capturing mouse events outside container
    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
    
    // Add cursor style to body during drag
    document.body.style.cursor = direction === 'horizontal' ? 'col-resize' : 'row-resize';
    document.body.style.userSelect = 'none';

    return () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    };
  }, [isDragging, leftWidth, direction, storageKey, minLeftWidth, maxLeftWidth]);

  // Save to localStorage when leftWidth changes (debounced by drag end)
  useEffect(() => {
    // Only save when not dragging (save happens on mouse up)
    if (!isDragging) {
      try {
        localStorage.setItem(storageKey, leftWidth.toString());
      } catch {
        // Ignore localStorage errors
      }
    }
  }, [leftWidth, isDragging, storageKey]);

  return {
    leftWidth,
    isDragging,
    handleMouseDown,
    setLeftWidth,
    resetToDefault,
    containerRef,
  };
}

export default useResizablePanels;
