import { render } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test } from 'vitest';
import { MockIcon } from '@/__tests__/test-utils';
import UiButton from '../UiButton.vue';

describe('UiButton', () => {
  test('renders as button with slot content and type="button"', () => {
    const { getByRole } = render(UiButton, {
      slots: { default: 'Click me' },
    });
    const button = getByRole('button');
    expect(button).toHaveTextContent('Click me');
    expect(button).toHaveAttribute('type', 'button');
  });

  describe('Variants (contract test)', () => {
    const variants = [
      'default',
      'destructive',
      'outline',
      'secondary',
      'ghost',
      'link',
    ] as const;

    test.each(variants)('accepts variant="%s"', (variant) => {
      const { getByRole } = render(UiButton, {
        props: { variant },
        slots: { default: 'Button' },
      });
      expect(getByRole('button')).toBeInTheDocument();
    });
  });

  describe('Sizes (contract test)', () => {
    const sizes = ['default', 'xs', 'sm', 'lg'] as const;

    test.each(sizes)('accepts size="%s"', (size) => {
      const { getByRole } = render(UiButton, {
        props: { size },
        slots: { default: 'Button' },
      });
      expect(getByRole('button')).toBeInTheDocument();
    });
  });

  test('emits click event when clicked', async () => {
    const user = userEvent.setup();
    const { getByRole, emitted } = render(UiButton, {
      slots: { default: 'Click' },
    });

    await user.click(getByRole('button'));

    expect(emitted('click')).toHaveLength(1);
  });

  test('is disabled when disabled prop is true', () => {
    const { getByRole } = render(UiButton, {
      props: { disabled: true },
      slots: { default: 'Button' },
    });
    expect(getByRole('button')).toBeDisabled();
  });

  describe('Loading State', () => {
    test('is disabled with aria-busy and shows spinner when loading', () => {
      const { getByRole, getByLabelText } = render(UiButton, {
        props: { loading: true },
        slots: { default: 'Button' },
      });
      const button = getByRole('button');
      expect(button).toBeDisabled();
      expect(button).toHaveAttribute('aria-busy', 'true');
      expect(getByLabelText('Loading')).toBeInTheDocument();
    });

    test('hides startIcon when loading', () => {
      const { queryByTestId } = render(UiButton, {
        props: { loading: true, startIcon: MockIcon },
        slots: { default: 'Button' },
      });
      expect(queryByTestId('mock-icon')).not.toBeInTheDocument();
    });
  });

  test('applies aria-label when provided', () => {
    const { getByRole } = render(UiButton, {
      props: { ariaLabel: 'Custom label' },
      slots: { default: 'Button' },
    });
    expect(getByRole('button')).toHaveAttribute('aria-label', 'Custom label');
  });

  describe('Icons', () => {
    test('renders startIcon when provided', () => {
      const { getByTestId } = render(UiButton, {
        props: { startIcon: MockIcon },
        slots: { default: 'Button' },
      });
      expect(getByTestId('mock-icon')).toBeInTheDocument();
    });

    test('renders endIcon when provided', () => {
      const { getByTestId } = render(UiButton, {
        props: { endIcon: MockIcon },
        slots: { default: 'Button' },
      });
      expect(getByTestId('mock-icon')).toBeInTheDocument();
    });
  });

  describe('asChild Mode', () => {
    test('does not render startIcon in asChild mode', () => {
      const { queryByTestId } = render(UiButton, {
        props: { startIcon: MockIcon, asChild: true },
        slots: { default: 'Button' },
      });
      expect(queryByTestId('mock-icon')).not.toBeInTheDocument();
    });

    test('does not render endIcon in asChild mode', () => {
      const { queryByTestId } = render(UiButton, {
        props: { endIcon: MockIcon, asChild: true },
        slots: { default: 'Button' },
      });
      expect(queryByTestId('mock-icon')).not.toBeInTheDocument();
    });
  });
});
