/**
 * DateRangePicker - Dual calendar range selection with presets
 * @countermeasure/web-components/form/date-picker
 */

import { type DateRangePickerConfig, type DateRangePreset } from './types'
import { Calendar } from '../calendar/index'
import { resolveContainer, uniqueId } from '../../primitives/utils'
import { announce } from '../../utils/a11y'

function formatDate(date: Date, format: string, locale?: string): string {
  // For ISO format, use standard formatting
  if (format === 'YYYY-MM-DD') {
    return date.toISOString().split('T')[0] ?? ''
  }

  // For display, use Intl.DateTimeFormat
  const loc = locale ?? (typeof navigator !== 'undefined' ? navigator.language : 'en-US')

  return new Intl.DateTimeFormat(loc, {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).format(date)
}

function defaultPresets(): DateRangePreset[] {
  return [
    {
      label: 'Last 7 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 6)
        return [start, end]
      },
    },
    {
      label: 'Last 30 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 29)
        return [start, end]
      },
    },
    {
      label: 'Last 90 days',
      getRange: () => {
        const end = new Date()
        const start = new Date()
        start.setDate(start.getDate() - 89)
        return [start, end]
      },
    },
    {
      label: 'Year to date',
      getRange: () => {
        const end = new Date()
        const start = new Date(end.getFullYear(), 0, 1)
        return [start, end]
      },
    },
  ]
}

export class DateRangePicker {
  public readonly el: HTMLElement

  private readonly inputEl: HTMLInputElement
  private readonly dropdownEl: HTMLElement
  private readonly inputId: string
  private readonly dropdownId: string
  private leftCalendar: Calendar | null = null
  private rightCalendar: Calendar | null = null
  private config: DateRangePickerConfig
  private startDate: Date | null
  private endDate: Date | null
  private pendingStart: Date | null = null
  private pendingEnd: Date | null = null
  private isOpen = false
  private isDestroyed = false

  private readonly handleDocumentClick: (e: MouseEvent) => void
  private readonly handleInputKeydown: (e: KeyboardEvent) => void

  constructor(config: DateRangePickerConfig) {
    this.config = config
    this.inputId = uniqueId('cmm-daterange')
    this.dropdownId = uniqueId('cmm-daterange-dropdown')
    this.startDate = config.startDate ?? null
    this.endDate = config.endDate ?? null

    this.el = document.createElement('div')
    this.el.className = this.buildRootClass()

    const inputWrap = document.createElement('div')
    inputWrap.className = 'cmm-date-range__input-wrap'

    this.inputEl = document.createElement('input')
    this.inputEl.id = this.inputId
    this.inputEl.type = 'text'
    this.inputEl.className = 'cmm-date-range__input'
    this.inputEl.readOnly = true
    this.inputEl.placeholder = 'Select date range'

    // Combobox ARIA pattern
    this.inputEl.setAttribute('role', 'combobox')
    this.inputEl.setAttribute('aria-haspopup', 'dialog')
    this.inputEl.setAttribute('aria-expanded', 'false')
    this.inputEl.setAttribute('aria-controls', this.dropdownId)
    this.inputEl.setAttribute('aria-label', 'Date range')
    this.updateInputDisplay()

    this.inputEl.addEventListener('click', () => {
      if (this.isDestroyed) return
      if (this.isOpen) this.close()
      else this.open()
    })

    const calIcon = document.createElement('button')
    calIcon.type = 'button'
    calIcon.className = 'cmm-date-range__toggle'
    calIcon.setAttribute('aria-label', 'Open date range picker')
    calIcon.innerHTML =
      '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="2" y="3" width="12" height="11" rx="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M2 6.5h12M5.5 2v2M10.5 2v2" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>'
    calIcon.addEventListener('click', e => {
      e.stopPropagation()
      if (this.isDestroyed) return
      if (this.isOpen) this.close()
      else this.open()
    })

    inputWrap.appendChild(this.inputEl)
    inputWrap.appendChild(calIcon)
    this.el.appendChild(inputWrap)

    this.dropdownEl = document.createElement('div')
    this.dropdownEl.id = this.dropdownId
    this.dropdownEl.className = 'cmm-date-range__dropdown'
    this.dropdownEl.setAttribute('role', 'dialog')
    this.dropdownEl.setAttribute('aria-modal', 'false')
    this.dropdownEl.setAttribute('aria-label', 'Choose date range')
    this.dropdownEl.style.display = 'none'
    this.el.appendChild(this.dropdownEl)

    this.handleDocumentClick = (e: MouseEvent) => {
      if (this.isDestroyed) return
      const target = e.target as Node
      if (!this.el.contains(target)) {
        this.close()
      }
    }

    this.handleInputKeydown = (e: KeyboardEvent) => {
      if (this.isDestroyed) return
      if (e.key === 'Escape' && this.isOpen) {
        e.preventDefault()
        this.close()
      }
    }

    this.inputEl.addEventListener('keydown', this.handleInputKeydown)

    const parent = resolveContainer(config.container)
    parent.appendChild(this.el)
  }

