import { h, nextTick, ref } from 'vue';
import { mount, VueWrapper } from '@vue/test-utils';
import type { Slot } from '@vue/test-utils/dist/types';
import MBreadcrumb from '../MBreadcrumbV2.vue';
import MBreadcrumbItem from '../MBreadcrumbItemV2.vue';

describe('MBreadcrumbV2', () => {
  let wrapper: VueWrapper<any>;

  async function init(
    // @ts-ignore
    props: InstanceType<typeof MBreadcrumb>['$props'],
    items: {
      // @ts-ignore
      props: InstanceType<typeof MBreadcrumbItem>['$props'];
      slot: Slot;
    }[],
  ) {
    wrapper = mount(MBreadcrumb, {
      props,
      slots: {
        default: items.map(
          ({ props, slot }) =>
            () =>
              h(MBreadcrumbItem, props, () => slot),
        ),
      },
    });
    await nextTick();
  }

  describe('should display <a> for previous steps, then normal <span> for current', () => {
    it('single', async () => {
      await init({}, [{ props: {}, slot: 'first' }]);

      expect(getItems()).toHaveLength(1);
      expect(getItem(0).find('span').exists()).toBe(true);
    });

    it('multiples', async () => {
      await init({}, [
        { props: {}, slot: 'first' },
        { props: {}, slot: 'second' },
        { props: {}, slot: 'third' },
      ]);

      expect(getItems()).toHaveLength(3);
      expect(getItem(0).find('a').exists()).toBe(true);
      expect(getItem(1).find('a').exists()).toBe(true);
      expect(getItem(2).find('span').exists()).toBe(true);
    });
  });

  it('should display labels', async () => {
    await init({}, [
      { props: {}, slot: 'first' },
      { props: {}, slot: 'second' },
      { props: {}, slot: 'third' },
    ]);

    expect(getItem(0).text()).toContain('first');
    expect(getItem(1).text()).toContain('second');
    expect(getItem(2).text()).toContain('third');
  });

  it.each([false, true])(
    'should apply \'light\' theme to links when \'dark\' enabled',
    async (darkThenLight) => {
      await init({ dark: darkThenLight }, [
        { props: {}, slot: 'first' },
        { props: {}, slot: 'second' },
        { props: {}, slot: 'third' },
      ]);

      expect(getItem(0).find('a').classes().includes('mc-link--light')).toBe(
        darkThenLight,
      );
      expect(getItem(1).find('a').classes().includes('mc-link--light')).toBe(
        darkThenLight,
      );
      expect(getItem(2).find('span').classes().includes('mc-link--light')).toBe(
        darkThenLight,
      );
    },
  );

  it('should apply specific class to last item when responsive', async () => {
    await init({ responsive: true }, [
      { props: {}, slot: 'first' },
      { props: {}, slot: 'second' },
      { props: {}, slot: 'third' },
    ]);

    expect(getItem(0).classes()).not.toContain('is-active');
    expect(getItem(1).classes()).not.toContain('is-active');
    expect(getItem(2).classes()).toContain('is-active');

    expect(getItem(0).html()).not.toContain('mc-breadcrumb__current');
    expect(getItem(1).html()).not.toContain('mc-breadcrumb__current');
    expect(getItem(2).find('span').classes()).toContain(
      'mc-breadcrumb__current',
    );
  });

  it('should be updated when list links updated', async () => {
    const links = ref([0, 1, 2]);

    wrapper = mount({
      components: { MBreadcrumb, MBreadcrumbItem },
      setup() {
        return { links };
      },
      template: `
        <MBreadcrumb>
        <MBreadcrumbItem v-for="link in links">{{ link }}</MBreadcrumbItem>
        </MBreadcrumb>`,
    });
    await nextTick();
    expect(getItems()).toHaveLength(3);
    expect(getItem(0).find('a').exists()).toBe(true);
    expect(getItem(1).find('a').exists()).toBe(true);
    expect(getItem(2).find('span').exists()).toBe(true);

    links.value = [0, 1];
    await nextTick();
    expect(getItems()).toHaveLength(2);
    expect(getItem(0).find('a').exists()).toBe(true);
    expect(getItem(1).find('span').exists()).toBe(true);

    links.value = [0, 1, 2, 3];
    await nextTick();
    expect(getItems()).toHaveLength(4);
    expect(getItem(0).find('a').exists()).toBe(true);
    expect(getItem(1).find('a').exists()).toBe(true);
    expect(getItem(2).find('a').exists()).toBe(true);
    expect(getItem(3).find('span').exists()).toBe(true);
  });

  function getItems() {
    return wrapper.findAll('ul > li');
  }

  function getItem(index: number) {
    return getItems()[index];
  }
});
