import { Box, Tab, Tabs } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { useListContext, useResourceContext } from 'react-admin';
import { ReactElement, useCallback, useEffect, useMemo, useRef } from 'react';
import { useListViewContext } from './ListViewProvider';
import { useSessionStorage } from '@/hooks';
import { useSearchParams } from 'react-router-dom';
import _ from 'lodash';

type ListTabToolbarConfig = {
  label: string;
  key: string;
  icon?: ReactElement;
  filter: Record<string, any>;
  default?: boolean;
};

interface ListTabsToolbarProps {
  tabs?: ListTabToolbarConfig[];
}

interface TabFilterState {
  filterValues: Record<string, any>;
  displayedFilters: Record<string, any>;
}

function useListTabs(tabs: ListTabToolbarConfig[]) {
  const [searchParams] = useSearchParams();
  const resource = useResourceContext();
  const { setCurrentTabKey } = useListViewContext();
  const { filterValues, displayedFilters, setFilters } = useListContext();

  const resourceKey = useMemo(() => resource.replace(/^entities\//, ''), [resource]);
  const tabGroupKey = `${resourceKey}-tab-group`;
  const tabFiltersKey = `${resourceKey}-tab-filters`;

  const defaultTabIndex = useMemo(() => tabs.findIndex((tab) => tab.default) ?? 0, [tabs]);

  const [currentTab, setCurrentTab] = useSessionStorage(tabGroupKey, defaultTabIndex) as [number, (v: number) => void];
  const [tabFilterStates, setTabFilterStates] = useSessionStorage(tabFiltersKey, {}) as [
    Record<string, TabFilterState>,
    (v: any) => void
  ];

  const initialized = useRef(false);
  const switchingTab = useRef(false);

  const handleTabChange = useCallback(
    (index: number) => {
      const tab = tabs[index];
      if (!tab) return;

      setCurrentTab(index);
      setCurrentTabKey?.(tab.key);

      const savedState = tabFilterStates?.[tab.key];
      const nextFilters = savedState?.filterValues ?? tab.filter;
      const nextDisplayed = savedState?.displayedFilters ?? {};

      if (!_.isEqual(nextFilters, filterValues) || !_.isEqual(nextDisplayed, displayedFilters)) {
        switchingTab.current = true;
        setFilters(nextFilters, nextDisplayed);
      }
    },
    [tabs, tabFilterStates, filterValues, displayedFilters, setCurrentTab, setCurrentTabKey, setFilters]
  );

  useEffect(() => {
    if (initialized.current) return;
    initialized.current = true;

    const param = searchParams.get(tabGroupKey);
    const initialIndex = param != null ? Number(param) : Number(currentTab);
    const hasUrlFilter = searchParams.get('filter') !== null;

    if (hasUrlFilter) {
      setCurrentTab(initialIndex);
      setCurrentTabKey?.(tabs[initialIndex]?.key);
    } else {
      handleTabChange(initialIndex);
    }
  }, [searchParams, tabGroupKey, currentTab, setCurrentTab, setCurrentTabKey, handleTabChange, tabs]);

  useEffect(() => {
    if (!initialized.current || switchingTab.current) {
      switchingTab.current = false;
      return;
    }

    const currentTabKey = tabs[Number(currentTab)]?.key;
    if (!currentTabKey) return;

    setTabFilterStates((prev: Record<string, TabFilterState>) => {
      const prevState = prev?.[currentTabKey];
      if (
        _.isEqual(prevState?.filterValues, filterValues) &&
        _.isEqual(prevState?.displayedFilters, displayedFilters)
      ) {
        return prev;
      }
      return {
        ...prev,
        [currentTabKey]: { filterValues, displayedFilters }
      };
    });
  }, [filterValues, displayedFilters, currentTab, tabs, setTabFilterStates]);

  return {
    currentTab,
    handleTabChange: (_: any, val: number) => handleTabChange(val)
  };
}

function ListTabsToolbar({ tabs = [] }: ListTabsToolbarProps) {
  const theme = useTheme();
  const { currentTab, handleTabChange } = useListTabs(tabs);

  if (tabs.length > 0 && tabs.some((tab) => !tab.key)) {
    throw new Error('ListTabsToolbar: Each tab must have a unique key.');
  }

  if (tabs.length === 0) return null;

  return (
    <Box sx={{ width: '100%' }}>
      <Tabs
        value={Number(currentTab)}
        onChange={handleTabChange}
        allowScrollButtonsMobile
        variant="scrollable"
        scrollButtons="auto"
        sx={{
          width: '100%',
          '.MuiTabs-scrollButtons.Mui-disabled': {
            opacity: 0.2
          }
        }}
      >
        {tabs.map((tab) => (
          <Tab
            icon={tab.icon}
            key={tab.key}
            label={tab.label}
            sx={{
              flex: '0 0 auto',
              lineHeight: 1,
              whiteSpace: 'nowrap',
              overflow: 'hidden',
              textOverflow: 'ellipsis',
              '& .MuiTab-iconWrapper': {
                marginRight: theme.spacing(0.5)
              }
            }}
          />
        ))}
      </Tabs>
    </Box>
  );
}

export { type ListTabToolbarConfig, ListTabsToolbar };
