import '@testing-library/jest-dom'

import { fireEvent, render } from '@testing-library/react'
import { vi } from 'vitest'

import { IPktDatepicker, PktDatepicker } from './Datepicker'

const datePickerId = 'datepickerId'
const label = 'Date Picker Label'

const createDatepickerTest = (props: Partial<IPktDatepicker> = {}) => {
  const defaultProps: IPktDatepicker = {
    label,
    id: datePickerId,
    ...props,
  }

  return render(<PktDatepicker {...defaultProps} />)
}

describe('PktDatepicker', () => {
  describe('Date boundary testing', () => {
    test('handles minimum possible dates', () => {
      const { container } = createDatepickerTest({
        value: '1900-01-01',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('1900-01-01')
    })

    test('handles maximum possible dates', () => {
      const { container } = createDatepickerTest({
        value: '2100-12-31',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2100-12-31')
    })

    test('handles year boundaries correctly', () => {
      const { container } = createDatepickerTest({
        value: '2024-12-31',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-12-31')
    })

    test('handles month boundaries correctly', () => {
      const { container } = createDatepickerTest({
        value: '2024-01-31',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-01-31')
    })

    test('handles leap year dates correctly', () => {
      const { container } = createDatepickerTest({
        value: '2024-02-29',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-02-29')
    })

    test.each([
      { desc: 'date before min', min: '2024-06-01', max: '2024-06-30', value: '2024-05-15' },
      { desc: 'date after max', min: '2024-06-01', max: '2024-06-30', value: '2024-07-15' },
      { desc: 'valid date within range', min: '2024-06-01', max: '2024-06-30', value: '2024-06-15' },
    ])('renders with $desc ($value) without crashing', ({ min, max, value }) => {
      const { container } = createDatepickerTest({
        min,
        max,
        value,
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe(value)
      expect(input).toHaveAttribute('min', min)
      expect(input).toHaveAttribute('max', max)
    })
  })

  describe('Error handling and edge cases', () => {
    test('handles empty values correctly', () => {
      const { container } = createDatepickerTest({
        value: '',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('')
    })

    test('handles undefined value correctly', () => {
      const { container } = createDatepickerTest({
        value: undefined,
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('')
    })

    test('handles empty array value for multiple', () => {
      const { container } = createDatepickerTest({
        multiple: true,
        value: [],
      })

      const tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
      expect(tags.length).toBe(0)
    })

    test('handles single-value array for range mode', () => {
      const { container } = createDatepickerTest({
        range: true,
        value: ['2024-06-15'],
      })

      const inputs = container.querySelectorAll('input[type="date"]') as NodeListOf<HTMLInputElement>
      expect(inputs[0].value).toBe('2024-06-15')
      expect(inputs[1].value).toBe('')
    })

    test('handles many dates with maxlength', () => {
      // Generate 20 unique dates
      const dates = Array.from({ length: 20 }, (_, i) => {
        const day = String(i + 1).padStart(2, '0')
        return `2024-06-${day}`
      })

      const { container } = createDatepickerTest({
        multiple: true,
        maxlength: 10,
        value: dates,
      })

      // Should render all dates as tags (maxlength only restricts new additions)
      const tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
      expect(tags.length).toBe(dates.length)

      // Input should be disabled since we're over maxlength
      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input).toBeDisabled()
    })

    test('handles conflicting properties gracefully (both multiple and range)', () => {
      // When both multiple and range are set, multiple takes precedence
      const { container } = createDatepickerTest({
        multiple: true,
        range: true,
        value: ['2024-06-15', '2024-06-20'],
      })

      // Multiple mode should render tags
      const tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
      expect(tags.length).toBe(2)

      // Should have only one input (multiple mode), not two (range mode)
      const inputs = container.querySelectorAll('input[type="date"]')
      expect(inputs.length).toBe(1)
    })

    test('handles string value passed as array', () => {
      const { container } = createDatepickerTest({
        value: '2024-06-15',
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-06-15')
    })

    test('handles array value passed for single mode', () => {
      const { container } = createDatepickerTest({
        value: ['2024-06-15'],
      })

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-06-15')
    })
  })

  describe('Controlled vs uncontrolled', () => {
    test('works as controlled component', () => {
      const { container, rerender } = render(
        <PktDatepicker id={datePickerId} label={label} value="2024-06-15" />,
      )

      let input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-06-15')

      rerender(<PktDatepicker id={datePickerId} label={label} value="2024-07-20" />)

      input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('2024-07-20')
    })

    test('works as uncontrolled component', () => {
      const { container } = createDatepickerTest()

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      expect(input.value).toBe('')
    })

    test('controlled range updates both inputs on rerender', () => {
      const { container, rerender } = render(
        <PktDatepicker id={datePickerId} label={label} range value={['2024-06-15', '2024-06-25']} />,
      )

      const inputs = container.querySelectorAll('input[type="date"]') as NodeListOf<HTMLInputElement>
      expect(inputs[0].value).toBe('2024-06-15')
      expect(inputs[1].value).toBe('2024-06-25')

      rerender(
        <PktDatepicker id={datePickerId} label={label} range value={['2024-07-01', '2024-07-31']} />,
      )

      const updatedInputs = container.querySelectorAll('input[type="date"]') as NodeListOf<HTMLInputElement>
      expect(updatedInputs[0].value).toBe('2024-07-01')
      expect(updatedInputs[1].value).toBe('2024-07-31')
    })

    test('controlled multiple updates tags on rerender', () => {
      const { container, rerender } = render(
        <PktDatepicker id={datePickerId} label={label} multiple value={['2024-06-15']} />,
      )

      let tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
      expect(tags.length).toBe(1)

      rerender(
        <PktDatepicker
          id={datePickerId}
          label={label}
          multiple
          value={['2024-06-15', '2024-06-20', '2024-06-25']}
        />,
      )

      tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
      expect(tags.length).toBe(3)
    })

    test('calendarOpen prop controls calendar state', () => {
      const { container, rerender } = render(
        <PktDatepicker id={datePickerId} label={label} calendarOpen={false} />,
      )

      let popup = container.querySelector('.pkt-calendar-popup')
      expect(popup).toHaveAttribute('hidden')

      rerender(<PktDatepicker id={datePickerId} label={label} calendarOpen={true} />)

      popup = container.querySelector('.pkt-calendar-popup')
      expect(popup).not.toHaveAttribute('hidden')
    })
  })

  describe('Form integration', () => {
    test('form input has name and value when name is set', () => {
      const { container } = createDatepickerTest({
        name: 'dateField',
        value: '2024-06-15',
      })

      const formInput = container.querySelector('input[aria-hidden="true"]') as HTMLInputElement
      expect(formInput).toBeInTheDocument()
      expect(formInput).toHaveAttribute('name', 'dateField')
      expect(formInput.value).toBe('2024-06-15')
    })

    test('form input has no name attribute when name is not set', () => {
      const { container } = createDatepickerTest({
        value: '2024-06-15',
      })

      const formInput = container.querySelector('input[aria-hidden="true"]') as HTMLInputElement
      expect(formInput).not.toHaveAttribute('name')
    })

    test('form input has comma-separated value for multiple', () => {
      const { container } = createDatepickerTest({
        name: 'dates',
        multiple: true,
        value: ['2024-06-15', '2024-06-20'],
      })

      const formInput = container.querySelector('input[aria-hidden="true"]') as HTMLInputElement
      expect(formInput.value).toBe('2024-06-15,2024-06-20')
    })

    test('form input has comma-separated value for range', () => {
      const { container } = createDatepickerTest({
        name: 'dateRange',
        range: true,
        value: ['2024-06-15', '2024-06-25'],
      })

      const formInput = container.querySelector('input[aria-hidden="true"]') as HTMLInputElement
      expect(formInput.value).toBe('2024-06-15,2024-06-25')
    })

    test('submits form on Enter key press', () => {
      const submitHandler = vi.fn((e: Event) => e.preventDefault())
      const { container } = render(
        <form onSubmit={submitHandler as unknown as React.FormEventHandler}>
          <PktDatepicker id={datePickerId} label={label} value="2024-06-15" />
        </form>,
      )

      const input = container.querySelector('input[type="date"]') as HTMLInputElement
      fireEvent.keyDown(input, { key: 'Enter' })

      expect(submitHandler).toHaveBeenCalled()
    })
  })
})
