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

type UseTabsProps = {
  initialTab: string;
  totalTabs: number;
  containerRef?: React.RefObject<HTMLElement | null>;
};

export function useTabs({ initialTab, totalTabs, containerRef }: UseTabsProps) {
  const [activeTab, setActiveTab] = useState(initialTab);
  const [visibleTabs, setVisibleTabs] = useState<number[]>(
    Array.from({ length: totalTabs }, (_, i) => i),
  );
  const [overflowTabs, setOverflowTabs] = useState<number[]>([]);
  const [allTabsHidden, setAllTabsHidden] = useState<boolean>(false);
  const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
  const tabLabelsRef = useRef<string[]>([]);
  const resizeTimeoutRef = useRef<number | undefined>(undefined);
  const [ready, setReady] = useState<boolean>(false);
  const hasCalculatedOnce = useRef(false);
  const lastWidthRef = useRef<number>(0);
  const originalOrderRef = useRef<number[]>([]);

  useEffect(() => {
    originalOrderRef.current = Array.from({ length: totalTabs }, (_, i) => i);
  }, [totalTabs]);

  const setTabRef = useCallback((element: HTMLButtonElement | null, index: number) => {
    tabRefs.current[index] = element;
    if (element) {
      const label = element.getAttribute('data-label');
      if (label) {
        tabLabelsRef.current[index] = label;
      }
    }
  }, []);

  const getTabId = useCallback((label: string, index: number) => {
    const cleanLabel = label.replace(/\s+/g, '-').toLowerCase();
    return `${cleanLabel}-${index}`;
  }, []);

  const focusTab = (index: number) => {
    const currentElement = tabRefs.current[index];
    if (currentElement) {
      currentElement.focus();
    }
  };

  const onTabSelect = useCallback((index: number) => {
    focusTab(index);
    const label = tabRefs.current[index]?.getAttribute('data-label');
    if (label) setActiveTab(label);
  }, []);

  const onTabClick = useCallback(
    (labelOrIndex: string | number) => {
      let clickedIndex: number;

      if (typeof labelOrIndex === 'string') {
        clickedIndex = tabRefs.current.findIndex(
          (ref) => ref?.getAttribute('data-label') === labelOrIndex,
        );
        if (clickedIndex === -1) return;
      } else {
        clickedIndex = labelOrIndex;
      }

      if (allTabsHidden) {
        const label = tabLabelsRef.current[clickedIndex];
        if (label) {
          setActiveTab(label);
          focusTab(clickedIndex);
        }
        return;
      }

      if (overflowTabs.includes(clickedIndex)) {
        const newVisibleTabs = [...visibleTabs];
        const newOverflowTabs = [...overflowTabs];

        const clickedIdxInOverflow = newOverflowTabs.indexOf(clickedIndex);
        if (clickedIdxInOverflow !== -1) {
          newOverflowTabs.splice(clickedIdxInOverflow, 1);
        }

        const lastVisible = newVisibleTabs.pop();
        if (lastVisible !== undefined) {
          newOverflowTabs.unshift(lastVisible);
        }

        newVisibleTabs.push(clickedIndex);

        setVisibleTabs(newVisibleTabs);
        setOverflowTabs(newOverflowTabs);

        requestAnimationFrame(() => {
          const label = tabRefs.current[clickedIndex]?.getAttribute('data-label');
          if (label) {
            setActiveTab(label);
            focusTab(clickedIndex);
          }
        });
      } else {
        const label = tabRefs.current[clickedIndex]?.getAttribute('data-label');
        if (label) {
          setActiveTab(label);
          focusTab(clickedIndex);
        }
      }
    },
    [visibleTabs, overflowTabs, allTabsHidden],
  );

  const handleKeyboard = useCallback(
    (event: React.KeyboardEvent, index: number) => {
      let newIndex = index;
      if (event.key === 'ArrowRight') {
        newIndex = (index + 1) % totalTabs;
      } else if (event.key === 'ArrowLeft') {
        newIndex = (index - 1 + totalTabs) % totalTabs;
      } else if (event.key === 'Home') {
        event.preventDefault();
        newIndex = 0;
      } else if (event.key === 'End') {
        event.preventDefault();
        newIndex = totalTabs - 1;
      } else {
        return;
      }
      onTabSelect(newIndex);
    },
    [totalTabs, onTabSelect],
  );

  const calculateVisibleTabs = useCallback(() => {
    const container = containerRef?.current;
    if (!container) return;

    const contentWrapper = container.closest('div');
    if (!contentWrapper) {
      setVisibleTabs(Array.from({ length: totalTabs }, (_, i) => i));
      setOverflowTabs([]);
      setAllTabsHidden(false);
      return;
    }

    const containerWidth = container.offsetWidth - 60;
    const tabElements = container.querySelectorAll('[role="tab"]');
    const moreButtonWidth = 80;
    const safetyMargin = 20;

    const tabWidths = Array.from(tabElements).map((el) => (el as HTMLElement).offsetWidth);
    const tabLabels = Array.from(tabElements).map((el) => el.getAttribute('data-label') || '');
    const tabTypes = Array.from(tabElements).map((el) => el.getAttribute('data-type') || '');

    const hasLongLabels = tabLabels.some((label) => label.length > 30);
    const minVisibleTabs = hasLongLabels ? 1 : 2;

    const activeTabIndex = tabRefs.current.findIndex(
      (ref) => ref?.getAttribute('data-label') === activeTab,
    );

    let currentWidth = 0;
    const visible: number[] = [];
    const overflow: number[] = [];

    let minTabsWidth = 0;
    Array.from({ length: minVisibleTabs }).forEach((_, i) => {
      if (i < tabWidths.length) {
        minTabsWidth += tabWidths[i] + (i > 0 ? moreButtonWidth + safetyMargin : 0);
      }
    });

    if (minTabsWidth > containerWidth) {
      setVisibleTabs([]);
      setOverflowTabs(Array.from({ length: totalTabs }, (_, i) => i));
      setAllTabsHidden(true);
      return;
    }

    const tabsByType = new Map<string, number[]>();
    Array.from({ length: totalTabs }).forEach((_, i) => {
      const type = tabTypes[i] || 'default';
      if (!tabsByType.has(type)) {
        tabsByType.set(type, []);
      }
      tabsByType.get(type)?.push(i);
    });

    tabsByType.forEach((tabIndices) => {
      let typeCurrentWidth = currentWidth;
      const typeVisible: number[] = [];
      const typeOverflow: number[] = [];

      tabIndices.slice(0, minVisibleTabs).forEach((tabIndex) => {
        const tabWidth = tabWidths[tabIndex];
        const projectedWidth =
          typeCurrentWidth +
          tabWidth +
          (typeVisible.length > 0 ? moreButtonWidth + safetyMargin : 0);

        if (projectedWidth <= containerWidth) {
          typeVisible.push(tabIndex);
          typeCurrentWidth += tabWidth;
        } else {
          typeOverflow.push(tabIndex);
        }
      });

      tabIndices.slice(minVisibleTabs).forEach((tabIndex) => {
        const tabWidth = tabWidths[tabIndex];
        const projectedWidth = typeCurrentWidth + tabWidth + moreButtonWidth + safetyMargin;

        if (projectedWidth <= containerWidth) {
          typeVisible.push(tabIndex);
          typeCurrentWidth += tabWidth;
        } else {
          typeOverflow.push(tabIndex);
        }
      });

      visible.push(...typeVisible);
      overflow.push(...typeOverflow);
      currentWidth = typeCurrentWidth;
    });

    if (activeTabIndex !== -1 && !visible.includes(activeTabIndex)) {
      if (visible.length > 0) {
        const removed = visible.pop();
        if (removed !== undefined) {
          overflow.unshift(removed);
        }
      }

      visible.push(activeTabIndex);
      const activeOverflowIndex = overflow.indexOf(activeTabIndex);
      if (activeOverflowIndex !== -1) overflow.splice(activeOverflowIndex, 1);
    }

    setVisibleTabs(visible);
    setOverflowTabs(overflow);
    setAllTabsHidden(visible.length === 0);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [containerRef, totalTabs]);

  useEffect(() => {
    if (!containerRef?.current) return;

    const ensureTabsReady = () => {
      const allTabsReady =
        tabRefs.current.length === totalTabs && tabRefs.current.every((tab) => tab?.offsetWidth);

      if (!allTabsReady) {
        resizeTimeoutRef.current = requestAnimationFrame(ensureTabsReady);
        return;
      }

      calculateVisibleTabs();
      hasCalculatedOnce.current = true;
    };

    resizeTimeoutRef.current = requestAnimationFrame(ensureTabsReady);

    let resizeTimeout: number;
    const handleResize = () => {
      if (!hasCalculatedOnce.current) return;

      if (resizeTimeout) {
        cancelAnimationFrame(resizeTimeout);
      }

      resizeTimeout = requestAnimationFrame(() => {
        if (resizeTimeoutRef.current) {
          cancelAnimationFrame(resizeTimeoutRef.current);
        }
        resizeTimeoutRef.current = requestAnimationFrame(() => {
          const container = containerRef?.current;
          if (!container) return;

          const currentWidth = container.offsetWidth;

          if (Math.abs(lastWidthRef.current - currentWidth) > 5) {
            lastWidthRef.current = currentWidth;
            calculateVisibleTabs();
          }
        });
      });
    };

    const resizeObserver = new ResizeObserver(handleResize);
    resizeObserver.observe(containerRef.current);
    window.addEventListener('resize', handleResize);

    return () => {
      resizeObserver.disconnect();
      window.removeEventListener('resize', handleResize);
      if (resizeTimeoutRef.current) {
        cancelAnimationFrame(resizeTimeoutRef.current);
      }
      if (resizeTimeout) {
        cancelAnimationFrame(resizeTimeout);
      }
    };
  }, [containerRef, totalTabs, calculateVisibleTabs]);

  useEffect(() => {
    const raf = requestAnimationFrame(() => {
      setReady(true);
      calculateVisibleTabs();
    });

    return () => cancelAnimationFrame(raf);
  }, [calculateVisibleTabs]);

  return {
    activeTab,
    setActiveTab,
    setTabRef,
    onTabClick,
    handleKeyboard,
    getTabId,
    visibleTabs,
    overflowTabs,
    ready,
    allTabsHidden,
  };
}
