/**
 * @license
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import '../../../test/common-test-setup';
import './gr-menu-editor';
import {GrMenuEditor} from './gr-menu-editor';
import {query, queryAndAssert, waitUntil} from '../../../test/test-utils';
import {PaperButtonElement} from '@polymer/paper-button';
import {TopMenuItemInfo} from '../../../types/common';
import {GrButton} from '../../shared/gr-button/gr-button';
import {fixture, html, assert} from '@open-wc/testing';
import {createDefaultPreferences} from '../../../constants/constants';

suite('gr-menu-editor tests', () => {
  let element: GrMenuEditor;
  let menu: TopMenuItemInfo[];

  function assertMenuNamesEqual(
    element: GrMenuEditor,
    expected: Array<string>
  ) {
    const names = element.menuItems.map(i => i.name);
    assert.equal(names.length, expected.length);
    for (let i = 0; i < names.length; i++) {
      assert.equal(names[i], expected[i]);
    }
  }

  // Click the up/down button (according to direction) for the index'th row.
  // The index of the first row is 0, corresponding to the array.
  function move(element: GrMenuEditor, index: number, direction: string) {
    const selector = `tr:nth-child(${index + 1}) .move${direction}Button`;

    const button = query<PaperButtonElement>(
      query<HTMLElement>(query<HTMLTableElement>(element, 'tbody'), selector),
      'paper-button'
    );
    button!.click();
  }

  setup(async () => {
    element = await fixture<GrMenuEditor>(
      html`<gr-menu-editor></gr-menu-editor>`
    );
    menu = [
      {url: '/first/url', name: 'first name', target: '_blank'},
      {url: '/second/url', name: 'second name', target: '_blank'},
      {url: '/third/url', name: 'third name', target: '_blank'},
    ];
    element.originalPrefs = {...createDefaultPreferences(), my: menu};
    element.menuItems = [...menu];
    await element.updateComplete;
  });

  test('renders', () => {
    assert.shadowDom.equal(
      element,
      /* HTML */ `
        <div class="gr-form-styles">
          <h2 class="heading-2" id="Menu">Menu</h2>
          <fieldset id="menu">
            <table>
              <thead>
                <tr>
                  <th>Name</th>
                  <th>URL</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>first name</td>
                  <td class="urlCell">/first/url</td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveUpButton"
                      data-index="0"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↑
                    </gr-button>
                  </td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveDownButton"
                      data-index="0"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↓
                    </gr-button>
                  </td>
                  <td>
                    <gr-button
                      aria-disabled="false"
                      class="remove-button"
                      data-index="0"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      Delete
                    </gr-button>
                  </td>
                </tr>
                <tr>
                  <td>second name</td>
                  <td class="urlCell">/second/url</td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveUpButton"
                      data-index="1"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↑
                    </gr-button>
                  </td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveDownButton"
                      data-index="1"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↓
                    </gr-button>
                  </td>
                  <td>
                    <gr-button
                      aria-disabled="false"
                      class="remove-button"
                      data-index="1"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      Delete
                    </gr-button>
                  </td>
                </tr>
                <tr>
                  <td>third name</td>
                  <td class="urlCell">/third/url</td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveUpButton"
                      data-index="2"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↑
                    </gr-button>
                  </td>
                  <td class="buttonColumn">
                    <gr-button
                      aria-disabled="false"
                      class="moveDownButton"
                      data-index="2"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      ↓
                    </gr-button>
                  </td>
                  <td>
                    <gr-button
                      aria-disabled="false"
                      class="remove-button"
                      data-index="2"
                      link=""
                      role="button"
                      tabindex="0"
                    >
                      Delete
                    </gr-button>
                  </td>
                </tr>
              </tbody>
              <tfoot>
                <tr>
                  <th>
                    <iron-input>
                      <input is="iron-input" placeholder="New Title" />
                    </iron-input>
                  </th>
                  <th>
                    <iron-input>
                      <input class="newUrlInput" placeholder="New URL" />
                    </iron-input>
                  </th>
                  <th></th>
                  <th></th>
                  <th>
                    <gr-button
                      aria-disabled="true"
                      disabled=""
                      id="add"
                      link=""
                      role="button"
                      tabindex="-1"
                    >
                      Add
                    </gr-button>
                  </th>
                </tr>
              </tfoot>
            </table>
            <gr-button
              aria-disabled="true"
              disabled=""
              id="save"
              role="button"
              tabindex="-1"
            >
              Save changes
            </gr-button>
            <gr-button
              aria-disabled="false"
              id="reset"
              link=""
              role="button"
              tabindex="0"
            >
              Reset
            </gr-button>
          </fieldset>
        </div>
      `
    );
  });

  test('add button disabled', async () => {
    element.newName = 'test-name';
    await element.updateComplete;
    let addButton = queryAndAssert<GrButton>(element, 'gr-button#add');
    assert.isTrue(addButton.hasAttribute('disabled'));

    element.newUrl = 'test-url';
    await element.updateComplete;
    addButton = queryAndAssert<GrButton>(element, 'gr-button#add');
    assert.isFalse(addButton.hasAttribute('disabled'));
  });

  test('add a new menu item', async () => {
    const newName = 'new name';
    const newUrl = 'new url';
    const originalMenuLength = element.menuItems.length;

    element.newName = newName;
    element.newUrl = newUrl;
    await element.updateComplete;

    const addButton = queryAndAssert<GrButton>(element, 'gr-button#add');
    assert.isFalse(addButton.hasAttribute('disabled'));
    addButton.click();

    assert.equal(element.menuItems.length, originalMenuLength + 1);
    assert.equal(element.menuItems[element.menuItems.length - 1].name, newName);
    assert.equal(element.menuItems[element.menuItems.length - 1].url, newUrl);
  });

  test('move items down', () => {
    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);

    // Move the middle item down
    move(element, 1, 'Down');
    assertMenuNamesEqual(element, ['first name', 'third name', 'second name']);

    // Moving the bottom item down is a no-op.
    move(element, 2, 'Down');
    assertMenuNamesEqual(element, ['first name', 'third name', 'second name']);
  });

  test('move item down and save', async () => {
    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);
    const saveButton = queryAndAssert<GrButton>(element, 'gr-button#save');
    assert.isTrue(saveButton.hasAttribute('disabled'));

    move(element, 1, 'Down');
    await element.updateComplete;
    assertMenuNamesEqual(element, ['first name', 'third name', 'second name']);
    assert.isFalse(saveButton.hasAttribute('disabled'));

    saveButton.click();
    await waitUntil(() => element.originalPrefs.my[1].name === 'third name');
    await element.updateComplete;

    assertMenuNamesEqual(element, ['first name', 'third name', 'second name']);
    assert.isTrue(saveButton.hasAttribute('disabled'));
  });

  test('move item down and reset', async () => {
    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);

    move(element, 1, 'Down');
    assertMenuNamesEqual(element, ['first name', 'third name', 'second name']);

    const resetButton = queryAndAssert<GrButton>(element, 'gr-button#reset');
    resetButton.click();
    await element.updateComplete;

    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);
  });

  test('move items up', () => {
    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);

    // Move the last item up twice to be the first.
    move(element, 2, 'Up');
    move(element, 1, 'Up');
    assertMenuNamesEqual(element, ['third name', 'first name', 'second name']);

    // Moving the top item up is a no-op.
    move(element, 0, 'Up');
    assertMenuNamesEqual(element, ['third name', 'first name', 'second name']);
  });

  test('remove item', () => {
    assertMenuNamesEqual(element, ['first name', 'second name', 'third name']);

    // Tap the delete button for the middle item.
    query<PaperButtonElement>(
      query<HTMLElement>(
        query<HTMLTableElement>(element, 'tbody'),
        'tr:nth-child(2) .remove-button'
      ),
      'paper-button'
    )!.click();

    assertMenuNamesEqual(element, ['first name', 'third name']);

    // Delete remaining items.
    for (let i = 0; i < 2; i++) {
      query<PaperButtonElement>(
        query<HTMLElement>(
          query<HTMLTableElement>(element, 'tbody'),
          'tr:first-child .remove-button'
        ),
        'paper-button'
      )!.click();
    }
    assertMenuNamesEqual(element, []);

    // Add item to empty menu.
    element.newName = 'new name';
    element.newUrl = 'new url';
    element.handleAddButton();
    assertMenuNamesEqual(element, ['new name']);
  });
});
