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

interface Position {
  x: number;
  y: number;
}

interface UseDraggableOptions {
  initialPosition?: Position;
  bounds?: 'parent' | 'window' | { left: number; top: number; right: number; bottom: number };
  onDragStart?: () => void;
  onDragEnd?: (position: Position) => void;
  disabled?: boolean;
}

interface UseDraggableReturn {
  position: Position;
  isDragging: boolean;
  dragHandleProps: {
    onMouseDown: (e: React.MouseEvent) => void;
    onTouchStart: (e: React.TouchEvent) => void;
    style: React.CSSProperties;
  };
  elementRef: React.RefObject<HTMLDivElement>;
  setPosition: (pos: Position) => void;
  resetPosition: () => void;
}

const STORAGE_KEY = 'zeiterfassung_pip_position';

// Default position: bottom-right corner with some padding
const getDefaultPosition = (): Position => {
  if (typeof window === 'undefined') return { x: 0, y: 0 };
  return {
    x: window.innerWidth - 420, // 400px width + 20px padding
    y: window.innerHeight - 350, // ~300px height + 50px padding
  };
};

export function useDraggable(options: UseDraggableOptions = {}): UseDraggableReturn {
  const {
    initialPosition,
    bounds = 'window',
    onDragStart,
    onDragEnd,
    disabled = false,
  } = options;

  // Try to load saved position from localStorage
  const getSavedPosition = useCallback((): Position | null => {
    try {
      const saved = localStorage.getItem(STORAGE_KEY);
      if (saved) {
        const pos = JSON.parse(saved);
        // Validate position is within bounds
        if (typeof pos.x === 'number' && typeof pos.y === 'number') {
          return pos;
        }
      }
    } catch {
      // Ignore parsing errors
    }
    return null;
  }, []);

  const getInitialPosition = useCallback((): Position => {
    // Priority: initialPosition > saved > default
    if (initialPosition && initialPosition.x !== -1 && initialPosition.y !== -1) {
      return initialPosition;
    }
    const saved = getSavedPosition();
    if (saved) {
      return saved;
    }
    return getDefaultPosition();
  }, [initialPosition, getSavedPosition]);

  const [position, setPositionState] = useState<Position>(getInitialPosition);
  const [isDragging, setIsDragging] = useState(false);

  const elementRef = useRef<HTMLDivElement>(null);
  const dragStartPos = useRef<Position>({ x: 0, y: 0 });
  const elementStartPos = useRef<Position>({ x: 0, y: 0 });

  // Clamp position to bounds
  const clampPosition = useCallback((pos: Position): Position => {
    if (typeof window === 'undefined' || !elementRef.current) return pos;

    const element = elementRef.current;
    const rect = element.getBoundingClientRect();
    let minX = 0;
    let minY = 0;
    let maxX = window.innerWidth - rect.width;
    let maxY = window.innerHeight - rect.height;

    if (typeof bounds === 'object') {
      minX = bounds.left;
      minY = bounds.top;
      maxX = bounds.right - rect.width;
      maxY = bounds.bottom - rect.height;
    }

    return {
      x: Math.max(minX, Math.min(maxX, pos.x)),
      y: Math.max(minY, Math.min(maxY, pos.y)),
    };
  }, [bounds]);

  // Set position with clamping and save
  const setPosition = useCallback((pos: Position) => {
    const clamped = clampPosition(pos);
    setPositionState(clamped);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(clamped));
  }, [clampPosition]);

  // Reset to default position
  const resetPosition = useCallback(() => {
    const defaultPos = getDefaultPosition();
    setPositionState(defaultPos);
    localStorage.removeItem(STORAGE_KEY);
  }, []);

  // Handle mouse/touch move
  const handleMove = useCallback((clientX: number, clientY: number) => {
    if (!isDragging) return;

    const deltaX = clientX - dragStartPos.current.x;
    const deltaY = clientY - dragStartPos.current.y;

    const newPos = clampPosition({
      x: elementStartPos.current.x + deltaX,
      y: elementStartPos.current.y + deltaY,
    });

    setPositionState(newPos);
  }, [isDragging, clampPosition]);

  // Handle drag end
  const handleEnd = useCallback(() => {
    if (!isDragging) return;

    setIsDragging(false);
    document.body.style.userSelect = '';
    document.body.style.cursor = '';

    // Save position
    localStorage.setItem(STORAGE_KEY, JSON.stringify(position));
    onDragEnd?.(position);
  }, [isDragging, position, onDragEnd]);

  // Mouse event handlers
  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      handleMove(e.clientX, e.clientY);
    };

    const handleMouseUp = () => {
      handleEnd();
    };

    if (isDragging) {
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
    }

    return () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };
  }, [isDragging, handleMove, handleEnd]);

  // Touch event handlers
  useEffect(() => {
    const handleTouchMove = (e: TouchEvent) => {
      if (e.touches.length === 1) {
        handleMove(e.touches[0].clientX, e.touches[0].clientY);
      }
    };

    const handleTouchEnd = () => {
      handleEnd();
    };

    if (isDragging) {
      document.addEventListener('touchmove', handleTouchMove, { passive: false });
      document.addEventListener('touchend', handleTouchEnd);
    }

    return () => {
      document.removeEventListener('touchmove', handleTouchMove);
      document.removeEventListener('touchend', handleTouchEnd);
    };
  }, [isDragging, handleMove, handleEnd]);

  // Handle window resize
  useEffect(() => {
    const handleResize = () => {
      setPositionState((prev) => clampPosition(prev));
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, [clampPosition]);

  // Start dragging (mouse)
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (disabled || e.button !== 0) return;

    e.preventDefault();
    setIsDragging(true);
    dragStartPos.current = { x: e.clientX, y: e.clientY };
    elementStartPos.current = { ...position };
    document.body.style.userSelect = 'none';
    document.body.style.cursor = 'grabbing';
    onDragStart?.();
  }, [disabled, position, onDragStart]);

  // Start dragging (touch)
  const handleTouchStart = useCallback((e: React.TouchEvent) => {
    if (disabled || e.touches.length !== 1) return;

    setIsDragging(true);
    dragStartPos.current = {
      x: e.touches[0].clientX,
      y: e.touches[0].clientY,
    };
    elementStartPos.current = { ...position };
    onDragStart?.();
  }, [disabled, position, onDragStart]);

  return {
    position,
    isDragging,
    dragHandleProps: {
      onMouseDown: handleMouseDown,
      onTouchStart: handleTouchStart,
      style: { cursor: disabled ? 'default' : isDragging ? 'grabbing' : 'grab' },
    },
    elementRef,
    setPosition,
    resetPosition,
  };
}

export default useDraggable;
