/**
 * @license
 * Copyright 2017 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import '../../../test/common-test-setup';
import './gr-label-score-row';
import {GrLabelScoreRow} from './gr-label-score-row';
import {AccountId} from '../../../api/rest-api';
import {GrButton} from '../../shared/gr-button/gr-button';
import {fixture, html, assert} from '@open-wc/testing';
import {waitEventLoop} from '../../../test/test-utils';

suite('gr-label-row-score tests', () => {
  let element: GrLabelScoreRow;

  setup(async () => {
    element = await fixture(html`<gr-label-score-row></gr-label-score-row>`);
    element.labels = {
      'Code-Review': {
        values: {
          '0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: 0,
        value: 1,
        all: [
          {
            _account_id: 123 as unknown as AccountId,
            value: 1,
          },
        ],
      },
      Verified: {
        values: {
          '0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: 0,
        value: 1,
        all: [
          {
            _account_id: 123 as unknown as AccountId,
            value: 1,
          },
        ],
      },
    };

    element.permittedLabels = {
      'Code-Review': ['-2', '-1', ' 0', '+1', '+2'],
      Verified: ['-1', ' 0', '+1'],
    };

    element.orderedLabelValues = [-2, -1, 0, 1, 2];
    //  {'0': 2, '1': 3, '2': 4, '-2': 0, '-1': 1};

    element.label = {
      name: 'Verified',
      value: '+1',
    };

    await element.updateComplete;
    await waitEventLoop();
  });

  function checkAriaCheckedValid() {
    const items = element.labelSelector!.items;
    assert.ok(items);
    const selectedItem = element.selectedItem;
    for (let i = 0; i < items!.length; i++) {
      const item = items![i];
      if (items![i] === selectedItem) {
        assert.isTrue(item.hasAttribute('aria-checked'), `item ${i}`);
        assert.equal(item.getAttribute('aria-checked'), 'true', `item ${i}`);
      } else {
        assert.isFalse(item.hasAttribute('aria-checked'), `item ${i}`);
      }
    }
  }

  test('label picker', async () => {
    const labelsChangedHandler = sinon.stub();
    element.addEventListener('labels-changed', labelsChangedHandler);
    assert.ok(element.labelSelector);
    const button = element.shadowRoot!.querySelector(
      'gr-button[data-value="-1"]'
    ) as GrButton;
    button.click();
    await element.updateComplete;

    assert.strictEqual(element.selectedValue, '-1');
    assert.strictEqual(element.selectedItem!.textContent!.trim(), '-1');
    const selectedValueLabel = element.shadowRoot!.querySelector(
      '#selectedValueLabel'
    );
    assert.strictEqual(selectedValueLabel!.textContent!.trim(), 'bad');
    const detail = labelsChangedHandler.args[0][0].detail;
    assert.equal(detail.name, 'Verified');
    assert.equal(detail.value, '-1');
    checkAriaCheckedValid();
  });

  test('Reset Vote title', () => {
    // User already voted +1 so we show reset vote
    assert.equal(element.computeLabelValueTitle('0'), 'Reset Vote');
    element.label = {
      name: 'Verified',
      value: '0',
    };
    // User voted 0 and selected 0 hence no score
    assert.equal(element.computeLabelValueTitle('0'), 'No score');
  });

  test('_computeVoteAttribute', () => {
    let value = 1;
    let index = 0;
    const totalItems = 5;
    // positive and first position
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'positive'
    );
    // negative and first position
    value = -1;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'min'
    );
    // negative but not first position
    index = 1;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'negative'
    );
    // neutral
    value = 0;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'neutral'
    );
    // positive but not last position
    value = 1;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'positive'
    );
    // positive and last position
    index = 4;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'max'
    );
    // negative and last position
    value = -1;
    assert.equal(
      element._computeVoteAttribute(value, index, totalItems),
      'negative'
    );
  });

  test('correct item is selected', () => {
    // 1 should be the value of the selected item
    assert.strictEqual(element.labelSelector!.selected, '+1');
    assert.strictEqual(element.selectedItem!.textContent!.trim(), '+1');
    const selectedValueLabel = element.shadowRoot!.querySelector(
      '#selectedValueLabel'
    );
    assert.strictEqual(selectedValueLabel!.textContent!.trim(), 'good');
    checkAriaCheckedValid();
  });

  test('_computeLabelValue', () => {
    assert.strictEqual(element._computeLabelValue(), '+1');
  });

  test('computeBlankItemsCount', () => {
    element.orderedLabelValues = [-2, -1, 0, 1, 2];
    element.label = {name: 'Code-Review', value: ' 0'};
    assert.strictEqual(element.computeBlankItemsCount('start'), 0);

    element.label = {name: 'Verified', value: ' 0'};
    assert.strictEqual(element.computeBlankItemsCount('start'), 1);
  });

  test('labelValues returns no keys', () => {
    element.orderedLabelValues = [];
    element.label = {name: 'Code-Review', value: ' 0'};

    assert.deepEqual(element.computeBlankItemsCount('start'), 0);
  });

  test('changes in label score are reflected in the DOM', async () => {
    element.labels = {
      'Code-Review': {
        values: {
          '0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: 0,
      },
      Verified: {
        values: {
          ' 0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: 0,
      },
    };
    // For some reason we need the element.labels to flush first before we
    // change the element.label
    await element.updateComplete;

    element.label = {name: 'Verified', value: ' 0'};
    await element.updateComplete;
    // Wait for @selected-item-changed to fire
    await waitEventLoop();

    const selector = element.labelSelector;
    assert.strictEqual(selector!.selected, ' 0');
    const selectedValueLabel = element.shadowRoot!.querySelector(
      '#selectedValueLabel'
    );
    assert.strictEqual(selectedValueLabel!.textContent!.trim(), 'Reset Vote');
    checkAriaCheckedValid();
  });

  test('asymmetrical labels', async () => {
    element.permittedLabels = {
      'Code-Review': ['-2', '-1', ' 0', '+1', '+2'],
      Verified: [' 0', '+1'],
    };
    await element.updateComplete;
    assert.strictEqual(element.labelSelector!.items!.length, 2);
    assert.strictEqual(
      element.shadowRoot!.querySelectorAll('.placeholder').length,
      3
    );

    element.permittedLabels = {
      'Code-Review': [' 0', '+1'],
      Verified: ['-2', '-1', ' 0', '+1', '+2'],
    };
    await element.updateComplete;
    assert.strictEqual(element.labelSelector!.items!.length, 5);
    assert.strictEqual(
      element.shadowRoot!.querySelectorAll('.placeholder').length,
      0
    );
  });

  test('default_value', async () => {
    element.permittedLabels = {
      Verified: ['-1', ' 0', '+1'],
    };
    element.labels = {
      Verified: {
        values: {
          '0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: -1,
      },
    };
    element.label = {
      name: 'Verified',
      value: null,
    };
    await element.updateComplete;
    assert.strictEqual(element.selectedValue, '-1');
    checkAriaCheckedValid();
  });

  test('default_value is null if not permitted', async () => {
    element.permittedLabels = {
      Verified: ['-1', ' 0', '+1'],
    };
    element.labels = {
      'Code-Review': {
        values: {
          '0': 'No score',
          '+1': 'good',
          '+2': 'excellent',
          '-1': 'bad',
          '-2': 'terrible',
        },
        default_value: -1,
      },
    };
    element.label = {
      name: 'Code-Review',
      value: null,
    };
    await element.updateComplete;
    assert.isNull(element.selectedValue);
  });

  test('shadowDom test', () => {
    assert.shadowDom.equal(
      element,
      /* HTML */ `
        <span class="labelNameCell" id="labelName" aria-hidden="true">
          Verified
        </span>
        <div class="buttonsCell">
          <span class="placeholder" data-label="Verified"></span>
          <iron-selector
            aria-labelledby="labelName"
            id="labelSelector"
            role="radiogroup"
            selected="+1"
          >
            <gr-button
              aria-disabled="false"
              aria-label="-1"
              data-name="Verified"
              data-value="-1"
              role="button"
              tabindex="0"
              title="bad"
              data-vote="min"
              votechip=""
              flatten=""
            >
              <gr-tooltip-content light-tooltip="" has-tooltip="" title="bad">
                -1
              </gr-tooltip-content>
            </gr-button>
            <gr-button
              aria-disabled="false"
              aria-label=" 0"
              data-name="Verified"
              data-value=" 0"
              role="button"
              tabindex="0"
              data-vote="neutral"
              title="Reset Vote"
              votechip=""
              flatten=""
            >
              <gr-tooltip-content
                light-tooltip=""
                title="Reset Vote"
                has-tooltip=""
              >
                0
              </gr-tooltip-content>
            </gr-button>
            <gr-button
              aria-checked="true"
              aria-disabled="false"
              aria-label="+1"
              class="iron-selected"
              data-name="Verified"
              data-value="+1"
              role="button"
              tabindex="0"
              title="good"
              data-vote="max"
              votechip=""
              flatten=""
            >
              <gr-tooltip-content light-tooltip="" has-tooltip="" title="good">
                +1
              </gr-tooltip-content>
            </gr-button>
          </iron-selector>
          <span class="placeholder" data-label="Verified"></span>
        </div>
        <div class="selectedValueCell ">
          <span id="selectedValueLabel">good</span>
        </div>
      `
    );
  });
});
