import { html, nothing, PropertyValues } from 'lit'
import { PktElement } from '@/base-elements/element'
import { customElement, property, state } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import { ref, createRef, Ref } from 'lit/directives/ref.js'

import { formatISODate, newDate } from 'shared-utils/date-utils'
import { PktCalendar } from '../calendar/calendar'
import { calendarUtils } from './datepicker-utils'

export class PktDatepickerPopup extends PktElement {
  @property({ type: Boolean, reflect: true }) open = false
  @property({ type: Boolean }) multiple = false
  @property({ type: Boolean }) range = false
  @property({ type: Boolean }) weeknumbers = false
  @property({ type: Boolean }) withcontrols = false
  @property({ type: Number }) maxMultiple: number | null = null
  @property({ type: Array }) selected: string[] = []
  @property({ type: String }) earliest: string | null = null
  @property({ type: String }) latest: string | null = null
  @property({ type: Array }) excludedates: string[] = []
  @property({ type: Array }) excludeweekdays: string[] = []
  @property({ type: String }) currentmonth: string | null = null
  @property({ type: String }) today: string | null = null

  @state() private _hasBeenOpened = false

  popupRef: Ref<HTMLElement> = createRef()
  calendarRef: Ref<HTMLElement> = createRef()

  firstUpdated() {
    // expose calendarRef for external use
    this.calRef = this.calendarRef
  }

  updated(changedProperties: PropertyValues) {
    super.updated(changedProperties)

    if (changedProperties.has('open')) {
      if (this.open) {
        this._hasBeenOpened = true
        document.addEventListener('keydown', this.handleDocumentKeydown)
        document.addEventListener('click', this.handleDocumentClick)
      } else {
        document.removeEventListener('click', this.handleDocumentClick)
        document.removeEventListener('keydown', this.handleDocumentKeydown)
      }
    }
  }

  disconnectedCallback() {
    super.disconnectedCallback()
    document.removeEventListener('click', this.handleDocumentClick)
    document.removeEventListener('keydown', this.handleDocumentKeydown)
  }

  handleDocumentClick = (e: MouseEvent) => {
    if (!this.open) return
    const path = e.composedPath() as EventTarget[]
    const host = this.parentElement as EventTarget | null
    const popupNode = this.popupRef.value as EventTarget | null
    if (
      !path.includes(this) &&
      !path.includes(popupNode as EventTarget) &&
      !(host && path.includes(host))
    ) {
      this.hide()
      this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
    }
  }

  handleDocumentKeydown = (e: KeyboardEvent) => {
    if (!this.open) return
    if (e.key === 'Escape') {
      this.hide()
      this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
    }
  }

  show() {
    this.open = true
    ;(this.calendarRef.value as HTMLElement | null)?.focus()
  }

  hide() {
    this.open = false
  }

  toggle() {
    this.open ? this.hide() : this.show()
  }

  contains(node: Node | null) {
    return !!node && !!(this.popupRef.value as HTMLElement | null)?.contains(node as Node)
  }

  focusOnCurrentDate() {
    const cal = this.calendarRef.value as PktCalendar
    if (cal && typeof cal.focusOnCurrentDate === 'function') cal.focusOnCurrentDate()
  }

  addToSelected(e: Event, min?: string | null, max?: string | null) {
    const cal = this.calendarRef.value as PktCalendar
    if (cal && typeof calendarUtils.addToSelected === 'function') {
      return calendarUtils.addToSelected(e, this.calendarRef as any, min, max)
    }

    // Calendar not rendered yet — handle add directly
    const target = e.target as HTMLInputElement
    if (!target.value) return

    const minAsDate = min ? newDate(min) : null
    const maxAsDate = max ? newDate(max) : null
    const date = newDate(target.value.split(',')[0])

    if (date && !isNaN(date.getTime()) && (!minAsDate || date >= minAsDate) && (!maxAsDate || date <= maxAsDate)) {
      this.handleDateSelect(date)
    }
    target.value = ''
  }

  handleDateSelect(date: Date) {
    const cal = this.calendarRef.value as PktCalendar
    if (cal && typeof cal.handleDateSelect === 'function') return cal.handleDateSelect(date)

    // Calendar not rendered yet — handle selection toggle directly
    const dateStr = formatISODate(date)
    const index = this.selected.indexOf(dateStr)
    const newSelected = index >= 0
      ? this.selected.filter((d) => d !== dateStr)
      : [...this.selected, dateStr]
    this.selected = newSelected
    this.dispatchEvent(
      new CustomEvent('date-selected', { detail: newSelected, bubbles: true, composed: true }),
    )
    return undefined
  }

  render() {
    const classes = { 'pkt-calendar-popup': true, show: this.open, hide: !this.open }
    return html`
      <div
        class="${classMap(classes)}"
        ${ref(this.popupRef)}
        id="date-popup"
        ?hidden=${!this.open}
        aria-hidden="${!this.open}"
      >
        ${this.open || this._hasBeenOpened
          ? html`<pkt-calendar
              ${ref(this.calendarRef)}
              ?multiple=${this.multiple}
              ?range=${this.range}
              ?weeknumbers=${this.weeknumbers}
              ?withcontrols=${this.withcontrols}
              .maxMultiple=${this.maxMultiple}
              .selected=${this.selected}
              .earliest=${this.earliest}
              .latest=${this.latest}
              .excludedates=${this.excludedates}
              .excludeweekdays=${this.excludeweekdays}
              .currentmonth=${this.currentmonth}
              .today=${this.today}
              @date-selected=${(e: CustomEvent) => {
                this.selected = e.detail
                this.dispatchEvent(
                  new CustomEvent('date-selected', { detail: e.detail, bubbles: true, composed: true }),
                )
              }}
              @close=${() => {
                this.hide()
                this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
              }}
            ></pkt-calendar>`
          : nothing}
      </div>
    `
  }
}

try {
  customElement('pkt-datepicker-popup')(PktDatepickerPopup)
} catch (e) {
  console.warn('Forsøker å definere <pkt-datepicker-popup>, men den er allerede definert')
}
