import { MaybePromise, Nullable } from 'tsdef';

import { FileActionState } from './action-handler.types';
import { FileViewConfig } from './file-view.types';
import { FileFilter, FileMap } from './file.types';
import { ChonkyIconName } from './icons.types';
import { ChonkyDispatch, RootState } from './redux.types';
import { FileSortKeySelector } from './sort.types';

export interface FileAction {
  /**
   * Unique file action ID. If you set the action ID to one of the built-in Chonky
   * action action IDs, you custom action definition will override the built-in
   * definition.
   */
  id: string;
  /**
   * When set to `true`, the action will only be active (dispatchable) when user
   * selects one or more files. If `fileFilter` is defined, it will be applied to
   * selection before checking if its empty.
   */
  requiresSelection?: boolean; // Requires selection of 1+ files
  /**
   * A predicate that determines whether a file should be included in the selection
   * for this action.
   */
  fileFilter?: FileFilter;
  /**
   * List of hotkeys that should trigger this action, defined using `hotkey-js`
   * notation.
   * @see https://www.npmjs.com/package/hotkeys-js
   */
  hotkeys?: string[] | readonly string[];
  /**
   * When button is defined and `toolbar` or `contextMenu` is set to `true`, a
   * button will be added to the relevant UI component. Clicking on this button
   * will active this action. The appearance of the button will change based on
   * the action definition and the current Chonky state.
   */
  button?: FileActionButton;
  /**
   * When `sortKeySelector` is specified, the action becomes a sorting toggle. When
   * this action is activated, it will sort files using the key selector, toggling
   * between Ascending and Descending orders.
   */
  sortKeySelector?: FileSortKeySelector;
  /**
   * When `fileViewConfig` is specified, triggering this action will apply the
   * provided config to Chonky's file view.
   */
  fileViewConfig?: FileViewConfig;
  /**
   * When `option` is specified, the action becomes an option toggle. When the action
   * is activated, the boolean value of the option will be toggled.
   */
  option?: FileActionOption;
  /**
   * When selection transform is defined, activating this action will update the file
   * selection. If the transform function returns `null`, selection will be left
   * untouched.
   */
  selectionTransform?: FileSelectionTransform;
  /**
   * When effect is defined, it will be called right before dispatching the action to
   * the user defined action handler. If the effect function returns a promise, Chonky
   * will wait for the promise to resolve or fail before dispatching the action to the
   * handler. If this function returns `true`, the file action will NOT be dispatched
   * the the handler.
   */
  effect?: FileActionEffect;
  /**
   * When customVisibility is defined, it will change the display state of the file action
   * The function must return the visibility as one of the CustomVisibilityState values:
   *  - Hidden
   *  - Disabled
   *  - Default
   *  - Active
   */
  customVisibility?: () => CustomVisibilityState;
  /**
   * Field used to infer the type of action payload. It is used solely for Typescript
   * type inference and action validation.
   */
  __payloadType?: any;
  /**
   * Field used to infer the type of extra state for this action. It is used solely
   * for Typescript type inference and action validation.
   */
  __extraStateType?: any;
}

export interface FileActionButton {
  name: string; // Button name
  toolbar?: boolean; // Whether to show the button in the toolbar
  contextMenu?: boolean; // Whether to show the button in the context menu
  group?: string; // Button group (dropdown in toolbar or section in context menu)
  tooltip?: string; // Help tooltip text
  icon?: ChonkyIconName | string | any; // Icon name
  iconOnly?: boolean; // Whether to only display the icon
}

export interface FileActionOption {
  id: string; // Unique option ID
  defaultValue: boolean; // Whether the option is enabled by default (required)
}

export type FileSelectionTransform = (data: {
  prevSelection: Set<string>;
  fileIds: ReadonlyArray<string>;
  fileMap: Readonly<FileMap>;
  hiddenFileIds: Set<string>;
}) => Nullable<Set<string>>;

export type FileActionEffect<Action extends FileAction = any> = (data: {
  action: Action;
  payload: Action['__payloadType'];
  state: FileActionState<{}>; // extra state is empty on purpose
  reduxDispatch: ChonkyDispatch;
  getReduxState: () => RootState;
}) => MaybePromise<undefined | boolean | void>;

export type FileActionMap = { [actonId: string]: FileAction };

export enum CustomVisibilityState {
  Hidden,
  Disabled,
  Default,
  Active,
}
