import '@testing-library/jest-dom'
import { toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
import { parseISODateString } from 'shared-utils/date-utils'

expect.extend(toHaveNoViolations)

import './datepicker'
import '../calendar/calendar'
import { PktDatepicker } from './datepicker'
import { PktCalendar } from '../calendar/calendar'
import { PktDatepickerPopup } from './datepicker-popup'

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('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const container = await createDatepicker()

      const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
      expect(datepicker).toBeInTheDocument()

      await datepicker.updateComplete
      expect(datepicker).toBeTruthy()
    })

    test('renders with correct structure', async () => {
      const container = await createDatepicker('label="Test Datepicker"')

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

      const inputWrapper = datepicker.querySelector('pkt-input-wrapper')
      const input = datepicker.querySelector('input')
      const calendarButton = datepicker.querySelector('button[type="button"]')

      expect(inputWrapper).toBeInTheDocument()
      expect(input).toBeInTheDocument()
      expect(calendarButton).toBeInTheDocument()
    })

    test('renders calendar when opened', 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"]')
      fireEvent.click(calendarButton!)
      await datepicker.updateComplete

      const calendar = datepicker.querySelector('pkt-calendar')
      expect(calendar).toBeInTheDocument()
    })

    test('closes calendar when clicking outside', async () => {
      const container = await createDatepicker('label="Test Datepicker"')

      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

      // Click outside
      fireEvent.click(document.body)
      await datepicker.updateComplete

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

    test('closes calendar when clicking outside', async () => {
      const container = await createDatepicker('label="Test Datepicker"')

      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

      // Click outside
      fireEvent.click(document.body)
      await datepicker.updateComplete

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

  describe('Properties and attributes', () => {
    test('applies default properties correctly', async () => {
      const container = await createDatepicker('name="test" id="test"')

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

      expect(datepicker.value).toBe('')
      expect(datepicker.label).toBe('Datovelger')
      expect(datepicker.multiple).toBe(false)
      expect(datepicker.range).toBe(false)
      expect(datepicker.maxlength).toBe(null)
      expect(datepicker.showRangeLabels).toBe(false)
    })

    test('handles value property correctly', async () => {
      const testDate = '2024-06-15'
      const container = await createDatepicker(`value="${testDate}"`)

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

      expect(datepicker.value).toBe(testDate)

      const input = datepicker.querySelector('input') as HTMLInputElement
      expect(input.value).toBeTruthy()
    })

    test('handles multiple values correctly', async () => {
      const testDates = '2024-06-15,2024-06-20,2024-06-25'
      const container = await createDatepicker(`value="${testDates}" multiple`)

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

      expect(datepicker.value).toBe(testDates)
      expect(datepicker.multiple).toBe(true)

      // Should show tags for multiple values
      const tags = datepicker.querySelectorAll('pkt-tag')
      expect(tags.length).toBe(3)
    })

    test('handles range values correctly', async () => {
      const rangeValue = '2024-06-15,2024-06-20'
      const container = await createDatepicker(`value="${rangeValue}" range`)

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

      expect(datepicker.value).toBe(rangeValue)
      expect(datepicker.range).toBe(true)
    })

    test('handles label property correctly', async () => {
      const testLabel = 'Select your date'
      const container = await createDatepicker(`label="${testLabel}"`)

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

      expect(datepicker.label).toBe(testLabel)

      const label = datepicker.querySelector('label')
      expect(label?.textContent).toContain(testLabel)
    })

    test('handles dateformat property correctly', async () => {
      const customFormat = 'MM/dd/yyyy'
      const container = await createDatepicker(
        `dateformat="${customFormat}" value="2024-06-15" multiple`,
      )

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

      expect(datepicker.dateformat).toBe(customFormat)

      // 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(/\d{2}\/\d{2}\/\d{4}/)
      }
    })

    test('handles maxlength property correctly', async () => {
      const container = await createDatepicker('multiple maxlength="3"')

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

      expect(datepicker.maxlength).toBe(3)
    })

    test('handles disabled property correctly', async () => {
      const container = await createDatepicker('disabled')

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

      expect(datepicker.disabled).toBe(true)

      const input = datepicker.querySelector('input') as HTMLInputElement
      const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLButtonElement

      expect(input.disabled).toBe(true)
      expect(calendarButton.disabled).toBe(true)
    })

    test('handles currentmonth property correctly', async () => {
      const testMonth = '2024-03-01'
      const container = await createDatepicker(`currentmonth="${testMonth}"`)

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

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

      const calendar = datepicker.querySelector('pkt-calendar') as PktCalendar
      expect(calendar.currentmonth).toEqual(parseISODateString(testMonth))
    })
  })

  describe('Calendar integration', () => {
    test('passes properties to calendar correctly', async () => {
      const container = await createDatepicker(
        'min="2024-06-01" max="2024-06-30" excludeweekdays="0,6"',
      )

      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

      const calendar = datepicker.querySelector('pkt-calendar') as PktCalendar
      expect(calendar.earliest).toBe('2024-06-01')
      expect(calendar.latest).toBe('2024-06-30')
      expect(calendar.excludeweekdays).toEqual(['0', '6'])
    })

    test('syncs selected dates between input and calendar', async () => {
      const testDate = '2024-06-15'
      const container = await createDatepicker(`value="${testDate}" calendar-open`)

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

      const popup = datepicker.querySelector('pkt-datepicker-popup') as PktDatepickerPopup
      await popup?.updateComplete

      const calendar = datepicker.querySelector('pkt-calendar') as PktCalendar
      await calendar?.updateComplete

      expect(calendar.selected).toContain(testDate)

      const selectedDate = datepicker.querySelector('.pkt-calendar__date--selected')
      expect(selectedDate).toBeInTheDocument()
    })

    test('updates input when date selected in calendar', 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

      // Select a date
      const availableDate = datepicker.querySelector(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      fireEvent.click(availableDate!)
      await datepicker.updateComplete

      // Input should be updated
      const input = datepicker.querySelector('input') as HTMLInputElement
      expect(input.value).toBeTruthy()
      expect(datepicker.value).toBeTruthy()
    })

    test('shows current month correctly in calendar', async () => {
      const currentMonth = '2024-06-01'
      const container = await createDatepicker(`currentmonth="${currentMonth}" calendar-open`)

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

      const popup = datepicker.querySelector('pkt-datepicker-popup') as PktDatepickerPopup
      await popup?.updateComplete

      const calendar = datepicker.querySelector('pkt-calendar') as PktCalendar
      await calendar?.updateComplete

      const monthTitle = datepicker.querySelector('.pkt-calendar__month-title')
      expect(monthTitle?.textContent).toContain('2024')
    })
  })
})
