/**
 * DESIGN (Rennmaus Filter.html): mobile-first filter UX —
 *   1. a horizontal "Quick-Chips" pill row (one pill per category, with a count badge),
 *   2. tapping a pill opens a bottom-sheet of multi-select options (✓ checkboxes,
 *      searchable for long lists like Farbschlag / Herkunft),
 *   3. active selections appear ABOVE the list as removable chips (so they scroll
 *      away with the list), with "Alle löschen".
 *
 * The user landed on the Quick-Chips concept, dezent style, brown accent. Colors
 * come from the app's existing tokens. `GerbilFilterBar` is the pill row + sheet;
 * `ActiveFilterChips` renders the removable chips and is placed above the list.
 */
import { useEffect, useMemo, useState, type CSSProperties, type ReactNode } from 'react'
import { createPortal } from 'react-dom'
import { de } from '../strings/de'
import './gerbilFilterBar.css'

export interface FilterOption {
  value: string
  label: string
  /** Optional swatch dot (used for status colors). */
  color?: string
  /** Optional leading symbol (used for gender ♂ ♀ ?). */
  symbol?: string
}

export interface FilterCategory {
  /** Matches the Gridify field / the key into the selected map. */
  key: string
  label: string
  /** Renders a search box above the option list (for long lists). */
  searchable?: boolean
  options: FilterOption[]
}

function countFor(selected: Record<string, string[]>, key: string): number {
  return (selected[key] ?? []).length
}

interface GerbilFilterBarProps {
  categories: FilterCategory[]
  selected: Record<string, string[]>
  onToggle: (key: string, value: string) => void
}

/** The Quick-Chips pill row + the category bottom-sheet. */
export function GerbilFilterBar({ categories, selected, onToggle }: GerbilFilterBarProps) {
  const t = de.filterBar
  const [activeKey, setActiveKey] = useState<string | null>(null)
  const activeCat = categories.find((c) => c.key === activeKey) ?? null

  return (
    <div className="rmf">
      <div className="rmf-quickrow" role="group" aria-label={t.title}>
        {categories.map((cat) => {
          const n = countFor(selected, cat.key)
          return (
            <button
              key={cat.key}
              type="button"
              className={'rmf-pill' + (n > 0 ? ' is-on' : '')}
              onClick={() => setActiveKey(cat.key)}
              aria-haspopup="dialog"
            >
              {cat.label}
              {n > 0 && <span className="rmf-pill-count">{n}</span>}
              <span className="rmf-pill-chev" aria-hidden="true">▾</span>
            </button>
          )
        })}
      </div>

      {activeCat && (
        <FilterSheet
          cat={activeCat}
          selected={selected[activeCat.key] ?? []}
          onToggle={onToggle}
          onClose={() => setActiveKey(null)}
        />
      )}
    </div>
  )
}

interface ActiveFilterChipsProps {
  categories: FilterCategory[]
  selected: Record<string, string[]>
  onRemove: (key: string, value: string) => void
  onClearAll: () => void
  /** Optional per-chip accent colour (e.g. status colours); falls back to the app accent. */
  chipColor?: (key: string, value: string) => string | undefined
}

/**
 * Removable chips for the active selections, placed above the list so they scroll
 * away as you browse. Wraps onto multiple lines — nothing is hidden.
 */
export function ActiveFilterChips({
  categories,
  selected,
  onRemove,
  onClearAll,
  chipColor,
}: ActiveFilterChipsProps) {
  const t = de.filterBar

  const chips = categories.flatMap((cat) => {
    const labelByValue = new Map(cat.options.map((o) => [o.value, o.label]))
    return (selected[cat.key] ?? []).map((value) => ({
      key: cat.key,
      value,
      catLabel: cat.label,
      label: labelByValue.get(value) ?? value,
    }))
  })

  if (chips.length === 0) return null

  return (
    <div className="rmf-chips">
      {chips.map((c) => {
        const accent = chipColor?.(c.key, c.value)
        return (
          <button
            key={c.key + c.value}
            type="button"
            className="rmf-chip"
            style={accent ? ({ '--chip': accent } as CSSProperties) : undefined}
            onClick={() => onRemove(c.key, c.value)}
            aria-label={`${c.catLabel}: ${c.label} — ${t.remove}`}
          >
            <span className="rmf-chip-cat">{c.catLabel}</span>
            <span className="rmf-chip-val">{c.label}</span>
            <span className="rmf-chip-x" aria-hidden="true">×</span>
          </button>
        )
      })}
      {chips.length > 1 && (
        <button type="button" className="rmf-chip rmf-chip-clear" onClick={onClearAll}>
          {t.clearAll}
        </button>
      )}
    </div>
  )
}

