import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import MNavigationIndicator from './MNavigationIndicator.vue';

const PauseCircle24 = {
  name: 'PauseCircle24',
  template: '<span data-testid="pause-icon"></span>',
};
const PlayCircle24 = {
  name: 'PlayCircle24',
  template: '<span data-testid="play-icon"></span>',
};

const MButton = {
  name: 'MButton',
  props: ['size', 'iconPosition', 'ghost'],
  template: `
    <button data-testid="m-button">
      <slot />

      <slot name="icon" />
      <slot />
    </button>
  `,
};

const MIconButton = {
  name: 'MIconButton',
  props: ['size', 'ghost'],
  template: `<button data-testid="m-icon-button"><slot name="icon" /></button>`,
};

describe('MNavigationIndicator.vue', () => {
  it('renders the correct number of steps', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 4, modelValue: 0 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const items = wrapper.findAll('.mc-navigation-indicator__item');
    expect(items).toHaveLength(4);
  });

  it('applies active class to the current step', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 5, modelValue: 2 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const stepButtons = wrapper.findAll(
      '.mc-navigation-indicator__list .mc-navigation-indicator__button',
    );
    expect(stepButtons[2].classes()).toContain(
      'mc-navigation-indicator__button--active',
    );
  });

  it('emits update:modelValue when a step is clicked', async () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 3, modelValue: 0 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const stepButtons = wrapper.findAll(
      '.mc-navigation-indicator__list .mc-navigation-indicator__button',
    );
    await stepButtons[1].trigger('click');

    const emitted = wrapper.emitted('update:modelValue');
    expect(emitted).toBeTruthy();
    expect(emitted![0][0]).toBe(1);
  });

  it('does not emit update:modelValue when a wrong key is pressed', async () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 3, modelValue: 0 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const stepButtons = wrapper.findAll(
      '.mc-navigation-indicator__list .mc-navigation-indicator__button',
    );
    await stepButtons[2].trigger('keydown', { key: 'Esc' });

    const emitted = wrapper.emitted('update:modelValue');
    expect(emitted).toBeFalsy();
  });

  it('does not render action button when player is false', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, player: false },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    expect(wrapper.find('[data-testid="m-button"]').exists()).toBe(false);
    expect(wrapper.find('[data-testid="m-icon-button"]').exists()).toBe(false);
  });

  it('renders icon-only button when no label is defined', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, action: 'resume' },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    expect(wrapper.find('[data-testid="m-icon-button"]').exists()).toBe(true);
    expect(wrapper.find('[data-testid="play-icon"]').exists()).toBe(true);
  });

  it('renders labeled button with correct label and pause icon when action is pause', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, label: 'Pause', action: 'pause' },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const button = wrapper.find('[data-testid="m-button"]');
    expect(button.exists()).toBe(true);
    expect(button.text()).toContain('Pause');
    expect(wrapper.find('[data-testid="pause-icon"]').exists()).toBe(true);
  });

  it('renders a navigation landmark with an aria-label', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 3, modelValue: 0 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const navigation = wrapper.find('nav[aria-label="Navigation steps"]');
    expect(navigation.exists()).toBe(true);
    expect(navigation.attributes('aria-label')).toBe('Navigation steps');
  });

  it('player icon button has aria-label reflecting action state', () => {
    const wrapperPause = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, action: 'pause' },
      global: { stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 } },
    });
    expect(
      wrapperPause
        .find('[data-testid="m-icon-button"]')
        .attributes('aria-label'),
    ).toBe('Pause');

    const wrapperResume = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, action: 'resume' },
      global: { stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 } },
    });
    expect(
      wrapperResume
        .find('[data-testid="m-icon-button"]')
        .attributes('aria-label'),
    ).toBe('Resume');
  });

  it('gives each step button an action-oriented aria-label', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 3, modelValue: 1 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const buttons = wrapper.findAll('.mc-navigation-indicator__button');
    expect(buttons[0].attributes('aria-label')).toBe('Go to step 1 of 3');
    expect(buttons[1].attributes('aria-label')).toBe('Current step, 2 of 3');
    expect(buttons[2].attributes('aria-label')).toBe('Go to step 3 of 3');
  });

  it('sets aria-current="step" only on the active step button', () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 3, modelValue: 1 },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    const buttons = wrapper.findAll('.mc-navigation-indicator__button');
    expect(buttons[1].attributes('aria-current')).toBe('step');
    expect(buttons[0].attributes('aria-current')).not.toBe('step');
    expect(buttons[2].attributes('aria-current')).not.toBe('step');
  });

  it('emits "action" when the player button is clicked', async () => {
    const wrapper = mount(MNavigationIndicator, {
      props: { steps: 2, modelValue: 0, action: 'resume' },
      global: {
        stubs: { MButton, MIconButton, PauseCircle24, PlayCircle24 },
      },
    });

    await wrapper.find('[data-testid="m-icon-button"]').trigger('click');
    expect(wrapper.emitted('action')).toBeTruthy();
  });
});