  getRange(): { start: Date | null; end: Date | null } {
    return { start: this.startDate, end: this.endDate }
  }

  setRange(start: Date | null, end: Date | null): void {
    this.startDate = start
    this.endDate = end
    this.updateInputDisplay()
    this.syncCalendars()
  }

  open(): void {
    if (this.isOpen || this.isDestroyed) return
    this.isOpen = true
    this.pendingStart = this.startDate
    this.pendingEnd = this.endDate
    this.dropdownEl.style.display = ''
    this.inputEl.setAttribute('aria-expanded', 'true')
    this.buildDropdownContent()
    this.positionDropdown()
    document.addEventListener('click', this.handleDocumentClick)
  }

  close(): void {
    if (!this.isOpen) return
    this.isOpen = false
    this.dropdownEl.style.display = 'none'
    this.inputEl.setAttribute('aria-expanded', 'false')
    document.removeEventListener('click', this.handleDocumentClick)
  }

  destroy(): void {
    this.isDestroyed = true
    this.close()
    this.inputEl.removeEventListener('keydown', this.handleInputKeydown)
    document.removeEventListener('click', this.handleDocumentClick)
    this.leftCalendar?.destroy()
    this.rightCalendar?.destroy()
    this.el.remove()
  }

  private buildRootClass(): string {
    const classes = ['cmm-date-range']
    if (this.config.className) classes.push(this.config.className)
    return classes.join(' ')
  }

