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

interface UseCollapseOptions {
  containerRef: React.RefObject<HTMLDivElement>;
  width: string;
  minWidthThreshold?: number;
  collapsible: boolean;
  defaultCollapsed: boolean;
  siblingMinWidth: number;
  onCollapseChange?: (collapsed: boolean) => void;
}

interface CollapseState {
  isCollapsed: boolean;
  isInitialized: boolean;
  transitionsEnabled: boolean;
}

export const useCollapse = ({
  containerRef,
  width,
  minWidthThreshold,
  collapsible,
  defaultCollapsed,
  siblingMinWidth,
  onCollapseChange,
}: UseCollapseOptions): {
  toggleCollapse: () => void;
  isCollapsed: boolean;
  isInitialized: boolean;
  transitionsEnabled: boolean;
} => {
  // Determine threshold for auto-collapse
  let threshold: number | undefined;
  let enableAutoCollapse = collapsible;

  if (minWidthThreshold !== undefined) {
    threshold = minWidthThreshold;
  } else if (width.endsWith('px')) {
    threshold = parseInt(width, 10);
  } else {
    // Width is not in px and no explicit threshold provided
    // Disable auto-collapse (manual collapse still works if collapsible=true)
    enableAutoCollapse = false;
  }

  const userCollapsedRef = useRef<boolean>(defaultCollapsed);
  const autoCollapsedRef = useRef<boolean>(false);
  const userExpandedRef = useRef<boolean>(false);
  const initializedRef = useRef<boolean>(false);

  const [state, setState] = useState<CollapseState>(() => ({
    isCollapsed: defaultCollapsed,
    isInitialized: false,
    transitionsEnabled: false,
  }));

  // Handle size observation and initialization
  useEffect(() => {
    if (
      !enableAutoCollapse ||
      !containerRef.current ||
      threshold === undefined
    ) {
      if (!enableAutoCollapse && !state.isInitialized) {
        setState((prev) => ({
          ...prev,
          isInitialized: true,
          transitionsEnabled: true,
        }));
      }
      return;
    }

    const parentElement = containerRef.current.parentElement;
    if (!parentElement) {
      return;
    }

    let timeoutId: NodeJS.Timeout | null = null;

    const checkSize = (availableWidth: number): void => {
      const requiredWidthExpanded = siblingMinWidth + threshold!;
      const shouldCollapse = availableWidth < requiredWidthExpanded;

      if (!initializedRef.current) {
        initializedRef.current = true;
        if (shouldCollapse && !defaultCollapsed) {
          autoCollapsedRef.current = true;
        }
        setState({
          isCollapsed: shouldCollapse || defaultCollapsed,
          isInitialized: true,
          transitionsEnabled: false,
        });
        return;
      }

      if (
        shouldCollapse &&
        !state.isCollapsed &&
        !userCollapsedRef.current &&
        !userExpandedRef.current
      ) {
        setState((prev) => ({ ...prev, isCollapsed: true }));
        autoCollapsedRef.current = true;
        onCollapseChange?.(true);
      } else if (
        !shouldCollapse &&
        state.isCollapsed &&
        autoCollapsedRef.current &&
        !userCollapsedRef.current
      ) {
        setState((prev) => ({ ...prev, isCollapsed: false }));
        autoCollapsedRef.current = false;
        userExpandedRef.current = false;
        onCollapseChange?.(false);
      }

      if (!shouldCollapse && !state.isCollapsed) {
        userExpandedRef.current = false;
      }
    };

    const resizeObserver = new ResizeObserver((entries) => {
      if (timeoutId !== null) {
        clearTimeout(timeoutId);
      }

      // Delay the check to avoid rapid toggling during quick resizes, run immediately on first init
      const delay = initializedRef.current ? 100 : 0;

      timeoutId = setTimeout(() => {
        for (const entry of entries) {
          checkSize(entry.contentRect.width);
        }
        timeoutId = null;
      }, delay);
    });

    resizeObserver.observe(parentElement);

    return () => {
      if (timeoutId !== null) {
        clearTimeout(timeoutId);
      }
      resizeObserver.disconnect();
    };
  }, [
    enableAutoCollapse,
    threshold,
    state.isCollapsed,
    state.isInitialized,
    containerRef,
    siblingMinWidth,
    defaultCollapsed,
    onCollapseChange,
  ]);

  // Enable transitions after the first render with correct state has painted
  useEffect(() => {
    if (state.isInitialized && !state.transitionsEnabled) {
      const rafId = requestAnimationFrame(() => {
        setState((prev) => ({ ...prev, transitionsEnabled: true }));
      });
      return () => cancelAnimationFrame(rafId);
    }
  }, [state.isInitialized, state.transitionsEnabled]);

  const toggleCollapse = (): void => {
    const newState = !state.isCollapsed;
    setState((prev) => ({ ...prev, isCollapsed: newState }));

    if (newState) {
      userCollapsedRef.current = true;
      userExpandedRef.current = false;
      autoCollapsedRef.current = false;
    } else {
      userCollapsedRef.current = false;
      userExpandedRef.current = true;
      autoCollapsedRef.current = false;

      // TODO: Temporarily disable auto-scrolling to prevent jarring experience when collapsing/expanding panels in smaller screens.
      // to be revisited with https://dev.azure.com/axinom/CMS/_workitems/edit/53479/
      // setTimeout(() => {
      //   containerRef.current?.scrollIntoView({
      //     behavior: 'smooth',
      //     block: 'nearest',
      //     inline: 'end',
      //   });
      // }, 350);
    }

    onCollapseChange?.(newState);
  };

  return {
    toggleCollapse,
    isCollapsed: state.isCollapsed,
    isInitialized: state.isInitialized,
    transitionsEnabled: state.transitionsEnabled,
  };
};
