import React, {
  ReactElement,
  useCallback,
  useEffect,
  useRef,
  useState,
} from 'react';
import {
  Box,
  IconButton,
  ListItemAction,
  Popover,
  Text,
  TextButton,
  Thumbnail,
} from '@wix/design-system';
import {
  ChevronLeft,
  DataCollection,
  MoreSmall,
} from '@wix/wix-ui-icons-common';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { ViewTypeState } from '../../state/ViewTypeState';
import {
  layoutOptions,
  layoutConfig,
} from '../TableGridSwitchButton/layoutConfig';

type Translate = ReturnType<typeof useWixPatternsContainer>['translate'];
type Focusable = { focus: () => void };

export interface ToolbarOverflowPrimaryItem {
  text: string;
  icon: ReactElement;
  onClick: () => void;
  dataHook?: string;
}

export interface ToolbarOverflowSecondaryItem {
  text: string;
  prefixIcon: ReactElement;
  onClick: () => void;
  dataHook?: string;
}

export interface ToolbarOverflowLayoutSwitchConfig {
  viewTypeState: ViewTypeState;
}

type ActiveView = 'main' | 'layout';

export interface ToolbarOverflowMenuProps {
  primaryItems: ToolbarOverflowPrimaryItem[];
  secondaryItems: ToolbarOverflowSecondaryItem[];
  layoutSwitchConfig?: ToolbarOverflowLayoutSwitchConfig;
}

export function ToolbarOverflowMenu({
  primaryItems,
  secondaryItems,
  layoutSwitchConfig,
}: ToolbarOverflowMenuProps) {
  const [shown, setShown] = useState(false);
  const [activeView, setActiveView] = useState<ActiveView>('main');
  const triggerRef = useRef<HTMLButtonElement>(null);
  const focusTargetRef = useRef<'first' | 'layoutSwitch' | null>(null);
  const { translate: t } = useWixPatternsContainer();

  const shouldFocusTriggerOnCloseRef = useRef(false);

  const close = useCallback(() => {
    setShown(false);
    setActiveView('main');
  }, []);

  const closeAndFocusTrigger = useCallback(() => {
    shouldFocusTriggerOnCloseRef.current = true;
    close();
  }, [close]);

  useEffect(() => {
    if (!shown && shouldFocusTriggerOnCloseRef.current) {
      shouldFocusTriggerOnCloseRef.current = false;
      setTimeout(() => {
        triggerRef.current?.focus();
      });
    }
  }, [shown]);

  const hasItems =
    primaryItems.length > 0 ||
    secondaryItems.length > 0 ||
    !!layoutSwitchConfig;

  if (!hasItems) {
    return null;
  }

  return (
    <Popover
      dataHook="toolbar-overflow-menu"
      shown={shown}
      placement="bottom"
      showArrow
      flip
      appendTo="parent"
      onClickOutside={closeAndFocusTrigger}
      onEscPress={closeAndFocusTrigger}
      onTabOut={close}
      zIndex={1101}
    >
      <Popover.Element>
        <IconButton
          ref={triggerRef}
          size="small"
          skin="inverted"
          dataHook="toolbar-overflow-menu-trigger"
          aria-label={t('cairo.moreActions')}
          onClick={() => {
            setShown((prev) => {
              if (!prev) {
                focusTargetRef.current = 'first';
              }
              return !prev;
            });
          }}
        >
          <MoreSmall />
        </IconButton>
      </Popover.Element>
      <Popover.Content>
        <Box
          dataHook="toolbar-overflow-menu-content"
          direction="vertical"
          minWidth={activeView === 'main' ? '300px' : '184px'}
          paddingTop="SP1"
          paddingBottom="SP1"
        >
          {activeView === 'main' ? (
            <MainView
              primaryItems={primaryItems}
              secondaryItems={secondaryItems}
              layoutSwitchConfig={layoutSwitchConfig}
              onItemClick={closeAndFocusTrigger}
              onLayoutSwitchClick={() => setActiveView('layout')}
              focusTarget={focusTargetRef}
              t={t}
            />
          ) : (
            <LayoutSwitchView
              config={layoutSwitchConfig!}
              onBack={() => {
                focusTargetRef.current = 'layoutSwitch';
                setActiveView('main');
              }}
              onSelect={closeAndFocusTrigger}
              t={t}
            />
          )}
        </Box>
      </Popover.Content>
    </Popover>
  );
}

