import { LocationDescriptor } from 'history';
import React, { useCallback, useMemo, useState } from 'react';
import { Data } from '../../../types';
import { IconName } from '../../Icons';
import { ListElement } from '../../List';
import {
  PageHeaderActionItemProps,
  PageHeaderActionType,
} from '../../PageHeader';
import { QuickEditConfig, QuickEditRegistration } from '../Explorer.model';
import { QuickEditContext } from './QuickEditContext';

export interface useQuickEditProps<T extends Data> {
  listRef: React.RefObject<ListElement>;
  registrations: QuickEditRegistration<T>[] | undefined;
  hasData: boolean;
  defaultItem: T;
  quickEditConfig?: QuickEditConfig;
  collapseFilters: () => void;
  generateItemLink?: (data: T) => LocationDescriptor<unknown>;
}

export interface useQuickEditReturnType<T extends Data> {
  readonly isQuickEditMode: boolean;
  readonly quickEditAction?: PageHeaderActionItemProps;
  readonly QuickEditContextProvider: React.FC;
  readonly quickEditStation: JSX.Element | undefined;
  readonly changeSelectedItem: (
    item: T,
    detailsLink?: LocationDescriptor<unknown>,
  ) => Promise<void>;
}

export const useQuickEdit = <T extends Data>({
  hasData,
  listRef,
  defaultItem,
  registrations,
  quickEditConfig,
  collapseFilters,
  generateItemLink,
}: useQuickEditProps<T>): useQuickEditReturnType<T> => {
  const [isQuickEditMode, setIsQuickEditMode] = useState<boolean>(false);
  const [currentRegistration, setCurrentRegistration] =
    useState<QuickEditRegistration<T>>();
  const [selectedItem, setSelectedItem] = useState<T>(defaultItem);
  const [detailsLink, setDetailsLink] = useState<LocationDescriptor<unknown>>();

  const updateDetailsLink = useCallback(
    (item?: T, registration?: QuickEditRegistration<T>) => {
      if (registration?.generateDetailsLink !== false && item) {
        setDetailsLink(
          registration?.generateDetailsLink?.(item) ?? generateItemLink?.(item),
        );
      } else {
        setDetailsLink(undefined);
      }
    },
    [generateItemLink],
  );

  const changeSelectedItem = useCallback(
    async (item: T): Promise<void> => {
      if (selectedItem) {
        await saveCallbackRef.current?.();
      }
      setSelectedItem({ ...item });
      updateDetailsLink(item, currentRegistration);
    },
    [currentRegistration, selectedItem, updateDetailsLink],
  );

  const saveCallbackRef = React.useRef<() => Promise<void>>();

  const registerSaveCallback = useCallback(
    (callback: () => Promise<void>): void => {
      saveCallbackRef.current = callback;
    },
    [],
  );

  const QuickEditContextProvider: React.FC = useCallback(
    ({ children }) => {
      return (
        <QuickEditContext.Provider
          value={{
            selectedItem,
            registerSaveCallback,
            isQuickEditMode,
            detailsLink,
            refresh: async () => {
              if (selectedItem) {
                await saveCallbackRef.current?.();
                setSelectedItem({ ...selectedItem });
              }
            },
          }}
        >
          {children}
        </QuickEditContext.Provider>
      );
    },
    [detailsLink, isQuickEditMode, registerSaveCallback, selectedItem],
  );

  const quickEditAction: PageHeaderActionItemProps | undefined = useMemo(
    () =>
      registrations !== undefined && registrations.length > 0
        ? {
            label: quickEditConfig?.label ?? 'Quick View',
            kind: 'group',
            icon: quickEditConfig?.icon ?? IconName.QuickEdit,
            disabled: !hasData && !isQuickEditMode,
            openActionsGroupOnStart: isQuickEditMode,
            onActionsGroupToggled: async (isOpen) => {
              if (!isOpen && selectedItem) {
                await saveCallbackRef.current?.();
                setCurrentRegistration(undefined);
                setSelectedItem(defaultItem);
                updateDetailsLink(defaultItem, registrations[0]);
                setDetailsLink(undefined);
                setIsQuickEditMode(false);
                listRef.current?.resetSelection();
              } else {
                if (defaultItem) {
                  setSelectedItem(defaultItem);
                  updateDetailsLink(defaultItem, registrations[0]);
                }
                setIsQuickEditMode(isOpen);
                setCurrentRegistration(isOpen ? registrations[0] : undefined);
                if (isOpen) {
                  collapseFilters();
                  listRef.current?.selectIndex(0);
                }
              }
            },
            actions: registrations.map((registration) => ({
              label: registration.label,
              icon: registration.icon ?? IconName.QuickEditStation,
              actionType:
                isQuickEditMode &&
                currentRegistration?.component === registration.component
                  ? PageHeaderActionType.Hightlight
                  : PageHeaderActionType.Context,
              onClick: async () => {
                await saveCallbackRef.current?.();
                setSelectedItem({ ...selectedItem });
                setCurrentRegistration(registration);
                updateDetailsLink(selectedItem, registration);
              },
            })),
          }
        : undefined,
    [
      collapseFilters,
      currentRegistration?.component,
      defaultItem,
      hasData,
      isQuickEditMode,
      listRef,
      quickEditConfig?.icon,
      quickEditConfig?.label,
      registrations,
      selectedItem,
      updateDetailsLink,
    ],
  );

  return {
    isQuickEditMode,
    quickEditAction,
    QuickEditContextProvider,
    quickEditStation: currentRegistration?.component,
    changeSelectedItem,
  };
};
