import '@testing-library/jest-dom'
import { render, fireEvent, act } from '@testing-library/react'
import { createRef } from 'react'
import { parseISODateString } from 'shared-utils/date-utils'

import { PktCalendar, IPktCalendar, PktCalendarHandle } from './Calendar'

const createCalendar = (props: Partial<IPktCalendar> = {}) => {
  return render(<PktCalendar {...props} />)
}

describe('PktCalendar', () => {
  describe('Date selection functionality', () => {
    test('selects single date correctly', () => {
      const { container } = createCalendar()

      // Find and click on a date
      const availableDate = container.querySelector(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      expect(availableDate).toBeInTheDocument()

      fireEvent.click(availableDate!)

      expect(availableDate).toHaveClass('pkt-calendar__date--selected')
    })

    test('handles multiple date selection', () => {
      const { container } = createCalendar({ multiple: true })

      // Find and click on multiple dates
      const availableDates = container.querySelectorAll(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      expect(availableDates.length).toBeGreaterThan(1)

      fireEvent.click(availableDates[0])
      fireEvent.click(availableDates[1])

      expect(availableDates[0]).toHaveClass('pkt-calendar__date--selected')
      expect(availableDates[1]).toHaveClass('pkt-calendar__date--selected')
    })

    test('respects maxMultiple limit', () => {
      const { container } = createCalendar({ multiple: true, maxMultiple: 2 })

      // Try to select more than maxMultiple dates
      const availableDates = container.querySelectorAll(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      expect(availableDates.length).toBeGreaterThan(2)

      // Select 3 dates but only 2 should be selected
      fireEvent.click(availableDates[0])
      fireEvent.click(availableDates[1])
      fireEvent.click(availableDates[2])

      const selectedDates = container.querySelectorAll('.pkt-calendar__date--selected')
      expect(selectedDates.length).toBeLessThanOrEqual(2)
    })

    test('handles pre-selected dates', () => {
      const preSelectedDates = ['2024-06-15', '2024-06-20']
      const { container } = createCalendar({
        selected: preSelectedDates,
        currentmonth: '2024-06-01',
      })

      const selectedDates = container.querySelectorAll('.pkt-calendar__date--selected')
      expect(selectedDates.length).toBe(2)
    })

    test('toggles date selection when clicking same date twice', () => {
      const { container } = createCalendar()

      const availableDate = container.querySelector(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      expect(availableDate).toBeInTheDocument()

      // First click - select
      fireEvent.click(availableDate!)
      expect(availableDate).toHaveClass('pkt-calendar__date--selected')

      // Second click - deselect
      fireEvent.click(availableDate!)
      expect(availableDate).not.toHaveClass('pkt-calendar__date--selected')
    })
  })

  describe('Range selection functionality', () => {
    test('handles range selection correctly', () => {
      const { container } = createCalendar({ range: true })

      const availableDates = container.querySelectorAll(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )
      expect(availableDates.length).toBeGreaterThan(3)

      // Select start date
      fireEvent.click(availableDates[5])

      // Select end date
      fireEvent.click(availableDates[10])

      // Check for range styling
      const rangeStart = container.querySelector('.pkt-calendar__date--range-start')
      const rangeEnd = container.querySelector('.pkt-calendar__date--range-end')
      const rangeInBetween = container.querySelectorAll('.pkt-calendar__date--in-range')

      expect(rangeStart).toBeInTheDocument()
      expect(rangeEnd).toBeInTheDocument()
      expect(rangeInBetween.length).toBeGreaterThan(0)
    })

    test('shows range hover preview', () => {
      const { container } = createCalendar({ range: true })

      const availableDates = container.querySelectorAll(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )

      // Select start date
      fireEvent.click(availableDates[5])

      // Hover over potential end date
      fireEvent.mouseOver(availableDates[10])

      // Should show hover preview styling
      const hoveredRanges = container.querySelectorAll('.pkt-calendar__date--in-range-hover')
      expect(hoveredRanges.length).toBeGreaterThan(0)
    })

    test('clears range when selecting new start date', () => {
      const { container } = createCalendar({ range: true })

      const availableDates = container.querySelectorAll(
        '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
      )

      // Create initial range
      fireEvent.click(availableDates[5])
      fireEvent.click(availableDates[10])

      // Select new start date
      fireEvent.click(availableDates[2])

      // Old range should be cleared
      const selectedDates = container.querySelectorAll('.pkt-calendar__date--selected')
      expect(selectedDates.length).toBe(1)
    })
  })

  describe('API methods', () => {
    test('addToSelected method works correctly', () => {
      const ref = createRef<PktCalendarHandle>()
      const { container } = render(
        <PktCalendar ref={ref} multiple currentmonth="2024-06-01" />,
      )

      const testDate = parseISODateString('2024-06-15')
      act(() => {
        ref.current!.addToSelected(testDate)
      })

      const dateButton = container.querySelector('button[data-date="2024-06-15"]')
      expect(dateButton).toHaveClass('pkt-calendar__date--selected')
    })

    test('removeFromSelected method works correctly', () => {
      const ref = createRef<PktCalendarHandle>()
      const { container } = render(
        <PktCalendar ref={ref} multiple currentmonth="2024-06-01" />,
      )

      const testDate = parseISODateString('2024-06-15')
      act(() => {
        ref.current!.addToSelected(testDate)
      })

      act(() => {
        ref.current!.removeFromSelected(testDate)
      })

      const dateButton = container.querySelector('button[data-date="2024-06-15"]')
      expect(dateButton).not.toHaveClass('pkt-calendar__date--selected')
    })

    test('toggleSelected method works correctly', () => {
      const ref = createRef<PktCalendarHandle>()
      const { container } = render(
        <PktCalendar ref={ref} currentmonth="2024-06-01" />,
      )

      const testDate = parseISODateString('2024-06-15')

      // Toggle on
      act(() => {
        ref.current!.toggleSelected(testDate)
      })

      let dateButton = container.querySelector('button[data-date="2024-06-15"]')
      expect(dateButton).toHaveClass('pkt-calendar__date--selected')

      // Toggle off
      act(() => {
        ref.current!.toggleSelected(testDate)
      })

      dateButton = container.querySelector('button[data-date="2024-06-15"]')
      expect(dateButton).not.toHaveClass('pkt-calendar__date--selected')
    })

    test('focusOnCurrentDate method works correctly', () => {
      const ref = createRef<PktCalendarHandle>()
      render(<PktCalendar ref={ref} />)

      act(() => {
        ref.current!.focusOnCurrentDate()
      })

      // Should focus on a date element
      const focusedElement = document.activeElement
      expect(focusedElement).toHaveClass('pkt-calendar__date')
    })
  })
})
