import '@testing-library/jest-dom/vitest';
import { render, waitFor } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test } from 'vitest';
import {
  UiSelect,
  UiSelectTrigger,
  UiSelectContent,
  UiSelectItem,
  UiSelectValue,
} from '../index';
import { UiIcon } from '../../UiIcon';

describe('UiSelectItem', () => {
  test('applies custom class', async () => {
    const user = userEvent.setup();
    const { getByRole } = render({
      components: {
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect>
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="a" class="font-bold">Option A</UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

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

    await waitFor(() => {
      expect(getByRole('option')).toHaveClass('font-bold');
    });
  });

  test('disabled item has data-disabled attribute', async () => {
    const user = userEvent.setup();
    const { getByRole } = render({
      components: {
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect>
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="disabled" :disabled="true">Disabled Option</UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

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

    await waitFor(() => {
      expect(getByRole('option', { name: 'Disabled Option' })).toHaveAttribute(
        'data-disabled',
        '',
      );
    });
  });

  test('renders right icon and keeps indicator on the right in single select', async () => {
    const user = userEvent.setup();
    const { getByRole, getByTestId } = render({
      components: {
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect default-value="a">
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="a">
              Option A
              <template #right-icon>
                <span data-testid="right-icon" aria-hidden="true">i</span>
              </template>
            </UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

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

    const option = getByRole('option', { name: 'Option A' });
    const end = option.querySelector('[data-slot="select-item-end"]');

    expect(getByTestId('right-icon')).toBeInTheDocument();
    expect(end).toHaveClass('!absolute');
    expect(end).toHaveClass('right-2');
  });

  test('preserves UiIcon size prop inside select items', async () => {
    const user = userEvent.setup();
    const { getByRole, getByTestId } = render({
      components: {
        UiIcon,
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect>
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="line">
              <UiIcon name="chart-line" size="m" data-testid="chart-icon" />
              Line
            </UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

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

    expect(getByTestId('chart-icon')).toHaveAttribute('width', '20');
    expect(getByTestId('chart-icon')).toHaveAttribute('height', '20');
    expect(getByRole('option', { name: 'Line' })).toHaveClass(
      "[&_svg:not([data-slot=icon]):not([class*='size-'])]:size-4",
    );
  });

  test('renders right icon and keeps indicator on the right in multi select', async () => {
    const user = userEvent.setup();
    const { getByRole, getByTestId } = render({
      components: {
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect :multiple="true" :default-value="['a']">
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="a">
              Option A
              <template #right-icon>
                <span data-testid="multi-right-icon" aria-hidden="true">i</span>
              </template>
            </UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

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

    const option = getByRole('option', { name: 'Option A' });
    const end = option.querySelector('[data-slot="select-item-end"]');

    expect(getByTestId('multi-right-icon')).toBeInTheDocument();
    expect(end).toHaveClass('!absolute');
    expect(end).toHaveClass('right-2');
  });

  test('cannot select disabled item', async () => {
    const user = userEvent.setup();
    const { getByRole } = render({
      components: {
        UiSelect,
        UiSelectTrigger,
        UiSelectContent,
        UiSelectItem,
        UiSelectValue,
      },
      template: `
        <UiSelect>
          <UiSelectTrigger>
            <UiSelectValue placeholder="Select" />
          </UiSelectTrigger>
          <UiSelectContent>
            <UiSelectItem value="enabled">Enabled Option</UiSelectItem>
            <UiSelectItem value="disabled" :disabled="true">Disabled Option</UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      `,
    });

    await user.click(getByRole('combobox'));
    await waitFor(() => expect(getByRole('listbox')).toBeInTheDocument());

    await user.click(getByRole('option', { name: 'Disabled Option' }));

    // Listbox should still be open after clicking disabled item
    expect(getByRole('listbox')).toBeInTheDocument();
  });
});
