import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'

expect.extend(toHaveNoViolations)

import './datepicker'
import '../calendar/calendar'
import { PktDatepicker } from './datepicker'

const waitForCustomElements = async () => {
  await customElements.whenDefined('pkt-datepicker')
  await customElements.whenDefined('pkt-calendar')
}

// Helper function to create datepicker markup
const createDatepicker = async (datepickerProps = '') => {
  const container = document.createElement('div')
  container.innerHTML = `
    <pkt-datepicker ${datepickerProps}></pkt-datepicker>
  `
  document.body.appendChild(container)
  await waitForCustomElements()
  return container
}

// Cleanup after each test
afterEach(() => {
  document.body.innerHTML = ''
})

describe('PktDatepicker', () => {
  describe('Event handling', () => {
    test('dispatches change event when value changes', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      let changeEventFired = false
      datepicker.addEventListener('change', () => {
        changeEventFired = true
      })

      const input = datepicker.querySelector('input') as HTMLInputElement
      fireEvent.change(input, { target: { value: '2024-06-15' } })
      fireEvent.blur(input)
      await datepicker.updateComplete

      expect(changeEventFired).toBe(true)
    })

    test('dispatches input event during typing', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      let inputEventFired = false
      datepicker.addEventListener('input', () => {
        inputEventFired = true
      })

      const input = datepicker.querySelector('input') as HTMLInputElement
      fireEvent.input(input, { target: { value: '2024-06-15' } })
      await datepicker.updateComplete

      expect(inputEventFired).toBe(true)
    })

    test('dispatches focus and blur events', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      let focusEventFired = false
      let blurEventFired = false

      datepicker.addEventListener('focus', () => {
        focusEventFired = true
      })
      datepicker.addEventListener('blur', () => {
        blurEventFired = true
      })

      const input = datepicker.querySelector('input') as HTMLInputElement
      fireEvent.focus(input)
      await datepicker.updateComplete
      fireEvent.blur(input)
      await datepicker.updateComplete

      expect(focusEventFired).toBe(true)
      expect(blurEventFired).toBe(true)
    })
  })

  describe('Accessibility', () => {
    test('has no accessibility violations', async () => {
      const container = await createDatepicker(
        'label="Test Datepicker" helptext="Select your date"',
      )

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const results = await axe(datepicker)
      expect(results).toHaveNoViolations()
    })

    test('associates label with input correctly', async () => {
      const container = await createDatepicker('id="test-datepicker" label="Test Label"')

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const label = datepicker.querySelector('label')
      const input = datepicker.querySelector('input')

      expect(label).toHaveAttribute('for')
      expect(input).toHaveAttribute('id')
      expect(label?.getAttribute('for')).toBe(input?.getAttribute('id'))
    })

    test('has proper ARIA attributes for calendar button', async () => {
      const container = await createDatepicker('label="Test Datepicker"')

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const calendarButton = datepicker.querySelector('button[type="button"]')
      expect(calendarButton).toBeInTheDocument()

      // Check initial state
      expect(datepicker.calendarOpen).toBe(false)

      // Open calendar
      fireEvent.click(calendarButton!)
      await datepicker.updateComplete

      expect(datepicker.calendarOpen).toBe(true)
    })

    test('provides proper screen reader announcements', async () => {
      const container = await createDatepicker('label="Test Datepicker"')

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const input = datepicker.querySelector('input')
      expect(input).toHaveAttribute('aria-describedby')
    })

    test('handles focus management correctly', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement

      // Focus should be manageable
      if (calendarButton) {
        calendarButton.focus()
        expect(document.activeElement).toBe(calendarButton)
      }
    })

    test('supports keyboard-only interaction', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      await datepicker.updateComplete

      const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement

      // Should open with keyboard
      if (calendarButton) {
        calendarButton.focus()
        fireEvent.keyDown(calendarButton, { key: 'Enter' })
        await datepicker.updateComplete

        expect(datepicker.calendarOpen).toBe(true)
      }

      // Should close with keyboard
      fireEvent.keyDown(datepicker, { key: 'Escape' })
      await datepicker.updateComplete

      expect(datepicker.calendarOpen).toBe(false)
    })
  })
})
