import '@testing-library/jest-dom/vitest';
import { render, waitFor } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test, vi } from 'vitest';
import { ref } from 'vue';
import {
  UiStepper,
  UiStepperItem,
  UiStepperTrigger,
  UiStepperIndicator,
  UiStepperTitle,
  UiStepperDescription,
  UiStepperSeparator,
} from '../index';

const components = {
  UiStepper,
  UiStepperItem,
  UiStepperTrigger,
  UiStepperIndicator,
  UiStepperTitle,
  UiStepperDescription,
  UiStepperSeparator,
};

const stepperTemplate = `
  <UiStepper v-bind="stepperProps" v-on="stepperEvents">
    <UiStepperItem :step="1">
      <UiStepperTrigger>
        <UiStepperIndicator>1</UiStepperIndicator>
        <UiStepperTitle>Step 1</UiStepperTitle>
      </UiStepperTrigger>
      <UiStepperSeparator />
    </UiStepperItem>
    <UiStepperItem :step="2">
      <UiStepperTrigger>
        <UiStepperIndicator>2</UiStepperIndicator>
        <UiStepperTitle>Step 2</UiStepperTitle>
      </UiStepperTrigger>
      <UiStepperSeparator />
    </UiStepperItem>
    <UiStepperItem :step="3">
      <UiStepperTrigger>
        <UiStepperIndicator>3</UiStepperIndicator>
        <UiStepperTitle>Step 3</UiStepperTitle>
      </UiStepperTrigger>
    </UiStepperItem>
  </UiStepper>
`;

describe('UiStepper', () => {
  test('activates step specified by defaultValue prop', () => {
    const { getAllByRole } = render({
      components,
      template: stepperTemplate,
      setup() {
        return {
          stepperProps: { defaultValue: 2, linear: false },
          stepperEvents: {},
        };
      },
    });

    const triggers = getAllByRole('button');
    expect(triggers[0]).toHaveAttribute('data-state', 'completed');
    expect(triggers[1]).toHaveAttribute('data-state', 'active');
    expect(triggers[2]).toHaveAttribute('data-state', 'inactive');
  });

  test('emits update:modelValue when a step trigger is clicked', async () => {
    const user = userEvent.setup();
    const onUpdateModelValue = vi.fn();

    const { getAllByRole } = render({
      components,
      template: stepperTemplate,
      setup() {
        return {
          stepperProps: { defaultValue: 1, linear: false },
          stepperEvents: { 'update:modelValue': onUpdateModelValue },
        };
      },
    });

    const triggers = getAllByRole('button');
    expect(triggers.length).toBe(3);

    await user.click(triggers[1]);

    expect(onUpdateModelValue).toHaveBeenCalledWith(2);
  });

  test('reflects controlled modelValue and updates when it changes', async () => {
    const modelValue = ref(1);

    const { getAllByRole } = render({
      components,
      template: `
        <UiStepper v-model="modelValue" :linear="false">
          <UiStepperItem :step="1">
            <UiStepperTrigger>
              <UiStepperIndicator>1</UiStepperIndicator>
              <UiStepperTitle>Step 1</UiStepperTitle>
            </UiStepperTrigger>
            <UiStepperSeparator />
          </UiStepperItem>
          <UiStepperItem :step="2">
            <UiStepperTrigger>
              <UiStepperIndicator>2</UiStepperIndicator>
              <UiStepperTitle>Step 2</UiStepperTitle>
            </UiStepperTrigger>
          </UiStepperItem>
        </UiStepper>
      `,
      setup() {
        return { modelValue };
      },
    });

    const triggers = getAllByRole('button');
    expect(triggers[0]).toHaveAttribute('data-state', 'active');
    expect(triggers[1]).toHaveAttribute('data-state', 'inactive');

    modelValue.value = 2;

    await waitFor(() => {
      expect(triggers[0]).toHaveAttribute('data-state', 'completed');
      expect(triggers[1]).toHaveAttribute('data-state', 'active');
    });
  });

  test('does not activate a disabled step when clicked', async () => {
    const user = userEvent.setup();
    const onUpdateModelValue = vi.fn();

    const { getAllByRole } = render({
      components,
      template: `
        <UiStepper :default-value="1" :linear="false" @update:modelValue="onUpdateModelValue">
          <UiStepperItem :step="1">
            <UiStepperTrigger>
              <UiStepperIndicator>1</UiStepperIndicator>
              <UiStepperTitle>Step 1</UiStepperTitle>
            </UiStepperTrigger>
            <UiStepperSeparator />
          </UiStepperItem>
          <UiStepperItem :step="2" :disabled="true">
            <UiStepperTrigger>
              <UiStepperIndicator>2</UiStepperIndicator>
              <UiStepperTitle>Step 2</UiStepperTitle>
            </UiStepperTrigger>
          </UiStepperItem>
        </UiStepper>
      `,
      setup() {
        return { onUpdateModelValue };
      },
    });

    const triggers = getAllByRole('button', { hidden: true });
    const step2Trigger = triggers[1];
    expect(step2Trigger).toBeDisabled();

    await user.click(step2Trigger);

    expect(triggers[0]).toHaveAttribute('data-state', 'active');
    expect(step2Trigger).toHaveAttribute('data-state', 'inactive');
    expect(onUpdateModelValue).not.toHaveBeenCalledWith(2);
  });
});
