/**
 * FEAT-7: Statistik & Berichte (/statistik).
 *
 * Lädt Tiere + Würfe + Farbschläge komplett (kleine Bestände, Gridify-paged,
 * notfalls mehrseitig) und wertet clientseitig über die reinen Funktionen in
 * src/statistics aus. Diagramme: BarChart (FEAT-7), LineChart (FEAT-6,
 * unverändert wiederverwendet), div-basierte horizontale Balken für die
 * Farbschlag-Verteilung (eingefärbt über die FEAT-4-Chipfarben).
 */
import { useCallback, useMemo, type ReactNode } from 'react'
import { de } from '../strings/de'
import { listGerbils } from '../api/gerbils'
import { listLitters } from '../api/litters'
import { listColorVarieties } from '../api/lookups'
import type { GridifyQuery } from '../api/gridify'
import type { Gerbil, Paged } from '../api/types'
import { useApi } from '../hooks/useApi'
import { UNKNOWN_FARBSCHLAG, fromDisplayString, genotypeToFarbschlag } from '../genetics'
import {
  avgLitterSizePerYear,
  farbschlagDistribution,
  littersPerYear,
  lossesPerYear,
  populationOverTime,
  type YearValue,
} from '../statistics/aggregate'
import BarChart from '../components/BarChart'
import LineChart from '../components/LineChart'
import { chipColorFor } from '../pedigree/chipColors'
import './statistik.css'

/** Alle Seiten eines Gridify-Listen-Endpunkts einsammeln (kleine Bestände). */
async function allPages<T>(fetchPage: (q: GridifyQuery) => Promise<Paged<T>>): Promise<T[]> {
  const first = await fetchPage({ page: 1, pageSize: 1000 })
  const items = [...first.items]
  let page = 2
  while (items.length < first.totalCount && page <= 10) {
    const next = await fetchPage({ page, pageSize: 1000 })
    if (next.items.length === 0) break
    items.push(...next.items)
    page++
  }
  return items
}

const toBars = (rows: YearValue[]) =>
  rows.map((r) => ({ label: String(r.year), value: r.value }))

/**
 * Punktreihe fürs Liniendiagramm ausdünnen (LineChart zeichnet pro Punkt
 * einen Kreis — bei >60 Monatspunkten wird die Linie sonst „perlig“).
 * Erster und letzter Punkt bleiben immer erhalten.
 */
function thin<T>(points: T[], max = 60): T[] {
  if (points.length <= max) return points
  const step = Math.ceil(points.length / max)
  return points.filter((_, i) => i % step === 0 || i === points.length - 1)
}

function Section({
  title,
  hint,
  children,
}: {
  title: string
  hint?: string
  children: ReactNode
}) {
  return (
    <section className="statistik-card">
      <h3>{title}</h3>
      {hint && <p className="statistik-card__hint">{hint}</p>}
      {children}
    </section>
  )
}

export default function StatistikPage() {
  const t = de.pages.statistik

  const gerbils = useApi(() => allPages((q) => listGerbils(q)), [])
  const litters = useApi(() => allPages((q) => listLitters(q)), [])
  const colorVarieties = useApi(() => listColorVarieties(), [])

  const colorNameById = useMemo(
    () => new Map((colorVarieties.data ?? []).map((c) => [c.id, c.name])),
    [colorVarieties.data],
  )
  const farbschlagOf = useCallback(
    (g: Gerbil): string | null => {
      const byId = g.colorVarietyId ? colorNameById.get(g.colorVarietyId) : undefined
      if (byId) return byId
      if (g.genotype && g.genotype.trim()) {
        try {
          const name = genotypeToFarbschlag(fromDisplayString(g.genotype))
          return name === UNKNOWN_FARBSCHLAG ? null : name
        } catch {
          return null
        }
      }
      return null
    },
    [colorNameById],
  )

  const todayIso = new Date().toISOString().slice(0, 10)
  const stats = useMemo(() => {
    if (!gerbils.data || !litters.data) return null
    return {
      littersPerYear: littersPerYear(litters.data),
      avgLitterSize: avgLitterSizePerYear(litters.data),
      farbschlag: farbschlagDistribution(gerbils.data, farbschlagOf),
      population: populationOverTime(gerbils.data, todayIso),
      losses: lossesPerYear(gerbils.data),
    }
  }, [gerbils.data, litters.data, farbschlagOf, todayIso])

  if (gerbils.loading || litters.loading) return <p className="muted">{de.common.loading}</p>
  const loadError = gerbils.error ?? litters.error
  if (loadError || !stats) {
    return (
      <section className="page">
        <h2>{t.title}</h2>
        <div className="alert alert--error">
          <span>{loadError ?? de.api.errors.unknown}</span>
          <button
            type="button"
            className="btn"
            onClick={() => {
              gerbils.reload()
              litters.reload()
            }}
          >
            {de.common.retry}
          </button>
        </div>
      </section>
    )
  }

  const noData = gerbils.data!.length === 0 && litters.data!.length === 0
  const maxFarbschlagCount = Math.max(...stats.farbschlag.map((e) => e.count), 1)

  return (
    <section className="page">
      <h2>{t.title}</h2>

      {noData ? (
        <p className="muted">{t.empty}</p>
      ) : (
        <div className="statistik-grid">
          <Section title={t.littersPerYear}>
            {stats.littersPerYear.length > 0 ? (
              <BarChart bars={toBars(stats.littersPerYear)} title={t.littersPerYear} />
            ) : (
              <p className="muted">{t.sectionEmpty}</p>
            )}
          </Section>

          <Section title={t.avgLitterSize} hint={t.avgLitterSizeHint}>
            {stats.avgLitterSize.length > 0 ? (
              <BarChart bars={toBars(stats.avgLitterSize)} title={t.avgLitterSize} decimals={1} />
            ) : (
              <p className="muted">{t.sectionEmpty}</p>
            )}
          </Section>

          <Section title={t.farbschlag} hint={t.farbschlagHint}>
            {stats.farbschlag.length > 0 ? (
              <ul className="hbar-list">
                {stats.farbschlag.map((entry) => {
                  const name = entry.name ?? t.withoutFarbschlag
                  const chip = entry.name ? chipColorFor(entry.name) : null
                  return (
                    <li key={name} className="hbar">
                      <span className="hbar__label" title={name}>
                        {name}
                      </span>
                      <span className="hbar__track">
                        <span
                          className="hbar__fill"
                          style={{
                            width: `${(entry.count / maxFarbschlagCount) * 100}%`,
                            background: chip?.bg,
                          }}
                        />
                      </span>
                      <span className="hbar__count">{entry.count}</span>
                    </li>
                  )
                })}
              </ul>
            ) : (
              <p className="muted">{t.sectionEmpty}</p>
            )}
          </Section>

          <Section title={t.population} hint={t.populationHint}>
            {stats.population.length >= 2 ? (
              <LineChart
                points={thin(stats.population)}
                unit={t.populationUnit}
                title={t.population}
              />
            ) : (
              <p className="muted">{t.sectionEmpty}</p>
            )}
          </Section>

          <Section title={t.losses} hint={t.lossesHint}>
            {stats.losses.length > 0 ? (
              <BarChart bars={toBars(stats.losses)} title={t.losses} />
            ) : (
              <p className="muted">{t.sectionEmpty}</p>
            )}
          </Section>
        </div>
      )}
    </section>
  )
}
