import { useMemo, useState } from 'react'
import { Link } from 'react-router-dom'
import { de } from '../strings/de'
import { listGerbils, listOriginBreeders, updateGerbil } from '../api/gerbils'
import { listColorVarieties } from '../api/lookups'
import { andFilter, condition, type GridifyQuery } from '../api/gridify'
import { GENDERS, GERBIL_STATUSES, type Gender, type GerbilStatus } from '../api/types'
import { useApi, useMutation } from '../hooks/useApi'
import { formatDate, genderLabel, statusLabel } from '../format/labels'
import { FilterPanel } from '../components/FilterPanel'
import './gerbils.css'

const PAGE_SIZE = 20

// SEARCH-2b: separator-insensitive search via Pam's normalized field. The term
// is normalized the SAME way server-side stores it (lowercase + strip [\s._-]),
// so 'clan kleine chaoten' matches 'clan-kleine-chaoten'.
const NAME_SEARCH_FIELD = 'nameSearch'
const normalizeSearch = (s: string): string => s.toLowerCase().replace(/[\s._-]/g, '')

type SortKey = 'nameAsc' | 'nameDesc' | 'birthDesc' | 'birthAsc'
const SORT_ORDER_BY: Record<SortKey, string> = {
  nameAsc: 'name',
  nameDesc: 'name desc',
  birthDesc: 'dateOfBirth desc',
  birthAsc: 'dateOfBirth',
}