interface BottomSheetProps {
  title: string
  onClose: () => void
  children: ReactNode
}

/**
 * Reusable bottom-sheet: dimmed scrim + slide-up panel with grip, title and a
 * "Fertig" button. Locks body scroll and closes on Escape / scrim tap. Used for
 * the category filters AND the sort selector (same drawer mechanic).
 */
export function BottomSheet({ title, onClose, children }: BottomSheetProps) {
  const t = de.filterBar

  useEffect(() => {
    const prev = document.body.style.overflow
    document.body.style.overflow = 'hidden'
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose()
    }
    window.addEventListener('keydown', onKey)
    return () => {
      document.body.style.overflow = prev
      window.removeEventListener('keydown', onKey)
    }
  }, [onClose])

  // Portal to <body> so the sheet escapes any sticky/stacking-context ancestor
  // (e.g. the sticky header) and renders above the bottom action bar.
  return createPortal(
    <div className="rmf-scrim" onClick={onClose} role="presentation">
      <div
        className="rmf-sheet"
        role="dialog"
        aria-modal="true"
        aria-label={title}
        onClick={(e) => e.stopPropagation()}
      >
        <div className="rmf-grip" aria-hidden="true" />
        <div className="rmf-sheet-head">
          <span className="rmf-sheet-title">{title}</span>
          <button type="button" className="rmf-sheet-done" onClick={onClose}>
            {t.done}
          </button>
        </div>
        <div className="rmf-sheet-body">{children}</div>
      </div>
    </div>,
    document.body,
  )
}

interface FilterSheetProps {
  cat: FilterCategory
  selected: string[]
  onToggle: (key: string, value: string) => void
  onClose: () => void
}

function FilterSheet({ cat, selected, onToggle, onClose }: FilterSheetProps) {
  return (
    <BottomSheet title={cat.label} onClose={onClose}>
      <OptionList cat={cat} selected={selected} onToggle={onToggle} />
    </BottomSheet>
  )
}

interface OptionListProps {
  cat: FilterCategory
  selected: string[]
  onToggle: (key: string, value: string) => void
}

function OptionList({ cat, selected, onToggle }: OptionListProps) {
  const t = de.filterBar
  const [q, setQ] = useState('')

  const options = useMemo(() => {
    if (!cat.searchable) return cat.options
    const term = q.trim().toLowerCase()
    if (!term) return cat.options
    return cat.options.filter((o) => o.label.toLowerCase().includes(term))
  }, [cat, q])

  return (
    <div className="rmf-picker">
      {cat.searchable && (
        <input
          className="rmf-search"
          placeholder={t.searchPlaceholder}
          value={q}
          onChange={(e) => setQ(e.target.value)}
          autoFocus
          aria-label={t.searchPlaceholder}
        />
      )}
      <div className={'rmf-optlist' + (cat.searchable ? ' rmf-optlist--scroll' : '')}>
        {options.length === 0 && <div className="rmf-empty">{t.noMatch}</div>}
        {options.map((o) => {
          const on = selected.includes(o.value)
          return (
            <button
              key={o.value}
              type="button"
              className={'rmf-opt' + (on ? ' is-on' : '')}
              onClick={() => onToggle(cat.key, o.value)}
              aria-pressed={on}
            >
              <span className="rmf-opt-box" aria-hidden="true">
                {on ? '✓' : ''}
              </span>
              {o.color && <span className="rmf-opt-dot" style={{ background: o.color }} />}
              {o.symbol && (
                <span className="rmf-opt-sym" aria-hidden="true">
                  {o.symbol}
                </span>
              )}
              <span className="rmf-opt-label">{o.label}</span>
            </button>
          )
        })}
      </div>
    </div>
  )
}
