import type { IPktComboboxOption } from 'shared-types/combobox'
import type { TTagSkin } from '../tag'
import { buildFulltext } from 'shared-utils/combobox/option-utils'

/**
 * Lit-specific utility functions for PktCombobox component.
 *
 * Framework-agnostic functions live in shared-utils/combobox/.
 * Only Lit-specific functions (using Ref, in-place mutation) stay here.
 */

// Selection state helpers (mutating, Lit-specific)

/**
 * In-place option mutation helpers that preserve referential identity
 * between this._options and this.options in the Lit component.
 */
export const selectionMutators = {
  markOptionSelected(options: IPktComboboxOption[], value: string | null): void {
    if (!value) return
    for (const option of options) {
      if (option.value === value) {
        option.selected = true
        break
      }
    }
  },

  markOptionDeselected(options: IPktComboboxOption[], value: string | null): void {
    if (!value) return
    for (const option of options) {
      if (option.value === value) {
        option.selected = false
        break
      }
    }
  },

  markAllSelected(options: IPktComboboxOption[]): void {
    for (const option of options) {
      option.selected = true
    }
  },

  markAllDeselected(options: IPktComboboxOption[]): void {
    for (const option of options) {
      option.selected = false
    }
  },

  removeUserAddedOptions(options: IPktComboboxOption[]): IPktComboboxOption[] {
    return options.filter((option) => !option.userAdded)
  },
}

// Slot parsing (Lit-specific)

/**
 * Parses option elements from slot controller nodes into IPktComboboxOption[].
 */
export const slotUtils = {
  parseOptionsFromSlot(nodes: Element[]): IPktComboboxOption[] {
    const options: IPktComboboxOption[] = []

    nodes.forEach((node: Element) => {
      if (!node.textContent && !node.getAttribute('value')) return

      const option: IPktComboboxOption = {
        value: node.getAttribute('value') || node.textContent || '',
        label: node.textContent || node.getAttribute('value') || '',
      }

      if (node.getAttribute('data-prefix')) {
        option.prefix = node.getAttribute('data-prefix') || undefined
      }
      if (node.getAttribute('tagskincolor')) {
        option.tagSkinColor = node.getAttribute('tagskincolor') as TTagSkin
      }
      if (node.getAttribute('description')) {
        option.description = node.getAttribute('description') || undefined
      }

      option.fulltext = buildFulltext(option)
      options.push(option)
    })

    return options
  },
}

// Options state synchronization (Lit-specific, in-place mutation)

export const optionStateUtils = {
  /**
   * Ensures options have labels and fulltext set.
   * Also syncs selected state with current values.
   *
   * IMPORTANT: Mutates options in place to preserve referential identity
   * between this._options and this.options in the Lit component.
   */
  syncOptionsWithValues(
    options: IPktComboboxOption[],
    values: string[],
  ): { options: IPktComboboxOption[]; newValues: string[] } {
    const newValues = [...values]

    options.forEach((option) => {
      if (option.value && !option.label) {
        option.label = option.value
      }
      if (option.selected && !newValues.includes(option.value)) {
        newValues.push(option.value)
      }
      option.fulltext = buildFulltext(option)
      option.selected = option.selected || newValues.includes(option.value)
    })

    return { options, newValues }
  },

  /**
   * Merges user-added options with new options, preserving user additions.
   */
  mergeWithUserAdded(
    newOptions: IPktComboboxOption[],
    previousOptions: IPktComboboxOption[],
  ): IPktComboboxOption[] {
    const userAddedValues = previousOptions.filter((option) => option?.userAdded && option.selected)
    const filteredUserAdded = userAddedValues.filter(
      (userOpt) =>
        !(Array.isArray(newOptions) ? newOptions : []).some((opt) => opt.value === userOpt.value),
    )
    return [...filteredUserAdded, ...newOptions]
  },
}
