/* eslint-disable lit-a11y/tabindex-no-positive */
import { assert, fixture, html, nextFrame, oneEvent } from '@open-wc/testing';
import sinon from 'sinon';
import UiIconButton, { IconButtonType } from '../../../src/ui/button/UiIconButton.js';
import { UiMock } from '../../helpers/UiMock.js';
import { IconType } from '../../../src/ui/icons/Icons.js';
import '../../../src/define/ui/ui-icon-button.js';
import '../../../src/define/ui/ui-icon.js';

describe('UI', () => {
  describe('UiIconButton', () => {
    async function basicFixture(icon: IconType): Promise<UiIconButton> {
      return fixture(html`<ui-icon-button><ui-icon .icon="${icon}"></ui-icon></ui-icon-button>`);
    }

    async function toggleFixture(icon: IconType): Promise<UiIconButton> {
      return fixture(html`<ui-icon-button toggle><ui-icon .icon="${icon}"></ui-icon></ui-icon-button>`);
    }

    async function tabindexFixture(icon: IconType): Promise<UiIconButton> {
      return fixture(html`<ui-icon-button tabindex="-1"><ui-icon .icon="${icon}"></ui-icon></ui-icon-button>`);
    }

    async function labeledFixture(icon: IconType): Promise<UiIconButton> {
      return fixture(html`<ui-icon-button aria-label="My button" title="My button description"><ui-icon .icon="${icon}"></ui-icon></ui-icon-button>`);
    }

    async function labeledToggleFixture(icon: IconType): Promise<UiIconButton> {
      return fixture(html`<ui-icon-button aria-label="My button" title="My button description"><ui-icon .icon="${icon}"></ui-icon></ui-icon-button>`);
    }

    describe('defaults', () => {
      it('sets the default type', async () => {
        const button = await basicFixture('add');
        assert.equal(button.type, IconButtonType.standard);
      });
    });

    describe('toggle button', () => {
      it('sets button active when pressing the button with space', async () => {
        const button = await toggleFixture('add');
        await UiMock.keyPress(button, 'Space');
        await nextFrame();
        assert.isTrue(button.active, 'button is active');
      });

      it('sets button active when pressing the button with enter', async () => {
        const button = await toggleFixture('add');
        await UiMock.keyPress(button, 'Enter');
        await nextFrame();
        assert.isTrue(button.active, 'button is active');
      });

      it('sets button active when clicking on the button', async () => {
        const button = await toggleFixture('add');
        button.click();
        await nextFrame();
        assert.isTrue(button.active, 'button is active');
      });

      it('sets "aria-pressed" when toggling the button', async () => {
        const button = await toggleFixture('add');
        await UiMock.keyPress(button, 'Space');
        await nextFrame();
        assert.equal(button.getAttribute('aria-pressed'), 'true');
      });

      it('dispatches the "active" event when toggling', async () => {
        const button = await toggleFixture('add');
        UiMock.keyPress(button, 'Space');
        const e = await oneEvent(button, 'active');
        assert.ok(e, 'dispatches the event');
      });

      it('does not dispatch the "active" event toggling attribute', async () => {
        const button = await toggleFixture('add');
        const spy = sinon.spy();
        button.addEventListener('active', spy);
        button.active = true;
        await nextFrame();
        assert.isFalse(spy.called);
      });

      it('does not dispatch the "click" event when toggling', async () => {
        const button = await toggleFixture('add');
        const spy = sinon.spy();
        button.addEventListener('click', spy);
        await UiMock.keyPress(button, 'Space');
        await nextFrame();
        assert.isFalse(spy.called);
      });
    });

    describe('non-toggle button', () => {
      it('clicks when pressing the button with space', async () => {
        const button = await basicFixture('add');
        const spy = sinon.spy();
        button.addEventListener('click', spy);
        await UiMock.keyPress(button, 'Space');
        await nextFrame();
        assert.isTrue(spy.calledOnce, 'event dispatched only once');
      });

      it('clicks when pressing the button with enter', async () => {
        const button = await basicFixture('add');
        const spy = sinon.spy();
        button.addEventListener('click', spy);
        await UiMock.keyPress(button, 'Enter');
        await nextFrame();
        assert.isTrue(spy.calledOnce, 'event dispatched only once');
      });
    });

    describe('a11y', () => {
      it('has the role', async () => {
        const button = await basicFixture('add');
        assert.equal(button.getAttribute('role'), 'button');
      });

      it('has the tabindex', async () => {
        const button = await basicFixture('add');
        assert.equal(button.getAttribute('tabindex'), '0');
      });

      it('respects the existing tabindex', async () => {
        const button = await tabindexFixture('add');
        assert.equal(button.getAttribute('tabindex'), '-1');
      });

      it('is accessible for regular button', async () => {
        const button = await labeledFixture('add');
        await assert.isAccessible(button);
      });

      it('is accessible when not active', async () => {
        const button = await labeledToggleFixture('add');
        await assert.isAccessible(button);
      });

      it('is accessible when active', async () => {
        const button = await labeledToggleFixture('add');
        button.active = true;
        await nextFrame();
        await assert.isAccessible(button);
      });
    });
  });
});
