import '@testing-library/jest-dom'

import { cleanup, fireEvent, render, waitFor } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import { vi } from 'vitest'

import { PktAlert } from './Alert'

expect.extend(toHaveNoViolations)

afterEach(cleanup)

describe('PktAlert', () => {
  test('calls onClose when close button is clicked', async () => {
    const onClose = vi.fn()
    const { getByLabelText } = render(
      <PktAlert closeAlert={true} onClose={onClose}>
        Hello World
      </PktAlert>,
    )
    fireEvent.click(getByLabelText('close'))
    await waitFor(() => {
      expect(onClose).toHaveBeenCalledTimes(1)
    })
  })

  test('renders with default role', async () => {
    const { getByRole } = render(<PktAlert>Alert text</PktAlert>)
    const alert = getByRole('status')
    expect(alert).toBeInTheDocument()
    expect(alert).toHaveAttribute('role', 'status')
  })

  test('renders with alert as role prop', async () => {
    const { getByRole } = render(<PktAlert role="alert">Alert text</PktAlert>)
    const alert = getByRole('alert')
    expect(alert).toBeInTheDocument()
    expect(alert).toHaveAttribute('role', 'alert')
  })

  test.each`
    camelCase      | kebabCase      | rendered
    ${'assertive'} | ${undefined}   | ${'assertive'}
    ${undefined}   | ${'assertive'} | ${'assertive'}
    ${'polite'}    | ${undefined}   | ${'polite'}
    ${undefined}   | ${undefined}   | ${'polite'}
    ${'off'}       | ${'assertive'} | ${'off'}
  `(
    'should support both ariaLive ($camelCase) and aria-live ($kebabCase) attributes ',
    async ({ camelCase, kebabCase, rendered }) => {
      const { container } = render(
        <PktAlert ariaLive={camelCase} aria-live={kebabCase}>
          Alert text
        </PktAlert>,
      )
      const elementThatHasAriaLive = container.querySelector('*[aria-live]')
      expect(elementThatHasAriaLive).toHaveAttribute('aria-live', rendered)
    },
  )

  test.each`
    title             | expected
    ${'Simple title'} | ${'Simple title'}
    ${''}             | ${undefined}
    ${null}           | ${undefined}
    ${(
  <span>
    Complex <strong>title</strong>
  </span>
)} | ${'<span>Complex <strong>title</strong></span>'}
  `('support complex title %$', async ({ title, expected }) => {
    const { container } = render(<PktAlert title={title}>Alert text</PktAlert>)
    const titleElement = container.querySelector('.pkt-alert__title')
    expect(titleElement?.innerHTML).toEqual(expected)
  })

  describe('size and compact', () => {
    test('renders with pkt-alert--medium by default', async () => {
      const { container } = render(<PktAlert>Alert text</PktAlert>)
      const alert = container.querySelector('.pkt-alert')
      expect(alert).toHaveClass('pkt-alert--medium')
      expect(alert).not.toHaveClass('pkt-alert--compact')
    })

    test.each`
      size        | expectedClass
      ${'small'}  | ${'pkt-alert--small'}
      ${'xsmall'} | ${'pkt-alert--xsmall'}
    `('renders with $expectedClass when size is $size', async ({ size, expectedClass }) => {
      const { container } = render(<PktAlert size={size}>Alert text</PktAlert>)
      const alert = container.querySelector('.pkt-alert')
      expect(alert).toHaveClass(expectedClass)
      expect(alert).not.toHaveClass('pkt-alert--medium')
    })

    test('renders with pkt-alert--small when compact is set without size', async () => {
      const { container } = render(<PktAlert compact>Alert text</PktAlert>)
      const alert = container.querySelector('.pkt-alert')
      expect(alert).toHaveClass('pkt-alert--small')
      expect(alert).not.toHaveClass('pkt-alert--compact')
      expect(alert).not.toHaveClass('pkt-alert--medium')
    })

    test('explicit size wins over compact', async () => {
      const { container } = render(
        <PktAlert compact size="xsmall">
          Alert text
        </PktAlert>,
      )
      const alert = container.querySelector('.pkt-alert')
      expect(alert).toHaveClass('pkt-alert--xsmall')
      expect(alert).not.toHaveClass('pkt-alert--compact')
      expect(alert).not.toHaveClass('pkt-alert--small')
    })
  })

  describe('accessibility', () => {
    test('renders with no wcag errors with axe', async () => {
      const { container } = render(<PktAlert title="Error" skin="error"></PktAlert>)
      const results = await axe(container)

      expect(results).toHaveNoViolations()
    })
  })
})
