import { ref } from 'vue'

let currentDropdownEl: HTMLElement | null = null
let currentOnDocClick: ((e: MouseEvent) => void) | null = null
const isDisabled = ref<any>(false)
const closeDropdown = () => {
  if (currentDropdownEl && currentDropdownEl.parentNode) currentDropdownEl.parentNode.removeChild(currentDropdownEl)
  currentDropdownEl = null
  if (currentOnDocClick) document.removeEventListener('click', currentOnDocClick, true)
  currentOnDocClick = null
}

const openDropdown = (
  td: HTMLTableCellElement,
  value: unknown,
  source: string[],
  onSelect: (opt: string) => void,
  isOptionDisabled?: (opt: string) => boolean,
) => {
  closeDropdown()
  const menu = document.createElement('div')
  menu.className = 'ht-dropdown-menu'
  const frag = document.createDocumentFragment()
  for (const opt of source) {
    const item = document.createElement('div')
    item.className = 'ht-dropdown-item'
    item.textContent = opt
    if (String(value) === String(opt)) item.classList.add('is-selected')
    const disabled = isDisabled.value && isOptionDisabled?.(opt) === true
    if (disabled) { item.classList.add('is-disabled'); item.setAttribute('aria-disabled', 'true') }
    item.onclick = (e) => { e.stopPropagation(); if (disabled) return; onSelect(opt); closeDropdown() }
    frag.appendChild(item)
  }
  menu.appendChild(frag)
  const rect = td.getBoundingClientRect()
  menu.style.visibility = 'hidden'
  document.body.appendChild(menu)
  const menuWidth = menu.offsetWidth
  const menuHeight = menu.offsetHeight
  const viewportRight = window.scrollX + window.innerWidth
  const viewportBottom = window.scrollY + window.innerHeight
  const left = Math.min(rect.left + window.scrollX, viewportRight - menuWidth - 8)
  let top = rect.bottom + window.scrollY
  let placement = 'bottom'
  if (top + menuHeight > viewportBottom - 8) { top = rect.top + window.scrollY - menuHeight; placement = 'top' }
  menu.style.left = `${Math.max(left, 8)}px`
  menu.style.top = `${top}px`
  menu.classList.add(placement === 'top' ? 'is-top' : 'is-bottom')
  menu.style.visibility = ''
  currentDropdownEl = menu
  currentOnDocClick = (ev: MouseEvent) => { const target = ev.target as Node; if (currentDropdownEl && !currentDropdownEl.contains(target)) closeDropdown() }
  document.addEventListener('click', currentOnDocClick, true)
}
export function handlerDropdownRenderer(instance: any, td: HTMLTableCellElement, row: number, column: number, prop: string | number, value: any, cellProperties: any) {
  td.innerHTML = ''
  const wrapper = document.createElement('div')
  wrapper.className = 'ht-cell-dropdown'
  const valueEl = document.createElement('span')
  valueEl.className = 'ht-cell-value'
  valueEl.textContent = value ?? ''
  const caretEl = document.createElement('span')
  caretEl.className = 'ht-cell-caret'
  wrapper.appendChild(valueEl)
  wrapper.appendChild(caretEl)
  td.appendChild(wrapper)
  const source: string[] = Array.isArray(cellProperties?.source)
    ? cellProperties.source
    : Array.isArray(cellProperties?.customDropdownSource)
    ? cellProperties.customDropdownSource
    : []
  let disabledSet = new Set<string>()
  if (isDisabled.value) {
    const colValues = instance.getSourceDataAtCol(column) as unknown[]
    const currentStr = String(value ?? '')
    disabledSet = new Set((Array.isArray(colValues) ? colValues : []).map(v => String(v)))
    disabledSet.delete(currentStr)
  } 
  wrapper.onclick = (e) => { e.stopPropagation(); openDropdown(td, value, source, (opt) => instance.setDataAtCell(row, column, opt), (opt) => isDisabled.value && disabledSet.has(String(opt))) }
  return td
}