/* eslint-disable vue/one-component-per-file -- each test defines its own
   inline host component to exercise a distinct UiToggleGroup scenario. */
import { render } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import { describe, expect, test } from 'vitest';
import { ref, nextTick, defineComponent } from 'vue';
import UiToggleGroup from '../UiToggleGroup.vue';
import UiToggleGroupItem from '../UiToggleGroupItem.vue';

describe('UiToggleGroup', () => {
  describe('Rendering', () => {
    test('renders toggle group', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'single' },
        slots: { default: '<button>Item</button>' },
      });
      const group = container.querySelector('[data-slot="toggle-group"]');
      expect(group).toBeInTheDocument();
    });

    test('renders with multiple type', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'multiple' },
        slots: { default: '<button>Item</button>' },
      });
      const group = container.querySelector('[data-slot="toggle-group"]');
      expect(group).toBeInTheDocument();
    });

    test('applies flex layout classes', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'single' },
        slots: { default: '<button>Item</button>' },
      });
      const group = container.querySelector('[data-slot="toggle-group"]');
      expect(group).toHaveClass('flex');
      expect(group).toHaveClass('items-center');
    });
  });

  describe('Single Selection Behavior', () => {
    test('clicking an item selects it', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('A'));
      await nextTick();

      expect(modelValue.value).toBe('a');
    });

    test('clicking a different item deselects the previous one', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('a');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      expect(modelValue.value).toBe('a');

      await user.click(getByText('B'));
      await nextTick();

      expect(modelValue.value).toBe('b');
    });

    test('only one item shows pressed state at a time', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('a');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      const itemA = getByText('A').closest('button');
      const itemB = getByText('B').closest('button');

      expect(itemA).toHaveAttribute('data-state', 'on');
      expect(itemB).toHaveAttribute('data-state', 'off');

      await user.click(getByText('B'));
      await nextTick();

      expect(itemA).toHaveAttribute('data-state', 'off');
      expect(itemB).toHaveAttribute('data-state', 'on');
    });
  });

  describe('Multiple Selection Behavior', () => {
    test('clicking an item adds it to the selection', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string[]>([]);

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="multiple">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('A'));
      await nextTick();

      expect(modelValue.value).toContain('a');
    });

    test('clicking multiple items selects all of them', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string[]>([]);

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="multiple">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('A'));
      await user.click(getByText('B'));
      await nextTick();

      expect(modelValue.value).toContain('a');
      expect(modelValue.value).toContain('b');
      expect(modelValue.value).toHaveLength(2);
    });

    test('clicking a selected item removes it from selection', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string[]>(['a', 'b']);

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="multiple">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('A'));
      await nextTick();

      expect(modelValue.value).not.toContain('a');
      expect(modelValue.value).toContain('b');
    });

    test('multiple items show pressed state simultaneously', async () => {
      const modelValue = ref<string[]>(['a', 'b']);

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="multiple">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      const itemA = getByText('A').closest('button');
      const itemB = getByText('B').closest('button');
      const itemC = getByText('C').closest('button');

      expect(itemA).toHaveAttribute('data-state', 'on');
      expect(itemB).toHaveAttribute('data-state', 'on');
      expect(itemC).toHaveAttribute('data-state', 'off');
    });
  });

  describe('Disabled Group Behavior', () => {
    test('disabled group does not respond to clicks', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('a');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single" disabled>
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('B'));
      await nextTick();

      expect(modelValue.value).toBe('a');
    });

    test('disabled group items have disabled attribute', () => {
      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        template: `
          <UiToggleGroup type="single" disabled>
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b">B</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      expect(getByText('A').closest('button')).toBeDisabled();
      expect(getByText('B').closest('button')).toBeDisabled();
    });
  });

  describe('Individual Disabled Item Behavior', () => {
    test('disabled item does not respond to clicks', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('a');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b" disabled>B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('B'));
      await nextTick();

      expect(modelValue.value).toBe('a');
    });

    test('only disabled item has disabled attribute', () => {
      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        template: `
          <UiToggleGroup type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b" disabled>B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      expect(getByText('A').closest('button')).not.toBeDisabled();
      expect(getByText('B').closest('button')).toBeDisabled();
      expect(getByText('C').closest('button')).not.toBeDisabled();
    });

    test('non-disabled items still work when one item is disabled', async () => {
      const user = userEvent.setup();
      const modelValue = ref<string>('a');

      const Component = defineComponent({
        components: { UiToggleGroup, UiToggleGroupItem },
        setup() {
          return { modelValue };
        },
        template: `
          <UiToggleGroup v-model="modelValue" type="single">
            <UiToggleGroupItem value="a">A</UiToggleGroupItem>
            <UiToggleGroupItem value="b" disabled>B</UiToggleGroupItem>
            <UiToggleGroupItem value="c">C</UiToggleGroupItem>
          </UiToggleGroup>
        `,
      });

      const { getByText } = render(Component);

      await user.click(getByText('C'));
      await nextTick();

      expect(modelValue.value).toBe('c');
    });
  });

  describe('UiToggleGroupItem', () => {
    test('renders toggle group item within group', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'single' },
        slots: {
          default: {
            components: { UiToggleGroupItem },
            template:
              '<UiToggleGroupItem value="test">Test</UiToggleGroupItem>',
          },
        },
        global: {
          components: { UiToggleGroupItem },
        },
      });
      const item = container.querySelector('[data-slot="toggle-group-item"]');
      expect(item).toBeInTheDocument();
    });

    test('items use muted-subtle hover fill', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'single' },
        slots: {
          default: {
            components: { UiToggleGroupItem },
            template:
              '<UiToggleGroupItem value="test">Test</UiToggleGroupItem>',
          },
        },
        global: {
          components: { UiToggleGroupItem },
        },
      });
      const item = container.querySelector('[data-slot="toggle-group-item"]');
      expect(item).toHaveClass('hover:bg-background-surface-muted-subtle');
    });

    test('renders multiple items within group', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'multiple' },
        slots: {
          default: {
            components: { UiToggleGroupItem },
            template: `
              <UiToggleGroupItem value="a">A</UiToggleGroupItem>
              <UiToggleGroupItem value="b">B</UiToggleGroupItem>
            `,
          },
        },
        global: {
          components: { UiToggleGroupItem },
        },
      });
      const items = container.querySelectorAll(
        '[data-slot="toggle-group-item"]',
      );
      expect(items).toHaveLength(2);
    });

    test('applies soft variant classes to items', () => {
      const { container } = render(UiToggleGroup, {
        props: { type: 'single', variant: 'soft' },
        slots: {
          default: {
            components: { UiToggleGroupItem },
            template: '<UiToggleGroupItem value="a">A</UiToggleGroupItem>',
          },
        },
        global: {
          components: { UiToggleGroupItem },
        },
      });
      const item = container.querySelector('[data-slot="toggle-group-item"]');
      expect(item).toHaveClass('bg-transparent');
      expect(item).toHaveClass('data-[state=on]:bg-accent');
      expect(item).toHaveClass('data-[state=on]:border-accent-default');
      expect(item).toHaveClass('aria-pressed:bg-accent');
      expect(item).toHaveClass('aria-pressed:border-accent-default');
    });
  });
});
