import { useEffect, useMemo, useRef, useState } from 'react'
import { Check, Search, X } from 'lucide-react'
import { Button } from './Button'
import { t, tf } from '../../lib/i18n'

export interface CheckboxPickerItem {
  id: number
  label: string
  description?: string
}

interface CheckboxPickerProps {
  triggerLabel: string
  placeholder: string
  items: CheckboxPickerItem[]
  selectedItems: CheckboxPickerItem[]
  loading?: boolean
  disabled?: boolean
  searchTerm: string
  onSearchChange: (value: string) => void
  onConfirm: (items: CheckboxPickerItem[]) => void
  onLoadMore?: () => void
  hasMore?: boolean
  emptyLabel?: string
  loadingLabel?: string
}

function areSameSelection(left: CheckboxPickerItem[], right: CheckboxPickerItem[]): boolean {
  if (left.length !== right.length) {
    return false
  }

  const leftIds = left.map(item => item.id).sort((a, b) => a - b)
  const rightIds = right.map(item => item.id).sort((a, b) => a - b)

  return leftIds.every((id, index) => id === rightIds[index])
}

export function CheckboxPicker({
  triggerLabel,
  placeholder,
  items,
  selectedItems,
  loading = false,
  disabled = false,
  searchTerm,
  onSearchChange,
  onConfirm,
  onLoadMore,
  hasMore = false,
  emptyLabel,
  loadingLabel,
}: CheckboxPickerProps) {
  const containerRef = useRef<HTMLDivElement>(null)
  const [isOpen, setIsOpen] = useState(false)
  const [draftSelection, setDraftSelection] = useState<CheckboxPickerItem[]>(selectedItems)

  useEffect(() => {
    if (isOpen) {
      return
    }

    if (!areSameSelection(draftSelection, selectedItems)) {
      setDraftSelection(selectedItems)
    }
  }, [draftSelection, isOpen, selectedItems])

  useEffect(() => {
    const handleOutsideClick = (event: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
        setIsOpen(false)
      }
    }

    document.addEventListener('mousedown', handleOutsideClick)
    return () => document.removeEventListener('mousedown', handleOutsideClick)
  }, [])

  const visibleItems = useMemo(() => {
    const needle = searchTerm.trim().toLowerCase()
    if (!needle) {
      return items
    }

    return items.filter(item => {
      const haystack = `${item.label} ${item.description || ''}`.toLowerCase()
      return haystack.includes(needle)
    })
  }, [items, searchTerm])

  const selectedIds = useMemo(() => new Set(draftSelection.map(item => item.id)), [draftSelection])

  const allVisibleSelected = visibleItems.length > 0 && visibleItems.every(item => selectedIds.has(item.id))

  const triggerSummary = selectedItems.length > 0
    ? selectedItems.length === 1
      ? selectedItems[0].label
      : tf('%d selected', selectedItems.length)
    : placeholder

  const handleToggle = (item: CheckboxPickerItem) => {
    setDraftSelection(prev => {
      const exists = prev.some(entry => entry.id === item.id)
      if (exists) {
        return prev.filter(entry => entry.id !== item.id)
      }

      return [...prev, item]
    })
  }

  const handleSelectAll = () => {
    setDraftSelection(prev => {
      const next = new Map(prev.map(item => [item.id, item]))

      if (allVisibleSelected) {
        visibleItems.forEach(item => next.delete(item.id))
      } else {
        visibleItems.forEach(item => next.set(item.id, item))
      }

      return Array.from(next.values())
    })
  }

  const handleConfirm = () => {
    if (draftSelection.length === 0) {
      return
    }

    onConfirm(draftSelection)
    setIsOpen(false)
  }

  return (
    <div ref={containerRef} className="relative min-w-[260px] flex-1">
      <button
        type="button"
        onClick={() => {
          if (!isOpen) {
            setDraftSelection(selectedItems)
          }

          setIsOpen(prev => !prev)
        }}
        disabled={disabled}
        className="flex w-full items-center justify-between gap-3 rounded-lg border border-bc-gray-300 bg-white px-3 py-2 text-start text-sm transition-colors hover:border-bc-primary disabled:cursor-not-allowed disabled:opacity-60"
      >
        <div className="min-w-0">
          <div className="text-xs text-bc-gray-400">{triggerLabel}</div>
          <div className="truncate text-bc-gray-700">{triggerSummary}</div>
        </div>
        {selectedItems.length > 0 && (
          <span className="shrink-0 rounded-full bg-bc-primary-light px-2 py-0.5 text-xs font-medium text-bc-primary">
            {selectedItems.length}
          </span>
        )}
      </button>

      {isOpen && (
        <div className="absolute z-20 mt-1 w-full rounded-lg border border-bc-gray-200 bg-white shadow-bc-lg">
          <div className="border-b border-bc-gray-100 p-3">
            <div className="relative">
              <Search className="pointer-events-none absolute inset-y-0 end-3 my-auto h-4 w-4 text-bc-gray-400" />
              <input
                type="text"
                value={searchTerm}
                onChange={e => onSearchChange(e.target.value)}
                placeholder={t('Search...')}
                className="w-full rounded-lg border border-bc-gray-300 bg-white px-3 py-2 pe-9 text-sm outline-none transition-colors focus:border-bc-primary focus:ring-1 focus:ring-bc-primary"
              />
            </div>
          </div>

          <div className="border-b border-bc-gray-100 px-3 py-2">
            <label className="flex cursor-pointer items-center gap-2 text-sm text-bc-gray-700">
              <input
                type="checkbox"
                checked={allVisibleSelected}
                onChange={handleSelectAll}
                className="h-4 w-4 rounded border-bc-gray-300 text-bc-primary focus:ring-bc-primary"
              />
              <span>{allVisibleSelected ? t('Deselect all') : t('Select all')}</span>
            </label>
          </div>

          <div className="max-h-64 overflow-y-auto">
            {loading ? (
              <div className="px-3 py-3 text-sm text-bc-gray-500">{loadingLabel || t('Loading...')}</div>
            ) : visibleItems.length === 0 ? (
              <div className="px-3 py-3 text-sm text-bc-gray-500">{emptyLabel || t('No results found')}</div>
            ) : (
              visibleItems.map(item => {
                const checked = selectedIds.has(item.id)

                return (
                  <label
                    key={item.id}
                    className="flex cursor-pointer items-start gap-3 border-b border-bc-gray-50 px-3 py-2 text-sm last:border-b-0 hover:bg-bc-gray-50"
                  >
                    <input
                      type="checkbox"
                      checked={checked}
                      onChange={() => handleToggle(item)}
                      className="mt-0.5 h-4 w-4 rounded border-bc-gray-300 text-bc-primary focus:ring-bc-primary"
                    />
                    <div className="min-w-0 flex-1">
                      <div className="truncate text-bc-gray-700">{item.label}</div>
                      {item.description && (
                        <div className="truncate text-xs text-bc-gray-400">{item.description}</div>
                      )}
                    </div>
                  </label>
                )
              })
            )}
          </div>

          {hasMore && onLoadMore && (
            <div className="border-t border-bc-gray-100 px-3 py-2">
              <Button size="sm" variant="ghost" onClick={onLoadMore} className="w-full justify-center">
                {t('Load more')}
              </Button>
            </div>
          )}

          <div className="flex items-center justify-between gap-3 border-t border-bc-gray-100 px-3 py-3">
            <div className="text-sm text-bc-gray-600">{tf('%d selected', draftSelection.length)}</div>
            <div className="flex items-center gap-2">
              <Button
                size="sm"
                variant="ghost"
                onClick={() => {
                  setDraftSelection(selectedItems)
                  setIsOpen(false)
                }}
                icon={<X className="h-4 w-4" />}
              >
                {t('Cancel')}
              </Button>
              <Button
                size="sm"
                onClick={handleConfirm}
                disabled={draftSelection.length === 0}
                icon={<Check className="h-4 w-4" />}
              >
                {t('Confirm')}
              </Button>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}
