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

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('Date input validation and formatting', () => {
    test('validates date input format', async () => {
      const container = await createDatepicker('label="Test"')

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

      const input = datepicker.querySelector('input') as HTMLInputElement

      // Test invalid date input - HTML5 date inputs will reject invalid formats
      // For date inputs, we test boundary validation instead
      fireEvent.change(input, { target: { value: '2024-02-30' } }) // Invalid date (Feb 30th)
      fireEvent.blur(input)
      await datepicker.updateComplete

      // Should show validation error or handle gracefully
      // For HTML5 date inputs, this might not trigger hasError, so we test that it doesn't crash
      expect(datepicker).toBeInTheDocument()
    })

    test('formats dates according to dateformat property', async () => {
      const container = await createDatepicker('dateformat="yyyy-MM-dd" value="2024-06-15"')

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

      const input = datepicker.querySelector('input') as HTMLInputElement
      expect(input.value).toBe('2024-06-15')
    })

    test('handles different date formats', async () => {
      const testCases = [
        { format: 'dd.MM.yyyy', expected: /\d{2}\.\d{2}\.\d{4}/ },
        { format: 'MM/dd/yyyy', expected: /\d{2}\/\d{2}\/\d{4}/ },
        { format: 'yyyy-MM-dd', expected: /\d{4}-\d{2}-\d{2}/ },
      ]

      for (const testCase of testCases) {
        const container = await createDatepicker(
          `dateformat="${testCase.format}" value="2024-06-15" multiple`,
        )
        const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
        await datepicker.updateComplete

        // Multiple mode input should be empty (for new input)
        const input = datepicker.querySelector('input') as HTMLInputElement
        expect(input.value).toBe('')

        // Selected dates should show in tags with custom format
        const tag = datepicker.querySelector('pkt-tag time')
        expect(tag).toBeInTheDocument()
        if (tag) {
          expect(tag.textContent).toMatch(testCase.expected)
        }

        // Cleanup
        container.remove()
      }
    })

    test('handles leap year dates correctly', async () => {
      const leapYearDate = '2024-02-29'
      const container = await createDatepicker(`value="${leapYearDate}"`)

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

      expect(datepicker.value).toBe(leapYearDate)
      expect(datepicker.hasError).toBe(false)
    })

    test('validates February 29 in non-leap years', async () => {
      const invalidLeapDate = '2023-02-29'
      const container = await createDatepicker(`value="${invalidLeapDate}"`)

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

      // Should handle gracefully or show error
      expect(datepicker).toBeInTheDocument()
    })

    test('handles edge case dates', async () => {
      const edgeDates = ['1900-01-01', '2000-01-01', '2100-12-31', '1999-12-31']

      for (const date of edgeDates) {
        const container = await createDatepicker(`value="${date}"`)
        const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
        await datepicker.updateComplete

        expect(datepicker.value).toBe(date)
        container.remove()
      }
    })
  })

  describe('Input field behavior', () => {
    test('allows manual date entry', async () => {
      const container = await createDatepicker('dateformat="yyyy-MM-dd"')

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

      const input = datepicker.querySelector('input') as HTMLInputElement

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

      expect(datepicker.value).toBe('2024-06-15')
    })

    test('validates manual date entry', async () => {
      const container = await createDatepicker()

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

      const input = datepicker.querySelector('input') as HTMLInputElement

      // HTML5 date inputs reject invalid formats, so we test that the component handles this gracefully
      fireEvent.change(input, { target: { value: 'invalid-date' } })
      fireEvent.blur(input)
      await datepicker.updateComplete

      // HTML5 date input will reject invalid dates, component should handle gracefully
      expect(datepicker).toBeInTheDocument()
      expect(input.value).toBe('') // Invalid dates become empty
    })

    test('shows placeholder text correctly', async () => {
      const placeholderText = 'Select a date'
      const container = await createDatepicker(`placeholder="${placeholderText}"`)

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

      const input = datepicker.querySelector('input') as HTMLInputElement
      expect(input.placeholder).toBe(placeholderText)
    })

    test('shows help text correctly', async () => {
      const helpText = 'Choose your preferred date'
      const container = await createDatepicker(`helptext="${helpText}"`)

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

      const helpTextElement = datepicker.querySelector('pkt-helptext')
      expect(helpTextElement?.textContent).toContain(helpText)
    })

    test('handles readonly state correctly', async () => {
      const container = await createDatepicker('readonly')

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

      const input = datepicker.querySelector('input') as HTMLInputElement
      expect(input.readOnly).toBe(true)

      // Calendar should still be accessible
      const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLButtonElement
      expect(calendarButton.disabled).toBe(false)
    })
  })

  describe('Keyboard navigation and interaction', () => {
    test('opens calendar with Enter key on calendar button', 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
      if (calendarButton) {
        calendarButton.focus()

        fireEvent.keyDown(calendarButton, { key: 'Enter' })
        await datepicker.updateComplete

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

    test('opens calendar with Space key on calendar button', 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
      if (calendarButton) {
        calendarButton.focus()

        fireEvent.keyDown(calendarButton, { key: ' ' })
        await datepicker.updateComplete

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

    test('closes calendar with Escape key', async () => {
      const container = await createDatepicker()

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

      // Open calendar
      const calendarButton = datepicker.querySelector('button[type="button"]')
      fireEvent.click(calendarButton!)
      await datepicker.updateComplete

      // Press Escape
      fireEvent.keyDown(datepicker, { key: 'Escape' })
      await datepicker.updateComplete

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

    test('navigates between tags with arrow keys in multiple mode', async () => {
      const multipleDates = '2024-06-15,2024-06-20,2024-06-25'
      const container = await createDatepicker(`value="${multipleDates}" multiple`)

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

      const tags = datepicker.querySelectorAll('pkt-tag')
      const firstTag = tags[0] as HTMLElement

      firstTag.focus()
      fireEvent.keyDown(firstTag, { key: 'ArrowRight' })
      await datepicker.updateComplete

      // Focus should move to next tag
      expect(document.activeElement).toBeTruthy()
    })
  })
})
