import { ApproxStructure, Assertions, type TestStore } from '@ephox/agar';
import { context, describe, it } from '@ephox/bedrock-client';
import { Objects } from '@ephox/boulder';

import * as AddEventsBehaviour from 'ephox/alloy/api/behaviour/AddEventsBehaviour';
import * as Behaviour from 'ephox/alloy/api/behaviour/Behaviour';
import * as GuiFactory from 'ephox/alloy/api/component/GuiFactory';
import type { SketchSpec } from 'ephox/alloy/api/component/SpecTypes';
import * as AlloyEvents from 'ephox/alloy/api/events/AlloyEvents';
import { tieredMenu as TieredMenu } from 'ephox/alloy/api/ui/TieredMenu';
import * as MenuEvents from 'ephox/alloy/menu/util/MenuEvents';
import * as TestDropdownMenu from 'ephox/alloy/test/dropdown/TestDropdownMenu';
import * as GuiSetup from 'ephox/alloy/test/GuiSetup';
import { HighlightOnOpen } from 'ephox/alloy/ui/types/TieredMenuTypes';

const makeTieredMenu = (store: TestStore, highlightOnOpen: HighlightOnOpen): SketchSpec => {
  return TieredMenu.sketch({
    dom: {
      tag: 'div',
      classes: [ 'this-test-tiered-menu' ]
    },
    components: [ ],

    highlightOnOpen,
    data: TestDropdownMenu.getSampleTieredData(),
    fakeFocus: true,

    tmenuBehaviours: Behaviour.derive([
      AddEventsBehaviour.config('tiered-menu-test', [
        AlloyEvents.run(MenuEvents.focus(), store.adder('menu.events.focus'))
      ])
    ]),

    eventOrder: Objects.wrapAll([
      {
        key: MenuEvents.focus(),
        value: [ 'alloy.base.behaviour', 'tiered-menu-test' ]
      }
    ]),

    onExecute: store.adderH('onExecute'),
    onEscape: store.adderH('onEscape'),
    onOpenMenu: store.adderH('onOpenMenu'),
    onOpenSubmenu: store.adderH('onOpenSubmenu'),
    onRepositionMenu: store.adderH('onRepositionMenu'),
    markers: TestDropdownMenu.markers()
  });
};

describe('browser.alloy.ui.dropdown.TieredMenuHighlightOnOpenTest', () => {

  // ASSUMPTION: the ApproxStructure.build arguments s, str, arr are always the same
  // so we don't need to pass the originals through to functions.
  const structActiveMenuAndItem = ApproxStructure.build((s, _str, arr) => {
    return s.element('div', {
      classes: [ ],
      children: [
        s.element('ol', {
          classes: [ arr.has('menu'), arr.has('selected-menu') ],
          children: [
            TestDropdownMenu.structActiveItem,
            TestDropdownMenu.structNotActiveItem,
            TestDropdownMenu.structNotActiveItem
          ]
        })
      ]
    });
  });

  context('HighlightOnOpen = HighlightNone', () => {
    const hook = GuiSetup.bddSetup(
      (store) => GuiFactory.build(
        makeTieredMenu(store, HighlightOnOpen.HighlightNone)
      )
    );

    it('TINY-8952: Test basic structure, before and after highlightPrimary', () => {
      const tmenuComp = hook.component();
      Assertions.assertStructure(
        'Testing the Tiered Menu structure',
        ApproxStructure.build((s, str, arr) => {
          return s.element('div', {
            classes: [ ],
            children: [
              s.element('ol', {
                // The menu should *not* be highlighted
                classes: [ arr.has('menu'), arr.not('selected-menu') ],
                children: [
                  TestDropdownMenu.structNotActiveItem,
                  TestDropdownMenu.structNotActiveItem,
                  TestDropdownMenu.structNotActiveItem
                ]
              })
            ]
          });
        }),
        tmenuComp.element
      );

      TieredMenu.highlightPrimary(tmenuComp);
      Assertions.assertStructure(
        'Testing the Tiered Menu structure after highlightPrimary',
        structActiveMenuAndItem,
        tmenuComp.element
      );
    });
  });

  context('HighlightOnOpen = HighlightJustMenu', () => {
    const hook = GuiSetup.bddSetup(
      (store) => GuiFactory.build(
        makeTieredMenu(store, HighlightOnOpen.HighlightJustMenu)
      )
    );

    it('TINY-8952: Test basic structure', () => {
      const tmenuComp = hook.component();
      Assertions.assertStructure(
        'Testing the Tiered Menu structure',
        ApproxStructure.build((s, str, arr) => {
          return s.element('div', {
            classes: [ ],
            children: [
              s.element('ol', {
                // The menu should be highlighted
                classes: [ arr.has('menu'), arr.has('selected-menu') ],
                children: [
                  TestDropdownMenu.structNotActiveItem,
                  TestDropdownMenu.structNotActiveItem,
                  TestDropdownMenu.structNotActiveItem
                ]
              })
            ]
          });
        }),
        tmenuComp.element
      );

      TieredMenu.highlightPrimary(tmenuComp);
      Assertions.assertStructure(
        'Testing the Tiered Menu structure after highlightPrimary',
        structActiveMenuAndItem,
        tmenuComp.element
      );
    });
  });

  context('HighlightOnOpen = HighlightMenuAndItem', () => {
    const hook = GuiSetup.bddSetup(
      (store) => GuiFactory.build(
        makeTieredMenu(store, HighlightOnOpen.HighlightMenuAndItem)
      )
    );

    it('TINY-8952: Test basic structure', () => {
      const tmenuComp = hook.component();
      Assertions.assertStructure(
        'Testing the Tiered Menu structure',
        structActiveMenuAndItem,
        tmenuComp.element
      );

      TieredMenu.highlightPrimary(tmenuComp);
      Assertions.assertStructure(
        'Testing the Tiered Menu structure after highlightPrimary',
        structActiveMenuAndItem,
        tmenuComp.element
      );
    });
  });
});
