import { useEffect, useMemo, useRef, useState } from 'react'
import { ChevronDown, Search, X } from 'lucide-react'
import { useLocale } from '@meshkee/dashboard-ui'
import { useT } from '../i18n/useT'
import type { UserProductCategoryOption } from '../services/userProductsService'
import styles from './CategorySearchSelect.module.css'

export interface FlatCategoryOption extends UserProductCategoryOption {
  depth: number
}

interface CategorySearchSelectProps {
  options: UserProductCategoryOption[]
  value: string
  onChange: (value: string) => void
  disabled?: boolean
  placeholder?: string
  id?: string
}

function categoryLabel(category: UserProductCategoryOption, isFa: boolean) {
  if (isFa) {
    return category.nameFa?.trim() || category.name
  }
  return category.name || category.nameFa?.trim() || ''
}

export function flattenCategoryTree(
  categories: UserProductCategoryOption[],
): FlatCategoryOption[] {
  const byParent = new Map<string | null, UserProductCategoryOption[]>()

  for (const category of categories) {
    const parentKey = category.parentId
    const list = byParent.get(parentKey) ?? []
    list.push(category)
    byParent.set(parentKey, list)
  }

  for (const list of byParent.values()) {
    list.sort((a, b) => {
      const aLabel = (a.nameFa || a.name).localeCompare(b.nameFa || b.name, 'fa')
      return aLabel
    })
  }

  const result: FlatCategoryOption[] = []
  const ids = new Set(categories.map((item) => item.id))

  function walk(parentId: string | null, depth: number) {
    const children = byParent.get(parentId) ?? []
    for (const child of children) {
      result.push({ ...child, depth })
      walk(child.id, depth + 1)
    }
  }

  walk(null, 0)

  // Orphans whose parent is missing from the list
  for (const category of categories) {
    if (category.parentId && !ids.has(category.parentId)) {
      if (!result.some((item) => item.id === category.id)) {
        result.push({ ...category, depth: 0 })
        walk(category.id, 1)
      }
    }
  }

  return result
}

function filterCategoryTree(
  flat: FlatCategoryOption[],
  query: string,
): FlatCategoryOption[] {
  const q = query.trim().toLowerCase()
  if (!q) return flat

  const byId = new Map(flat.map((item) => [item.id, item]))
  const matchedIds = new Set<string>()

  for (const item of flat) {
    const nameEn = item.name.toLowerCase()
    const nameFa = (item.nameFa || '').toLowerCase()
    if (nameEn.includes(q) || nameFa.includes(q) || (item.nameFa || '').includes(query.trim())) {
      matchedIds.add(item.id)
      let parentId = item.parentId
      while (parentId) {
        matchedIds.add(parentId)
        parentId = byId.get(parentId)?.parentId ?? null
      }
    }
  }

  return flat.filter((item) => matchedIds.has(item.id))
}

export function CategorySearchSelect({
  options,
  value,
  onChange,
  disabled = false,
  placeholder,
  id,
}: CategorySearchSelectProps) {
  const t = useT()
  const { locale } = useLocale()
  const isFa = locale === 'fa'
  const [open, setOpen] = useState(false)
  const [query, setQuery] = useState('')
  const containerRef = useRef<HTMLDivElement>(null)

  const flat = useMemo(() => flattenCategoryTree(options), [options])
  const filtered = useMemo(() => filterCategoryTree(flat, query), [flat, query])

  const selected = flat.find((option) => option.id === value)
  const selectedLabel = selected ? categoryLabel(selected, isFa) : ''
  const searchPlaceholder = placeholder ?? t('myProducts.fields.searchCategory')

  useEffect(() => {
    if (!open) return

    function onClickOutside(e: MouseEvent) {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setOpen(false)
        setQuery('')
      }
    }

    document.addEventListener('mousedown', onClickOutside)
    return () => document.removeEventListener('mousedown', onClickOutside)
  }, [open])

  useEffect(() => {
    if (disabled) {
      setOpen(false)
      setQuery('')
    }
  }, [disabled])

  function selectOption(nextId: string) {
    onChange(nextId)
    setOpen(false)
    setQuery('')
  }

  return (
    <div
      className={styles.wrapper}
      ref={containerRef}
      dir={isFa ? 'rtl' : 'ltr'}
    >
      <div
        className={[
          styles.inputWrap,
          open ? styles.inputWrapOpen : '',
          disabled ? styles.inputWrapDisabled : '',
        ]
          .filter(Boolean)
          .join(' ')}
      >
        <Search size={16} className={styles.searchIcon} aria-hidden />
        <input
          id={id}
          type="text"
          className={styles.input}
          disabled={disabled}
          placeholder={selected ? selectedLabel : searchPlaceholder}
          value={open ? query : selectedLabel}
          onChange={(e) => {
            setQuery(e.target.value)
            if (!open) setOpen(true)
          }}
          onFocus={() => {
            if (!disabled) setOpen(true)
          }}
          autoComplete="off"
          role="combobox"
          aria-expanded={open}
          aria-autocomplete="list"
        />
        {value && !open && !disabled ? (
          <button
            type="button"
            className={styles.clearBtn}
            onClick={() => onChange('')}
            aria-label={t('myProducts.fields.clearCategory')}
          >
            <X size={14} />
          </button>
        ) : null}
        <ChevronDown
          size={16}
          className={`${styles.chevron} ${open ? styles.chevronOpen : ''}`}
          aria-hidden
        />
      </div>

      {open && !disabled ? (
        <ul className={styles.dropdown} role="listbox">
          {filtered.length === 0 ? (
            <li className={styles.noResults}>{t('myProducts.fields.noCategories')}</li>
          ) : (
            filtered.map((option) => (
              <li key={option.id}>
                <button
                  type="button"
                  className={[
                    styles.option,
                    option.depth > 0 ? styles.optionChild : '',
                    value === option.id ? styles.optionSelected : '',
                  ]
                    .filter(Boolean)
                    .join(' ')}
                  style={
                    option.depth > 0
                      ? {
                          marginInlineStart: `${option.depth * 22}px`,
                        }
                      : undefined
                  }
                  onClick={() => selectOption(option.id)}
                  role="option"
                  aria-selected={value === option.id}
                >
                  <span className={styles.optionLabel}>
                    {categoryLabel(option, isFa)}
                  </span>
                  {!isFa && option.nameFa ? (
                    <span className={styles.optionSecondary}>{option.nameFa}</span>
                  ) : null}
                  {isFa && option.name && option.name !== option.nameFa ? (
                    <span className={styles.optionSecondary} dir="ltr">
                      {option.name}
                    </span>
                  ) : null}
                </button>
              </li>
            ))
          )}
        </ul>
      ) : null}
    </div>
  )
}
