import { fromISOToDate, newDate } from 'shared-utils/date-utils'
import { Ref } from 'lit/directives/ref.js'
import { PktCalendar } from '@/components/calendar/calendar'
import {
  validateRangeOrder,
  sortDates,
  filterDates,
  getDatepickerInputType,
  getDatepickerInputClasses,
  getDatepickerButtonClasses,
  getRangeLabelClasses,
  processDateSelection as sharedProcessDateSelection,
  handleCalendarPosition as sharedHandleCalendarPosition,
  handleDatepickerKeydown,
  handleDatepickerButtonKeydown,
} from 'shared-utils/datepicker-utils'

/**
 * Utility functions for PktDatepicker component
 *
 * This module provides helper functions organized by concern.
 * Framework-agnostic functions are delegated to shared-utils/datepicker-utils.
 * Lit-specific functions (using Ref, ElementInternals, PktCalendar) stay here.
 */

/**
 * Value parsing and validation utilities
 * Delegates to shared-utils/datepicker-utils
 */
export const valueUtils = {
  validateRangeOrder,
  sortDates,
  filterSelectableDates: filterDates,
}

/**
 * Input type detection utilities
 * Delegates to shared-utils/datepicker-utils
 */
export const inputTypeUtils = {
  getInputType: getDatepickerInputType,
}

/**
 * Form and validation utilities (Lit-specific — uses ElementInternals)
 */
export const formUtils = {
  submitForm(element: HTMLElement): void {
    const form = (element as any).internals?.form as HTMLFormElement
    if (form) {
      form.requestSubmit()
    }
  },

  submitFormOrFallback(internals: any, fallbackAction: () => void): void {
    const form = internals?.form as HTMLFormElement
    if (form) {
      form.requestSubmit()
    } else {
      fallbackAction()
    }
  },

  validateDateInput(
    input: HTMLInputElement,
    internals: any,
    min?: string | null,
    max?: string | null,
    strings?: any,
  ): void {
    const value = input.value
    if (!value) return

    if (min && min > value) {
      internals.setValidity(
        { rangeUnderflow: true },
        strings?.forms?.messages?.rangeUnderflow || 'Value is below minimum',
        input,
      )
    } else if (max && max < value) {
      internals.setValidity(
        { rangeOverflow: true },
        strings?.forms?.messages?.rangeOverflow || 'Value is above maximum',
        input,
      )
    }
  },
}

/**
 * Calendar interaction utilities
 * handleCalendarPosition delegates to shared-utils (with Lit ref unwrapping).
 * addToSelected stays Lit-specific (uses Ref<PktCalendar>).
 */
export const calendarUtils = {
  addToSelected(
    event: Event | KeyboardEvent,
    calendarRef: Ref<PktCalendar>,
    min?: string | null,
    max?: string | null,
  ): void {
    const target = event.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) &&
      calendarRef.value
    ) {
      calendarRef.value.handleDateSelect(date)
    }
    target.value = ''
  },

  handleCalendarPosition(
    popupRef: Ref<HTMLDivElement>,
    inputRef: Ref<HTMLInputElement>,
    hasCounter: boolean = false,
  ): void {
    sharedHandleCalendarPosition(popupRef.value ?? null, inputRef.value ?? null, hasCounter)
  },
}

/**
 * Event handling utilities (Lit-specific — uses Lit Ref types)
 */
export const eventUtils = {
  createDocumentClickListener(
    inputRef: Ref<HTMLInputElement>,
    inputRefTo: Ref<HTMLInputElement> | null,
    btnRef: Ref<HTMLButtonElement>,
    getCalendarOpen: () => boolean,
    onBlur: () => void,
    hideCalendar: () => void,
  ): (e: MouseEvent) => void {
    return (e: MouseEvent) => {
      if (
        inputRef?.value &&
        btnRef?.value &&
        !inputRef.value.contains(e.target as Node) &&
        !(inputRefTo?.value && inputRefTo.value.contains(e.target as Node)) &&
        !btnRef.value.contains(e.target as Node) &&
        !(e.target as Element).closest('.pkt-calendar-popup') &&
        getCalendarOpen()
      ) {
        onBlur()
        hideCalendar()
      }
    }
  },

  createDocumentKeydownListener(
    getCalendarOpen: () => boolean,
    hideCalendar: () => void,
  ): (e: KeyboardEvent) => void {
    return (e: KeyboardEvent) => {
      if (e.key === 'Escape' && getCalendarOpen()) {
        hideCalendar()
      }
    }
  },

  handleFocusOut(
    event: FocusEvent,
    element: HTMLElement,
    onBlur: () => void,
    hideCalendar: () => void,
  ): void {
    if (!element.contains(event.target as Node)) {
      onBlur()
      hideCalendar()
    }
  },
}

/**
 * CSS class utilities
 * Delegates to shared-utils/datepicker-utils
 */
export const cssUtils = {
  getInputClasses: getDatepickerInputClasses,
  getButtonClasses: getDatepickerButtonClasses,
  getRangeLabelClasses,
}

/**
 * Date value processing utilities
 * processDateSelection delegates to shared-utils.
 * updateInputValues and processRangeBlur stay Lit-specific (use Lit Ref).
 */
export const dateProcessingUtils = {
  processDateSelection: sharedProcessDateSelection,

  updateInputValues(
    inputRef: Ref<HTMLInputElement>,
    inputRefTo: Ref<HTMLInputElement> | null,
    values: string[],
    range: boolean,
    multiple: boolean,
    manageValidity: (input: HTMLInputElement) => void,
  ): void {
    if (!inputRef.value) return

    if (range && inputRefTo?.value) {
      inputRef.value.value = values[0] ?? ''
      inputRefTo.value.value = values[1] ?? ''
      manageValidity(inputRef.value)
      manageValidity(inputRefTo.value)
    } else if (!multiple) {
      inputRef.value.value = values.length ? values[0] : ''
      manageValidity(inputRef.value)
    }
  },

  processRangeBlur(
    event: Event,
    values: string[],
    calendarRef: Ref<PktCalendar>,
    clearInputValue: () => void,
    manageValidity: (input: HTMLInputElement) => void,
  ): void {
    const target = event.target as HTMLInputElement
    if (target.value) {
      manageValidity(target)
      const date = fromISOToDate(target.value)
      if (date) {
        calendarRef?.value?.handleDateSelect(date)
      }
    } else if (values[0]) {
      clearInputValue()
    }
  },
}

/**
 * Keyboard navigation utilities
 * Delegates to shared-utils/datepicker-utils
 */
export const keyboardUtils = {
  handleInputKeydown: handleDatepickerKeydown,
  handleButtonKeydown: handleDatepickerButtonKeydown,
}