export default function GerbilsPage() {
  const t = de.pages.gerbils
  const [search, setSearch] = useState('')
  const [status, setStatus] = useState<GerbilStatus | ''>('Active')
  const [gender, setGender] = useState<Gender | ''>('')
  const [colorVarietyId, setColorVarietyId] = useState('')
  const [originBreeder, setOriginBreeder] = useState('')
  // BESTAND-FILTER: default to the own clan (Bestand); opt in to external ancestors.
  const [showExternal, setShowExternal] = useState(false)
  const [sort, setSort] = useState<SortKey>('nameAsc')
  const [page, setPage] = useState(1)

  const colorVarieties = useApi(() => listColorVarieties(), [])
  const colorNameById = useMemo(() => {
    const map = new Map<string, string>()
    for (const cv of colorVarieties.data ?? []) map.set(cv.id, cv.name)
    return map
  }, [colorVarieties.data])
  const breeders = useApi(() => listOriginBreeders(), [])

  const filter = andFilter(
    search.trim() &&
      condition({ field: NAME_SEARCH_FIELD, op: 'contains', value: normalizeSearch(search) }),
    status && condition({ field: 'status', op: '==', value: status }),
    gender && condition({ field: 'gender', op: '==', value: gender }),
    colorVarietyId && condition({ field: 'colorVarietyId', op: '==', value: colorVarietyId }),
    originBreeder && condition({ field: 'originBreeder', op: '==', value: originBreeder }),
    // Default view = own clan (Bestand). Unless "externe Ahnen einblenden" is on,
    // restrict to resident animals (server-side, so paging/counts stay correct).
    !showExternal && condition({ field: 'isResident', op: '==', value: true }),
  )
  const orderBy = SORT_ORDER_BY[sort]
  const query: GridifyQuery = { filter: filter || undefined, orderBy, page, pageSize: PAGE_SIZE }

  const gerbils = useApi(() => listGerbils(query), [filter, orderBy, page])

  const resetFilters = () => {
    setSearch('')
    setStatus('Active')
    setGender('')
    setColorVarietyId('')
    setOriginBreeder('')
    setShowExternal(false)
    setPage(1)
    setSort('nameAsc')
  }

  // When a filter changes, jump back to page 1.
  const onFilterChange = <T,>(setter: (v: T) => void) => (value: T) => {
    setter(value)
    setPage(1)
  }

  const total = gerbils.data?.totalCount ?? 0
  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE))
  const items = gerbils.data?.items ?? []

  // UX-MOBILE-1: count non-default filter values for the badge.
  const activeFilterCount =
    (status !== 'Active' ? 1 : 0) +
    (gender !== '' ? 1 : 0) +
    (colorVarietyId !== '' ? 1 : 0) +
    (originBreeder !== '' ? 1 : 0) +
    (showExternal ? 1 : 0)

  // Multi-select bulk "Zur Abgabe stellen".
  const [selected, setSelected] = useState<Set<string>>(new Set())
  const toggleSelect = (id: string) =>
    setSelected((prev) => {
      const next = new Set(prev)
      if (next.has(id)) next.delete(id)
      else next.add(id)
      return next
    })
  const bulkForSale = useMutation((ids: string[]) =>
    Promise.all(ids.map((id) => updateGerbil(id, { status: 'ForSale' }))),
  )
  async function markSelectedForSale() {
    const result = await bulkForSale.run([...selected])
    if (result.ok) {
      setSelected(new Set())
      gerbils.reload()
    }
  }

  return (
    <section className="page">
      <header className="page-head">
        <div>
          <h2>{t.title}</h2>
          {gerbils.data && (
            <p className="muted">
              {total} {t.countLabel}
            </p>
          )}
        </div>
        <Link to="/rennmaeuse/neu" className="btn btn--primary">
          + {t.newButton}
        </Link>
      </header>

      <FilterPanel
        searchField={
          <input
            type="search"
            className="input"
            placeholder={t.searchPlaceholder}
            value={search}
            onChange={(e) => onFilterChange(setSearch)(e.target.value)}
            aria-label={t.fields.name}
          />
        }
        activeCount={activeFilterCount}
        onReset={resetFilters}
      >
        <label className="field">
          <span>{t.filters.status}</span>
          <select
            value={status}
            onChange={(e) => onFilterChange(setStatus)(e.target.value as GerbilStatus | '')}
          >
            <option value="">{t.filters.all}</option>
            {GERBIL_STATUSES.map((s) => (
              <option key={s} value={s}>
                {statusLabel(s)}
              </option>
            ))}
          </select>
        </label>
        <label className="field">
          <span>{t.filters.gender}</span>
          <select
            value={gender}
            onChange={(e) => onFilterChange(setGender)(e.target.value as Gender | '')}
          >
            <option value="">{t.filters.all}</option>
            {GENDERS.map((g) => (
              <option key={g} value={g}>
                {genderLabel(g)}
              </option>
            ))}
          </select>
        </label>
        <label className="field">
          <span>{t.filters.colorVariety}</span>
          <select
            value={colorVarietyId}
            onChange={(e) => onFilterChange(setColorVarietyId)(e.target.value)}
          >
            <option value="">{t.filters.all}</option>
            {(colorVarieties.data ?? []).map((cv) => (
              <option key={cv.id} value={cv.id}>
                {cv.name}
              </option>
            ))}
          </select>
        </label>
        <label className="field">
          <span>{t.fields.origin}</span>
          <select
            value={originBreeder}
            onChange={(e) => onFilterChange(setOriginBreeder)(e.target.value)}
          >
            <option value="">{t.filters.all}</option>
            {(breeders.data ?? []).map((b) => (
              <option key={b} value={b}>
                {b}
              </option>
            ))}
          </select>
        </label>
        <label className="field">
          <span>{t.filters.sortBy}</span>
          <select value={sort} onChange={(e) => setSort(e.target.value as SortKey)}>
            <option value="nameAsc">{t.sort.nameAsc}</option>
            <option value="nameDesc">{t.sort.nameDesc}</option>
            <option value="birthDesc">{t.sort.birthDesc}</option>
            <option value="birthAsc">{t.sort.birthAsc}</option>
          </select>
        </label>
        <label className="field field--check" title={t.filters.showExternalHint}>
          <span>{t.filters.showExternal}</span>
          <input
            type="checkbox"
            checked={showExternal}
            onChange={(e) => onFilterChange(setShowExternal)(e.target.checked)}
          />
        </label>
      </FilterPanel>

      {gerbils.loading && <p className="muted">{de.common.loading}</p>}
      {gerbils.error && (
        <div className="alert alert--error">
          <span>{gerbils.error}</span>
          <button type="button" className="btn" onClick={gerbils.reload}>
            {de.common.retry}
          </button>
        </div>
      )}

      {!gerbils.loading && !gerbils.error && items.length === 0 && (
        <p className="muted">{t.empty}</p>
      )}

      {selected.size > 0 && (
        <div className="bulk-bar">
          <span>
            {selected.size} {t.countLabel}
          </span>
          <button
            type="button"
            className="btn btn--primary"
            disabled={bulkForSale.pending}
            onClick={markSelectedForSale}
          >
            {de.pages.abgabe.markMultiAction}
          </button>
          {bulkForSale.error && <span className="error-text">{bulkForSale.error}</span>}
        </div>
      )}

      {items.length > 0 && (
        <ul className="card-list">
          {items.map((g) => (
            <li key={g.id} className="gerbil-row">
              <input
                type="checkbox"
                className="gerbil-row__check"
                checked={selected.has(g.id)}
                onChange={() => toggleSelect(g.id)}
                aria-label={g.name || t.nameless}
              />
              <Link to={`/rennmaeuse/${g.id}`} className="gerbil-card">
                <span className="gerbil-card__name">
                  {g.name || t.nameless}
                  {g.isResident === false && (
                    <span className="badge badge--external" title={t.externalTitle}>
                      {t.externalBadge}
                    </span>
                  )}
                </span>
                <span className={`badge badge--${g.status.toLowerCase()}`}>
                  {statusLabel(g.status)}
                </span>
                <span className="gerbil-card__meta">{genderLabel(g.gender)}</span>
                <span className="gerbil-card__meta">
                  {g.colorVarietyId ? (colorNameById.get(g.colorVarietyId) ?? '—') : '—'}
                </span>
                <span className="gerbil-card__meta">{formatDate(g.dateOfBirth)}</span>
              </Link>
            </li>
          ))}
        </ul>
      )}

      {totalPages > 1 && (
        <nav className="pager" aria-label={de.common.pageNav}>
          <button
            type="button"
            className="btn"
            disabled={page <= 1}
            onClick={() => setPage((p) => Math.max(1, p - 1))}
          >
            {de.common.previous}
          </button>
          <span className="muted">
            {de.common.page} {page} {de.common.of} {totalPages}
          </span>
          <button
            type="button"
            className="btn"
            disabled={page >= totalPages}
            onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
          >
            {de.common.next}
          </button>
        </nav>
      )}
    </section>
  )
}
