import { render } from '@testing-library/vue';
import { describe, expect, test, vi } from 'vitest';
import {
  UiDrawer,
  UiDrawerClose,
  UiDrawerContent,
  UiDrawerDescription,
  UiDrawerFooter,
  UiDrawerHeader,
  UiDrawerTitle,
  UiDrawerTrigger,
} from '../index';
import { UiButton } from '../../UiButton';
import { ref } from 'vue';

describe('UiDrawer', () => {
  test('emits update:open when trigger is clicked', async () => {
    const onUpdateOpen = vi.fn();
    const { getByText } = render({
      components: {
        UiDrawer,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
      },
      setup() {
        return { onUpdateOpen };
      },
      template: `
        <UiDrawer @update:open="onUpdateOpen">
          <UiDrawerTrigger>Open</UiDrawerTrigger>
          <UiDrawerContent>
            <UiDrawerHeader>
              <UiDrawerTitle>Title</UiDrawerTitle>
              <UiDrawerDescription>Description</UiDrawerDescription>
            </UiDrawerHeader>
            Content
          </UiDrawerContent>
        </UiDrawer>
      `,
    });

    await getByText('Open').click();
    expect(onUpdateOpen).toHaveBeenCalledWith(true);
  });

  test('works with as-child pattern and UiButton', async () => {
    const onUpdateOpen = vi.fn();
    const { getByRole } = render({
      components: {
        UiDrawer,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
        UiButton,
      },
      setup() {
        return { onUpdateOpen };
      },
      template: `
        <UiDrawer @update:open="onUpdateOpen">
          <UiDrawerTrigger as-child>
            <UiButton variant="outline">Open Drawer</UiButton>
          </UiDrawerTrigger>
          <UiDrawerContent>
            <UiDrawerHeader>
              <UiDrawerTitle>Title</UiDrawerTitle>
              <UiDrawerDescription>Description</UiDrawerDescription>
            </UiDrawerHeader>
            Content
          </UiDrawerContent>
        </UiDrawer>
      `,
    });

    await getByRole('button', { name: 'Open Drawer' }).click();
    expect(onUpdateOpen).toHaveBeenCalledWith(true);
  });

  test('closes via UiDrawerClose', async () => {
    const onUpdateOpen = vi.fn();
    const { getByRole, getByText } = render({
      components: {
        UiDrawer,
        UiDrawerClose,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerFooter,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
      },
      setup() {
        return { onUpdateOpen };
      },
      template: `
        <UiDrawer @update:open="onUpdateOpen">
          <UiDrawerTrigger>Open</UiDrawerTrigger>
          <UiDrawerContent>
            <UiDrawerHeader>
              <UiDrawerTitle>Title</UiDrawerTitle>
              <UiDrawerDescription>Description</UiDrawerDescription>
            </UiDrawerHeader>
            <UiDrawerFooter>
              <UiDrawerClose>Close</UiDrawerClose>
            </UiDrawerFooter>
          </UiDrawerContent>
        </UiDrawer>
      `,
    });

    await getByText('Open').click();
    expect(getByRole('dialog')).toBeInTheDocument();

    await getByText('Close').click();
    expect(onUpdateOpen).toHaveBeenCalledWith(false);
  });

  test('emits escapeKeyDown and closes when Escape is pressed', async () => {
    const onEscapeKeyDown = vi.fn();
    const onUpdateOpen = vi.fn();
    const { getByText, getByRole } = render({
      components: {
        UiDrawer,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
      },
      setup() {
        return { onEscapeKeyDown, onUpdateOpen };
      },
      template: `
        <UiDrawer @update:open="onUpdateOpen">
          <UiDrawerTrigger>Open</UiDrawerTrigger>
          <UiDrawerContent @escape-key-down="onEscapeKeyDown">
            <UiDrawerHeader>
              <UiDrawerTitle>Title</UiDrawerTitle>
              <UiDrawerDescription>Description</UiDrawerDescription>
            </UiDrawerHeader>
            Content
          </UiDrawerContent>
        </UiDrawer>
      `,
    });

    await getByText('Open').click();
    expect(getByRole('dialog')).toBeInTheDocument();

    await getByRole('dialog').dispatchEvent(
      new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }),
    );

    expect(onEscapeKeyDown).toHaveBeenCalled();
    expect(onUpdateOpen).toHaveBeenCalledWith(false);
  });

  test('forwards class to the underlying drawer content element', async () => {
    const { getByText, getByRole } = render({
      components: {
        UiDrawer,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
      },
      template: `
        <UiDrawer>
          <UiDrawerTrigger>Open</UiDrawerTrigger>
          <UiDrawerContent class="my-drawer-class">
            <UiDrawerHeader>
              <UiDrawerTitle>Title</UiDrawerTitle>
              <UiDrawerDescription>Description</UiDrawerDescription>
            </UiDrawerHeader>
            Content
          </UiDrawerContent>
        </UiDrawer>
      `,
    });

    await getByText('Open').click();
    expect(getByRole('dialog')).toHaveClass('my-drawer-class');
  });

  test('supports controlled mode via v-model:open', async () => {
    const { getByRole, getByText } = render({
      components: {
        UiDrawer,
        UiDrawerContent,
        UiDrawerDescription,
        UiDrawerHeader,
        UiDrawerTitle,
        UiDrawerTrigger,
      },
      setup() {
        const open = ref(false);
        return { open };
      },
      template: `
        <div>
          <button type="button" @click="open = true">Open via model</button>
          <button type="button" @click="open = false">Close via model</button>
          <UiDrawer v-model:open="open">
            <UiDrawerTrigger>Open</UiDrawerTrigger>
            <UiDrawerContent>
              <UiDrawerHeader>
                <UiDrawerTitle>Title</UiDrawerTitle>
                <UiDrawerDescription>Description</UiDrawerDescription>
              </UiDrawerHeader>
              Content
            </UiDrawerContent>
          </UiDrawer>
        </div>
      `,
    });

    await getByText('Open via model').click();
    expect(getByRole('dialog')).toHaveAttribute('data-state', 'open');

    await getByText('Close via model').click();
    expect(getByRole('dialog')).toHaveAttribute('data-state', 'closed');
  });
});
