import { useMemo } from 'react';
import { showNotification } from '../../../initialize';
import { Data } from '../../../types';
import { ErrorTypeToStationError } from '../../../utils/ErrorTypeToStationError';
import { IconName } from '../../Icons';
import { ItemSelectEventArgs } from '../../List';
import { PageHeaderActionItemProps } from '../../PageHeader';
import {
  PageHeaderActionProps,
  PageHeaderActionType,
  PageHeaderJsActionProps,
  isPageHeaderNavigationAction,
} from '../../PageHeader/PageHeaderAction';
import { ErrorType } from '../../models';
import { ExplorerBulkAction, ItemSelection } from '../Explorer.model';
import { ResultCounts } from './useDataProvider';
import { StationMessage } from './useStationMessage';

interface UseActionsProps<T extends Data> {
  actions?: PageHeaderActionProps[];
  bulkActions?: ExplorerBulkAction<T>[];
  quickEditAction?: PageHeaderActionItemProps;
  bulkEditAction?: ExplorerBulkAction<T>;
  openBulkActionsOnStart: boolean | undefined;
  filtersVisible: boolean;
  hasFilters: boolean;
  resultCount: ResultCounts;
  activeFilterCount: number;
  itemSelection: ItemSelectEventArgs<T>;
  getBulkActionSelection: () => ItemSelection<T>;
  onReloadData: () => void;
  setStationMessage: (
    value: React.SetStateAction<StationMessage | undefined>,
  ) => void;
  onBulkActionsToggled: (expanded: boolean) => void;
  setIsBulkOpen: (value: React.SetStateAction<boolean>) => void;
  toggleFiltersVisible: () => void;
  closeBulkEdit: () => void;
}

interface UseActionsReturnType {
  readonly actions: PageHeaderActionItemProps[];
}

export const useActions = <T extends Data>({
  getBulkActionSelection,
  onReloadData,
  setStationMessage,
  actions,
  itemSelection,
  onBulkActionsToggled,
  openBulkActionsOnStart,
  resultCount,
  setIsBulkOpen,
  hasFilters,
  filtersVisible,
  activeFilterCount,
  toggleFiltersVisible,
  quickEditAction,
  bulkActions,
  closeBulkEdit,
  bulkEditAction,
}: UseActionsProps<T>): UseActionsReturnType => {
  const bulkActionItems: PageHeaderJsActionProps[] = useMemo(
    () => [
      ...(bulkEditAction ? [bulkEditAction] : []),
      ...(bulkActions ?? []).map((action) => ({
        ...action,
        onClick: async () => {
          if (action.showStartedNotification !== false) {
            showNotification({
              title: `Bulk Action '${action.label}' Started`,
            });
          }

          try {
            const result = await action.onClick(getBulkActionSelection());
            if (result) {
              const message = errMsg(result);
              showNotification({
                title:
                  typeof message.title === 'string'
                    ? message.title
                    : 'An error occurred',
                body: message.body,
                options: {
                  type: 'error',
                },
              });
            } else {
              if (action.reloadData) {
                onReloadData();
              }
            }
          } catch (error) {
            setStationMessage(
              errMsg(
                error,
                'An error occurred when trying to execute the bulk operation.',
              ),
            );
          }
        },
      })),
    ],
    [
      bulkActions,
      bulkEditAction,
      getBulkActionSelection,
      onReloadData,
      setStationMessage,
    ],
  );

  const pageHeaderActions: PageHeaderActionItemProps[] = useMemo(() => {
    const headerActions: PageHeaderActionItemProps[] = [];

    if (hasFilters) {
      headerActions.push({ kind: 'spacer' });

      headerActions.push({
        label:
          activeFilterCount > 0 ? `Filters (${activeFilterCount})` : 'Filters',
        icon: IconName.Filters,
        kind: 'action',
        actionType: filtersVisible
          ? PageHeaderActionType.Active
          : PageHeaderActionType.Context,
        onClick: async () => {
          toggleFiltersVisible();
        },
      });
    }

    if (bulkActionItems.length > 0) {
      headerActions.push({ kind: 'spacer' });

      headerActions.push({
        label: 'Bulk Actions',
        icon: IconName.Bulk,
        kind: 'group',
        actions: bulkActionItems,
        openActionsGroupOnStart: openBulkActionsOnStart,
        onActionsGroupToggled: async (isOpen) => {
          setIsBulkOpen(isOpen);
          onBulkActionsToggled(isOpen);

          if (!isOpen) {
            closeBulkEdit();
          }
        },
        groupActionsDisabled:
          itemSelection.items?.length === 0 || resultCount?.filtered === 0,
      });
    }

    if (quickEditAction) {
      headerActions.push({ kind: 'spacer' });

      headerActions.push(quickEditAction);
    }

    if (actions && actions.length > 0) {
      headerActions.push({ kind: 'spacer' });

      actions?.forEach((action) => {
        headerActions.push({
          ...(isPageHeaderNavigationAction(action)
            ? action
            : {
                ...action,
                onClick: async () => {
                  try {
                    const result = await action.onClick();
                    if (result) {
                      setStationMessage(errMsg(result));
                    }
                  } catch (error) {
                    setStationMessage(
                      errMsg(
                        error,
                        'An error occurred when trying to execute the operation.',
                      ),
                    );
                  }
                },
              }),
          kind: 'action',
        });
      });
    }

    return headerActions;
  }, [
    actions,
    activeFilterCount,
    bulkActionItems,
    closeBulkEdit,
    filtersVisible,
    hasFilters,
    itemSelection.items?.length,
    onBulkActionsToggled,
    openBulkActionsOnStart,
    quickEditAction,
    resultCount?.filtered,
    setIsBulkOpen,
    setStationMessage,
    toggleFiltersVisible,
  ]);

  return {
    actions: pageHeaderActions,
  };
};

const errMsg = (err: unknown | ErrorType, msg?: string): StationMessage => {
  return {
    ...ErrorTypeToStationError(err as ErrorType, msg),
    canClose: true,
    type: 'error',
  };
};