function MainView({
  primaryItems,
  secondaryItems,
  layoutSwitchConfig,
  onItemClick,
  onLayoutSwitchClick,
  focusTarget,
  t,
}: {
  primaryItems: ToolbarOverflowPrimaryItem[];
  secondaryItems: ToolbarOverflowSecondaryItem[];
  layoutSwitchConfig?: ToolbarOverflowLayoutSwitchConfig;
  onItemClick: () => void;
  onLayoutSwitchClick: () => void;
  focusTarget: React.MutableRefObject<'first' | 'layoutSwitch' | null>;
  t: Translate;
}) {
  const firstItemRef = useRef<Focusable | null>(null);
  const layoutSwitchRef = useRef<Focusable | null>(null);

  useEffect(() => {
    const target = focusTarget.current;
    focusTarget.current = null;

    if (target === 'first') {
      firstItemRef.current?.focus();
    } else if (target === 'layoutSwitch') {
      layoutSwitchRef.current?.focus();
    }
  });

  const isFirstItemPrimary = primaryItems.length > 0;

  return (
    <>
      {primaryItems.length > 0 && (
        <Box direction="horizontal" gap="SP2" padding="SP2">
          {primaryItems.map((item, index) => (
            <Box key={index} flex={1} minWidth={0}>
              <Thumbnail
                ref={index === 0 ? (firstItemRef as any) : undefined}
                size="tiny"
                skin="secondary"
                image={item.icon}
                onClick={() => {
                  item.onClick();
                  onItemClick();
                }}
                dataHook={item.dataHook}
                title={
                  <Text size="medium" weight="thin">
                    {item.text}
                  </Text>
                }
                width="100%"
              />
            </Box>
          ))}
        </Box>
      )}
      {layoutSwitchConfig && (
        <ListItemAction
          ref={
            !isFirstItemPrimary
              ? (r) => {
                  layoutSwitchRef.current = r;
                  if (!firstItemRef.current) {
                    firstItemRef.current = r;
                  }
                }
              : layoutSwitchRef
          }
          size="medium"
          dataHook="overflow-layout-switch"
          prefixIcon={<DataCollection />}
          title={t('cairo.table.layout.switchLayout')}
          onClick={() => {
            layoutSwitchConfig.viewTypeState.reportLayoutSwitch();
            onLayoutSwitchClick();
          }}
        />
      )}
      {secondaryItems.map((item, index) => (
        <ListItemAction
          key={index}
          ref={
            !isFirstItemPrimary && !layoutSwitchConfig && index === 0
              ? firstItemRef
              : undefined
          }
          size="medium"
          title={item.text}
          onClick={() => {
            item.onClick();
            onItemClick();
          }}
          prefixIcon={item.prefixIcon}
          dataHook={item.dataHook}
        />
      ))}
    </>
  );
}

function LayoutSwitchView({
  config,
  onBack,
  onSelect,
  t,
}: {
  config: ToolbarOverflowLayoutSwitchConfig;
  onBack: () => void;
  onSelect: () => void;
  t: Translate;
}) {
  const { viewTypeState } = config;
  const activeOptionRef = useRef<Focusable>(null);

  useEffect(() => {
    activeOptionRef.current?.focus();
  }, []);

  return (
    <>
      <Box padding="SP1 SP3">
        <TextButton
          size="small"
          dataHook="overflow-layout-switch-back"
          prefixIcon={<ChevronLeft />}
          onClick={onBack}
        >
          {t('cairo.import.back')}
        </TextButton>
      </Box>
      {layoutOptions.map((option, index) => {
        const isActive = viewTypeState.viewType === option;
        return (
          <ListItemAction
            key={option}
            ref={isActive ? activeOptionRef : undefined}
            size="medium"
            dataHook={`overflow-layout-option-${option}`}
            prefixIcon={layoutConfig[option].icon as ReactElement}
            title={t(layoutConfig[option].translationKey)}
            highlighted={isActive ? true : undefined}
            onClick={() => {
              viewTypeState.reportLayoutOptionClicked(option, index);
              if (!isActive) {
                viewTypeState.changeViewType(option);
              }
              onSelect();
            }}
          />
        );
      })}
    </>
  );
}