  private buildDropdownContent(): void {
    this.dropdownEl.innerHTML = ''
    this.leftCalendar?.destroy()
    this.rightCalendar?.destroy()
    this.leftCalendar = null
    this.rightCalendar = null

    const body = document.createElement('div')
    body.className = 'cmm-date-range__body'

    // Presets sidebar
    const presets = this.config.presets ?? defaultPresets()
    const sidebar = document.createElement('div')
    sidebar.className = 'cmm-date-range__presets'

    for (const preset of presets) {
      const btn = document.createElement('button')
      btn.type = 'button'
      btn.className = 'cmm-date-range__preset-btn'
      btn.textContent = preset.label
      btn.addEventListener('click', () => {
        if (this.isDestroyed) return
        const [start, end] = preset.getRange()
        this.pendingStart = start
        this.pendingEnd = end
        this.syncCalendars()
      })
      sidebar.appendChild(btn)
    }

    body.appendChild(sidebar)

    // Calendar container
    const calendarsWrap = document.createElement('div')
    calendarsWrap.className = 'cmm-date-range__calendars'

    const leftContainer = document.createElement('div')
    leftContainer.className = 'cmm-date-range__calendar-left'
    calendarsWrap.appendChild(leftContainer)

    const rightContainer = document.createElement('div')
    rightContainer.className = 'cmm-date-range__calendar-right'
    calendarsWrap.appendChild(rightContainer)

    body.appendChild(calendarsWrap)
    this.dropdownEl.appendChild(body)

    // Create calendars
    const now = this.pendingStart ?? new Date()
    const leftYear = now.getFullYear()
    const leftMonth = now.getMonth()
    let rightYear = leftYear
    let rightMonth = leftMonth + 1
    if (rightMonth > 11) {
      rightMonth = 0
      rightYear += 1
    }

    this.leftCalendar = new Calendar({
      container: leftContainer,
      mode: 'range',
      rangeStart: this.pendingStart,
      rangeEnd: this.pendingEnd,
      minDate: this.config.minDate,
      maxDate: this.config.maxDate,
      onRangeChange: (start, end) => {
        this.pendingStart = start
        this.pendingEnd = end
        this.rightCalendar?.setRange(start, end)
      },
    })
    this.leftCalendar.goToMonth(leftYear, leftMonth)

    this.rightCalendar = new Calendar({
      container: rightContainer,
      mode: 'range',
      rangeStart: this.pendingStart,
      rangeEnd: this.pendingEnd,
      minDate: this.config.minDate,
      maxDate: this.config.maxDate,
      onRangeChange: (start, end) => {
        this.pendingStart = start
        this.pendingEnd = end
        this.leftCalendar?.setRange(start, end)
      },
    })
    this.rightCalendar.goToMonth(rightYear, rightMonth)

    // Footer with buttons
    const footer = document.createElement('div')
    footer.className = 'cmm-date-range__footer'

    const cancelBtn = document.createElement('button')
    cancelBtn.type = 'button'
    cancelBtn.className = 'cmm-date-range__cancel-btn'
    cancelBtn.textContent = 'Cancel'
    cancelBtn.addEventListener('click', () => {
      if (this.isDestroyed) return
      this.close()
    })

    const applyBtn = document.createElement('button')
    applyBtn.type = 'button'
    applyBtn.className = 'cmm-date-range__apply-btn'
    applyBtn.textContent = 'Apply'
    applyBtn.addEventListener('click', () => {
      if (this.isDestroyed) return
      this.startDate = this.pendingStart
      this.endDate = this.pendingEnd
      this.updateInputDisplay()
      this.config.onChange?.(this.startDate, this.endDate)

      // Announce the selection to screen readers
      if (this.startDate !== null && this.endDate !== null) {
        const startStr = this.startDate.toLocaleDateString('en-US', {
          month: 'short',
          day: 'numeric',
          year: 'numeric',
        })
        const endStr = this.endDate.toLocaleDateString('en-US', {
          month: 'short',
          day: 'numeric',
          year: 'numeric',
        })
        announce(`Selected range from ${startStr} to ${endStr}`, 'polite')
      }

      this.close()
    })

    footer.appendChild(cancelBtn)
    footer.appendChild(applyBtn)
    this.dropdownEl.appendChild(footer)
  }

  private syncCalendars(): void {
    this.leftCalendar?.setRange(this.pendingStart, this.pendingEnd)
    this.rightCalendar?.setRange(this.pendingStart, this.pendingEnd)
  }

  private updateInputDisplay(): void {
    const fmt = this.config.format ?? 'YYYY-MM-DD'
    const loc = this.config.locale
    if (this.startDate !== null && this.endDate !== null) {
      this.inputEl.value = `${formatDate(this.startDate, fmt, loc)} \u2014 ${formatDate(this.endDate, fmt, loc)}`
    } else if (this.startDate !== null) {
      this.inputEl.value = `${formatDate(this.startDate, fmt, loc)} \u2014 ...`
    } else {
      this.inputEl.value = ''
    }
  }

  private positionDropdown(): void {
    const rect = this.el.getBoundingClientRect()
    const spaceBelow = window.innerHeight - rect.bottom
    if (spaceBelow < 400 && rect.top > spaceBelow) {
      this.dropdownEl.classList.add('cmm-date-range__dropdown--above')
      this.dropdownEl.classList.remove('cmm-date-range__dropdown--below')
    } else {
      this.dropdownEl.classList.add('cmm-date-range__dropdown--below')
      this.dropdownEl.classList.remove('cmm-date-range__dropdown--above')
    }
  }
}
