// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="../../../../test/src/custom_typings/chai.d.ts" />
/* eslint-disable no-undef */
import { ZuiWell } from '@zywave/zui-well';

import { awaitEvent, constructHtml } from '../../../../test/src/util/helpers';
import { assert } from '@esm-bundle/chai';
import type { ZuiWellType } from '@zywave/zui-well';
import type { ZuiIcon } from '@zywave/zui-icons';
const supportedWellTypes: ZuiWellType[] = ['info', 'warning', 'error', 'success'];

suite('zui-well', () => {
  let element: ZuiWell;
  const shadowWell = () => element.shadowRoot!.querySelector('.well') as Element;
  const shadowWellStyles = () => window.getComputedStyle(shadowWell());

  setup(async () => {
    element = document.createElement('zui-well') as ZuiWell;

    document.body.appendChild(element);
    await element.updateComplete;
  });

  teardown(() => {
    document.body.removeChild(element);
  });

  test('initializes as a ZuiWell', () => {
    assert.instanceOf(element, ZuiWell);
  });

  test('well text contents properly render', async () => {
    const wellText = 'Body copy';
    const wellActionText = 'Action text';
    const wellContentsStr = `
      ${wellText} 
      <a href="#" slot="action">${wellActionText}</a>
    `;
    const wellContents = constructHtml(wellContentsStr.trim());
    element.appendChild(wellContents);
    await element.updateComplete;
    const slotText = element.shadowRoot!.querySelector('slot').assignedNodes()[0];
    const slotActionText = (
      element.shadowRoot!.querySelector('slot[name="action"]') as HTMLSlotElement
    ).assignedNodes()[0];
    assert.equal(slotText.textContent.trim(), wellText);
    assert.equal(slotActionText.textContent, wellActionText);
  });

  for (const type of supportedWellTypes) {
    test(`Well of type... ${type}, produces corresponding icon... zui-${type}`, async () => {
      element.type = type;
      await element.updateComplete;
      const shadowIconEl: ZuiIcon = element.shadowRoot!.querySelector('.icon zui-icon');
      assert.equal(shadowIconEl.icon, `zui-${type}`);
    });
  }

  test('ZuiWell noIcon does not render icon', async () => {
    element.setAttribute('no-icon', '');
    await element.updateComplete;
    const shadowIcon = element.shadowRoot!.querySelector('.icon');
    const shadowIconStyle = getComputedStyle(shadowIcon);
    assert.equal(shadowIconStyle.display, 'none');
  });

  test("ZuiWell 'banner' attr spans entire width of its parent container", async () => {
    element.setAttribute('banner', '');
    await element.updateComplete;
    assert.equal(shadowWellStyles().maxWidth, 'none');
  });

  test('ZuiWell dismissible, dismisses well', async () => {
    const getShadowIcon = () => element.shadowRoot!.querySelector('.dismiss') as HTMLElement;
    element.dismissible = false;
    assert.isNull(getShadowIcon());
    element.dismissible = true;
    await element.updateComplete;
    assert.exists(getShadowIcon());
    getShadowIcon().focus();
    getShadowIcon().click();
    await awaitEvent(element, 'dismiss');
    assert.equal((shadowWell() as HTMLElement).style.height, '0px');
  });

  test("ZuiWell defaults to 'static' and 'animated' attr when added animates well", async () => {
    const getShadowWell = () => element.shadowRoot!.querySelector('.well');
    const shadowWellStyles = () => window.getComputedStyle(getShadowWell());
    let animationStyles = shadowWellStyles().getPropertyValue('animation-name');
    assert.isTrue(animationStyles.includes('none'));
    element.setAttribute('animated', '');
    await element.updateComplete;
    animationStyles = shadowWellStyles().getPropertyValue('animation-name');
    assert.isTrue(animationStyles.includes('well-appear'));
  });

  suite('ZuiWell properties reflects attributes', () => {
    test('type property reflects attribute', async () => {
      element.type = 'warning';
      await element.updateComplete;
      const typeAttr = element.getAttribute('type');
      assert.equal(typeAttr, 'warning');
    });

    test('noIcon property reflects attribute', async () => {
      element.noIcon = true;
      await element.updateComplete;
      const noIconAttr = element.getAttribute('no-icon');
      assert.isNotNull(noIconAttr);
    });

    test('dismissible property reflects attribute', async () => {
      element.dismissible = true;
      await element.updateComplete;
      const dismissibleAttr = element.getAttribute('dismissible');
      assert.isNotNull(dismissibleAttr);
    });

    test('banner property reflects attribute', async () => {
      element.banner = true;
      await element.updateComplete;
      const bannerAttr = element.getAttribute('banner');
      assert.isNotNull(bannerAttr);
    });

    test('animated property reflects attribute', async () => {
      element.animated = true;
      await element.updateComplete;
      const animatedAttr = element.getAttribute('animated');
      assert.isNotNull(animatedAttr);
    });
  });
});
