import type { Optional } from '@ephox/katamari';
import type { SugarElement } from '@ephox/sugar';

import type { AlloyBehaviourRecord } from '../../api/behaviour/Behaviour';
import type { AlloyComponent } from '../../api/component/ComponentApi';
import type { SketchBehaviours } from '../../api/component/SketchBehaviours';
import type { AlloySpec, RawDomSchema } from '../../api/component/SpecTypes';
import type { FocusManager } from '../../api/focus/FocusManagers';
import type { CompositeSketch, CompositeSketchDetail, CompositeSketchSpec } from '../../api/ui/Sketcher';
import type { CustomEvent } from '../../events/SimulatedEvent';
import type { FlatgridConfigSpec, MatrixConfigSpec, MenuConfigSpec } from '../../keying/KeyingModeTypes';

import type { ItemSpec } from './ItemTypes';

export interface MenuGridMovementSpec {
  mode: 'grid';
  initSize: {
    numColumns: number;
    numRows: number;
  };
}

export interface MenuMatrixMovementSpec {
  mode: 'matrix';
  rowSelector: string;
  previousSelector?: (comp: AlloyComponent) => Optional<SugarElement<HTMLElement>>;
}

export interface MenuNormalMovementSpec {
  mode: 'menu';
  moveOnTab?: boolean;
}

export type MenuMovementSpec = MenuGridMovementSpec | MenuMatrixMovementSpec | MenuNormalMovementSpec;

// config: (detail: MenuDetail,  movementInfo: MenuMovement) => KeyingConfigSpec
export interface MenuGridMovement {
  mode: 'grid';
  config: (detail: MenuDetail, movementInfo: MenuMovement) => FlatgridConfigSpec;
  initSize: {
    numColumns: number;
    numRows: number;
  };
}

export interface MenuMatrixMovement {
  mode: 'matrix';
  config: (detail: MenuDetail, movementInfo: MenuMovement) => MatrixConfigSpec;
  rowSelector: string;
  previousSelector: (comp: AlloyComponent) => Optional<SugarElement<HTMLElement>>;
}

export interface MenuNormalMovement {
  mode: 'menu';
  config: (detail: MenuDetail, movement: MenuMovement) => MenuConfigSpec;
  moveOnTab: boolean;
}

export type MenuMovement = MenuGridMovement | MenuMatrixMovement | MenuNormalMovement;

export interface MenuDetail extends CompositeSketchDetail {
  uid: string;
  dom: RawDomSchema;
  components: AlloySpec[ ];
  menuBehaviours: SketchBehaviours;

  fakeFocus: boolean;
  markers: {
    item: string;
    selectedItem: string;
  };

  onHighlight: (comp: AlloyComponent, target: AlloyComponent) => void;
  onDehighlight: (comp: AlloyComponent, target: AlloyComponent) => void;
  value: string;
  movement: MenuMovement;

  focusManager: FocusManager;
  eventOrder: Record<string, string[]>;
  showMenuRole: boolean;
  role: Optional<string>;
}

export interface MenuSpec extends CompositeSketchSpec {
  uid?: string;
  dom: RawDomSchema;
  components: AlloySpec[];
  menuBehaviours?: AlloyBehaviourRecord;

  value: string;
  items: ItemSpec[];

  fakeFocus?: boolean;
  focusManager?: FocusManager;
  markers: {
    item: string;
    selectedItem: string;
  };

  movement?: MenuMovementSpec;

  onHighlight?: (comp: AlloyComponent, target: AlloyComponent) => void;
  onDehighlight?: (comp: AlloyComponent, target: AlloyComponent) => void;
  eventOrder?: Record<string, string[]>;
  showMenuRole?: boolean;
  role?: string;
}

export interface MenuSketcher extends CompositeSketch<MenuSpec> { }

export interface MenuItemToggledEvent extends CustomEvent {
  readonly item: AlloyComponent;
  readonly state: boolean;
}

export interface MenuItemHoverEvent extends CustomEvent {
  readonly item: AlloyComponent;
}

export interface MenuFocusEvent extends CustomEvent {
  readonly menu: AlloyComponent;
  readonly item: AlloyComponent;
}
