import '@testing-library/jest-dom'

import { fireEvent, render as originalRender, RenderOptions, RenderResult } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import { createRef, ReactNode } from 'react'
import { vi } from 'vitest'

import { PktTag } from './Tag'

expect.extend(toHaveNoViolations)

const render = async (
  ui: ReactNode,
  options?: Omit<RenderOptions, 'queries'> | undefined,
): Promise<RenderResult> => {
  const renderResult = originalRender(ui, options)
  await window.customElements.whenDefined('pkt-icon')
  return Promise.resolve(renderResult)
}

describe('PktTag', () => {
  describe('basic rendering', () => {
    it('renders correctly without any props', async () => {
      const { getByText } = await render(<PktTag>Hello</PktTag>)
      expect(getByText('Hello')).toBeInTheDocument()
    })

    it('renders an icon when iconName prop is provided', async () => {
      await render(<PktTag iconName="user">Tag with Icon</PktTag>)
      const iconElement = document.querySelector('.pkt-tag__icon.pkt-icon[name="user"]')
      expect(iconElement).toBeInTheDocument()
    })

    it('renders with the specified skin and size', async () => {
      const { container } = await render(
        <PktTag skin="red" size="small">
          Tag
        </PktTag>,
      )

      const spanElement = container.querySelector('span.pkt-tag')

      expect(spanElement).toHaveClass('pkt-tag--red')
      expect(spanElement).toHaveClass('pkt-tag--small')
    })

    it('forwardRef works correctly', async () => {
      const ref = createRef<HTMLButtonElement>()
      const { unmount } = await render(
        <PktTag closeTag={true} ref={ref}>
          Click me
        </PktTag>,
      )
      expect(ref.current).toBeInstanceOf(HTMLElement)
      unmount()
      expect(ref.current).toBeNull()
    })

    it('closes the tag when the close button is clicked', async () => {
      const { container, getByText } = await render(<PktTag closeTag={true}>Closeable Tag</PktTag>)

      const buttonElement = container.querySelector('.pkt-tag.pkt-btn')
      expect(buttonElement).not.toHaveClass('pkt-hide')

      fireEvent.click(getByText('Closeable Tag'))

      expect(buttonElement).toBeInTheDocument()
      expect(buttonElement).toHaveClass('pkt-hide')
    })

    it('calls onClose when tag is clicked', async () => {
      const onClose = vi.fn()
      const { getByText } = await render(
        <PktTag closeTag={true} onClose={onClose}>
          Closeable Tag
        </PktTag>,
      )
      fireEvent.click(getByText('Closeable Tag'))
      expect(onClose).toHaveBeenCalled()
    })
  })

  describe('accessibility', () => {
    it('renders with no wcag errors with axe', async () => {
      const { container } = await render(
        <PktTag skin="red" size="small" iconName="user" closeTag={true}>
          Tag
        </PktTag>,
      )
      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })
  })
})
