import { useMemo, useState, type ReactNode } from 'react'
import { Link, useParams } from 'react-router-dom'
import { de } from '../strings/de'
import { getGerbil, updateGerbil, listGerbils } from '../api/gerbils'
import { getVerifiedStatus, verifyGerbil, unverifyGerbil } from '../api/verified'
import { listLitters as listLittersPaged } from '../api/litters'
import { listColorVarieties, listContacts, listEnclosures, listLitters } from '../api/lookups'
import { useApi, useMutation } from '../hooks/useApi'
import { formatDate, genderLabel, statusLabel } from '../format/labels'
import { ALL_TRAITS, TRAIT_CATEGORIES } from '../format/traits'
import {
  fromDisplayString,
  genotypeToFarbschlag,
  formatVarietyName,
  displayGenotypeSafe,
  toDisplayString,
  hasUnknown,
  inferUnknownsFromParents,
} from '../genetics'
import type { Gender, GerbilStatus } from '../api/types'
import FarbschlagImage from '../components/FarbschlagImage'
import GerbilAcquisitionSection from '../components/GerbilAcquisitionSection'
import GerbilExhibitionsTab from '../components/GerbilExhibitionsTab'
import GerbilHealthTab from '../components/GerbilHealthTab'
import GerbilPhotosTab from '../components/GerbilPhotosTab'
import GerbilProfilePhoto from '../components/GerbilProfilePhoto'
import GerbilWeightTab from '../components/GerbilWeightTab'
import ProvenanceDialog from '../components/ProvenanceDialog'
import ReportErrorDialog from '../components/ReportErrorDialog'
import { useGerbilName } from '../components/breederSuffix'
import { useToast } from '../components/toast'
import './rennmausakte.css'

type DetailTab = 'photos' | 'health' | 'weight' | 'exhibitions'

// DESIGN (Rennmausakte): per-status colours for the hero status badge.
const STATUS_COLORS: Record<GerbilStatus, string> = {
  Breeding: '#5e8c5a',
  Pet: '#5a7da8',
  ForSale: '#c2703d',
  Deceased: '#8a847b',
  GivenAway: '#b08e5c',
}
const GENDER_SYMBOL: Record<Gender, string> = { unknown: '?', male: '♂', female: '♀' }

/** Parse a stored genotype string and derive its normalized form + Farbschlag. */
function describeGenotype(genotype: string | null): { display: string; farbschlag: string } | null {
  if (!genotype || !genotype.trim()) return null
  try {
    const g = fromDisplayString(genotype)
    return { display: displayGenotypeSafe(genotype), farbschlag: genotypeToFarbschlag(g) }
  } catch {
    return { display: displayGenotypeSafe(genotype), farbschlag: de.genetics.unknownFarbschlag }
  }
}

/** A labelled key/value row inside a card (semantic dt/dd, styled as a grid). */
/** „Saphir Schecke" → „Saphir": Modifier-Zusaetze fuer den Namensvergleich abschneiden. */
function stripVarietyModifiers(name: string): string {
  return name.replace(' Schecke', '').replace(' Rex', '').trim()
}

function Kv({ label, children }: { label: string; children: ReactNode }) {
  return (
    <div className="ak-kv">
      <dt className="ak-kv-label">{label}</dt>
      <dd className="ak-kv-value">{children}</dd>
    </div>
  )
}

export default function GerbilDetailPage() {
  const t = de.pages.gerbils
  const gerbilName = useGerbilName()
  const toast = useToast()
  const { id = '' } = useParams()
  const [tab, setTab] = useState<DetailTab>('photos')
  const [reportOpen, setReportOpen] = useState(false)
  const [provenanceOpen, setProvenanceOpen] = useState(false)

  const gerbil = useApi(() => getGerbil(id), [id])
  const forSale = useMutation(() => updateGerbil(id, { status: 'ForSale' }))
  // GEPRÜFTE TIERE: „vollständig korrekt"-Markierung / Schutz-Status dieses Tiers.
  const verifiedStatus = useApi(() => getVerifiedStatus(id), [id])
  const verify = useMutation(() => verifyGerbil(id))
  const unverify = useMutation(() => unverifyGerbil(id))
  // FEAT-14: Charakterbogen (persisted on the Gerbil).
  const [charTraits, setCharTraits] = useState<string[]>([])
  const [charNote, setCharNote] = useState('')
  const [charInit, setCharInit] = useState<string | null>(null)
  // Charakter ist v. a. für lebende Bestandstiere relevant → bei Zucht/Liebhaber
  // aufgeklappt, sonst (Abgabe/Verstorben/Abgegeben) eingeklappt (manuell öffenbar).
  const [charExpanded, setCharExpanded] = useState(true)
  const saveCharacter = useMutation(() =>
    updateGerbil(id, { characterTraits: charTraits, characterNote: charNote.trim() || null }),
  )
  const colorVarieties = useApi(() => listColorVarieties(), [])
  const enclosures = useApi(() => listEnclosures(), [])
  const contacts = useApi(() => listContacts(), [])
  const litters = useApi(() => listLitters(), [])
  const parentLitters = useApi(
    () => listLittersPaged({ filter: `fatherId=${id}|motherId=${id}`, orderBy: 'date desc', pageSize: 50 }),
    [id],
  )

  const breedingParentIds = useMemo(() => {
    const ids = new Set<string>()
    for (const l of litters.data ?? []) {
      if (l.fatherId) ids.add(l.fatherId)
      if (l.motherId) ids.add(l.motherId)
    }
    return ids
  }, [litters.data])

  const offspring = useApi(
    () => {
      const litterIds = (parentLitters.data?.items ?? []).map((l) => l.id)
      if (litterIds.length === 0) {
        return Promise.resolve({ items: [], totalCount: 0, page: 1, pageSize: 100 })
      }
      const filter = litterIds.map((lid) => `litterId=${lid}`).join('|')
      return listGerbils({ filter, pageSize: 200 })
    },
    [parentLitters.data],
  )

  // ZUCHTPARTNER: die jeweils anderen Elterntiere der eigenen Würfe (distinct).
  const partnerIds = useMemo(() => {
    const ids = new Set<string>()
    for (const l of parentLitters.data?.items ?? []) {
      const pid = l.fatherId === id ? l.motherId : l.fatherId
      if (pid && pid !== id) ids.add(pid)
    }
    return [...ids]
  }, [parentLitters.data, id])
  const partners = useApi(
    () =>
      partnerIds.length === 0
        ? Promise.resolve({ items: [], totalCount: 0, page: 1, pageSize: 100 })
        : listGerbils({ filter: partnerIds.map((pid) => `id=${pid}`).join('|'), pageSize: 100 }),
    [partnerIds],
  )

  const breedingOffspring = useMemo(() => {
    return (offspring.data?.items ?? []).filter(
      (child) => child.status === 'Breeding' || breedingParentIds.has(child.id),
    )
  }, [offspring.data, breedingParentIds])


  const colorName = useMemo(
    () => new Map((colorVarieties.data ?? []).map((c) => [c.id, c.name])),
    [colorVarieties.data],
  )
  const enclosureName = useMemo(
    () => new Map((enclosures.data ?? []).map((e) => [e.id, e.name])),
    [enclosures.data],
  )
  const contactName = useMemo(
    () => new Map((contacts.data ?? []).map((c) => [c.id, c.name])),
    [contacts.data],
  )
  const litterName = useMemo(
    () => new Map((litters.data ?? []).map((l) => [l.id, l.name])),
    [litters.data],
  )

  // Parents come from the gerbil's own litter (litterId → litter.fatherId/motherId).
  // Fetch each parent gerbil for its name + link (mirrors WurfDetailPage).
  const ownLitterId = gerbil.data?.litterId ?? null
  const ownLitter = useMemo(
    () => (ownLitterId ? ((litters.data ?? []).find((l) => l.id === ownLitterId) ?? null) : null),
    [litters.data, ownLitterId],
  )
  const fatherId = ownLitter?.fatherId ?? null
  const motherId = ownLitter?.motherId ?? null
  const father = useApi(() => (fatherId ? getGerbil(fatherId) : Promise.resolve(null)), [fatherId])
  const mother = useApi(() => (motherId ? getGerbil(motherId) : Promise.resolve(null)), [motherId])

  // Character chips — toggle while preserving the catalog order (stable output).
  const selectedTraits = new Set(charTraits)
  const toggleTrait = (key: string) => {
    const next = new Set(selectedTraits)
    if (next.has(key)) next.delete(key)
    else next.add(key)
    setCharTraits(ALL_TRAITS.filter((tr) => next.has(tr.key)).map((tr) => tr.key))
  }

  if (gerbil.loading) return <p className="muted">{de.common.loading}</p>
  if (gerbil.error || !gerbil.data) {
    return (
      <section className="page">
        <p className="muted">{gerbil.error ?? t.detail.notFound}</p>
        <Link to="/rennmaeuse" className="btn">
          {t.detail.back}
        </Link>
      </section>
    )
  }

  const g = gerbil.data
  // Abgegebene/verstorbene Tiere sind nicht mehr im eigenen Bestand → kein Gehege.
  const showEnclosure = g.status !== 'Deceased' && g.status !== 'GivenAway'

  const geno = describeGenotype(g.genotype)
  // GEN-5 (Tickets cc9ea3fe / 1a508c04): unbekannte Gencode-Buchstaben aus einem
  // reinerbigen Elternteil ergänzen (Mendel: ein reinerbiger Elternteil kann nur
  // dieses eine Allel vererben). Greift nur, wenn der Genotyp ein '-' enthält UND
  // mindestens ein Elternteil mit Genotyp am eigenen Wurf hinterlegt ist.
  const genoInferred = (() => {
    if (!g.genotype) return null
    let child
    try {
      child = fromDisplayString(g.genotype)
    } catch {
      return null
    }
    if (!hasUnknown(child)) return null
    const parse = (s: string | null | undefined) => {
      if (!s) return null
      try {
        return fromDisplayString(s)
      } catch {
        return null
      }
    }
    const f = parse(father.data?.genotype)
    const m = parse(mother.data?.genotype)
    if (!f && !m) return null
    const res = inferUnknownsFromParents(child, f, m)
    if (res.inferred.length === 0) return null
    const display = toDisplayString(res.genotype)
    if (display === geno?.display) return null
    return { display, farbschlag: genotypeToFarbschlag(res.genotype) }
  })()

  const lookup = (map: Map<string, string>, key: string | null) => (key ? (map.get(key) ?? '—') : '—')
  const baseColorName = g.colorVarietyId ? (colorName.get(g.colorVarietyId) ?? null) : null
  const storedColorName = baseColorName ? formatVarietyName(baseColorName, g.genotype) : null

  // Geschwisterverpaarung: Vater und Mutter dieses Tiers sind Vollgeschwister —
  // erkennbar an gemeinsamer litterId ODER gleichem Geburtsdatum (starkes Indiz:
  // ein identisches Datum entsteht praktisch nur durch einen gemeinsamen Wurf,
  // und die Eltern-Würfe sind in den Daten nicht immer verknüpft).
  const isSiblingPairing =
    !!father.data &&
    !!mother.data &&
    father.data.id !== mother.data.id &&
    ((!!father.data.litterId && father.data.litterId === mother.data.litterId) ||
      (!!father.data.dateOfBirth && father.data.dateOfBirth === mother.data.dateOfBirth))

  const parentLink = (
    pid: string | null,
    p: Parameters<typeof gerbilName>[0] | null,
  ): ReactNode =>
    pid && p ? (
      <Link to={`/rennmaeuse/${pid}`}>{gerbilName(p) || de.pages.gerbils.nameless}</Link>
    ) : (
      de.pages.litters.detail.unknownParent
    )

  // Seed the character state once from the loaded gerbil (adjust-state-during-render).
  if (charInit !== g.id) {
    setCharInit(g.id)
    setCharTraits(g.characterTraits ?? [])
    setCharNote(g.characterNote ?? '')
    setCharExpanded(g.status === 'Breeding' || g.status === 'Pet')
  }

  return (
    <section className="ak">
      <div className="ak-hero">
        <GerbilProfilePhoto
          gerbilId={g.id}
          className="ak-herophoto"
          fallback={
            <div className="ak-herophoto ak-herophoto--empty" aria-hidden="true">
              🐭
            </div>
          }
        />
        <div className="ak-herobar">
          <Link to="/rennmaeuse" className="ak-back" aria-label={t.detail.back}>
            ‹
          </Link>
        </div>
        <div className="ak-heroover">
          <h1 className="ak-name">{gerbilName(g) || de.pages.gerbils.nameless}</h1>
          {g.isResident !== false && (parentLitters.data?.items.length ?? 0) > 0 && (
            <span
              className="ak-badge-extern"
              style={{ color: '#5e8c5a' }}
              title={t.detail.zuchttierBadgeTitle}
            >
              {t.detail.zuchttierBadge}
            </span>
          )}
          <span className="ak-statusbadge" style={{ color: STATUS_COLORS[g.status] }}>
            {statusLabel(g.status)}
          </span>
          {g.isResident === false && (
            <span className="ak-badge-extern" title={de.pages.gerbils.externalTitle}>
              {de.pages.gerbils.externalBadge}
            </span>
          )}
          {verifiedStatus.data?.isVerified && (
            <span
              className="ak-badge-extern"
              style={{ color: '#5e8c5a' }}
              title={de.verified.verifiedBadgeTitle}
            >
              {de.verified.verifiedBadge}
            </span>
          )}
          {verifiedStatus.data && !verifiedStatus.data.isVerified && (
            <span
              className="ak-badge-extern"
              style={{ color: '#5a7da8' }}
              title={de.verified.protectedBadgeTitle}
            >
              {de.verified.protectedBadge}
            </span>
          )}
          {verifiedStatus.data?.status === 'drifted' && (
            <span
              className="ak-badge-extern"
              style={{ color: '#c2703d' }}
              title={de.verified.driftBadgeTitle}
            >
              {de.verified.driftBadge}
            </span>
          )}
        </div>
      </div>

      <div className="ak-content">
        <div className="ak-facts">
          <span className="ak-fact">
            <span aria-hidden="true">{GENDER_SYMBOL[g.gender]}</span>
            {genderLabel(g.gender)}
            {g.isCastrated ? ' (Kastrat)' : ''}
          </span>
          {g.dateOfBirth && (
            <span className="ak-fact">
              <span aria-hidden="true">🎂</span>
              {formatDate(g.dateOfBirth)}
            </span>
          )}
          {storedColorName && (
            <span className="ak-fact">
              <span aria-hidden="true">🎨</span>
              {storedColorName}
            </span>
          )}
          {isSiblingPairing && (
            <span className="ak-fact ak-fact--sibling" title={t.detail.siblingPairingTitle}>
              <span aria-hidden="true">⚭</span>
              {t.detail.siblingPairing}
            </span>
          )}
        </div>

        <div className="ak-actions">
          <Link to={`/rennmaeuse/${g.id}/bearbeiten`} className="ak-btn primary">
            {t.detail.edit}
          </Link>
          <Link to={`/genetik?parent=${g.id}`} className="ak-btn">
            {t.detail.testMating}
          </Link>
          <Link to={`/rennmaeuse/${g.id}/stammbaum`} className="ak-btn">
            {de.pages.stammbaum.openButton}
          </Link>
          {g.status !== 'ForSale' && g.status !== 'Deceased' && (
            <button
              type="button"
              className="ak-btn"
              disabled={forSale.pending}
              onClick={async () => {
                const r = await forSale.run()
                if (r.ok) {
                  toast.success(de.common.saved)
                  gerbil.reload()
                } else {
                  toast.error(r.error)
                }
              }}
            >
              {de.pages.abgabe.markAction}
            </button>
          )}
          {g.status !== 'Deceased' && g.status !== 'GivenAway' && (
            <Link to={`/vertraege/neu?tiere=${g.id}`} className="ak-btn">
              {de.pages.vertraege.wizard.title}
            </Link>
          )}
          <button type="button" className="ak-btn" onClick={() => setProvenanceOpen(true)}>
            {de.provenance.button}
          </button>
          <button type="button" className="ak-btn" onClick={() => setReportOpen(true)}>
            {de.feedback.button}
          </button>
          <Link to="/rennmaeuse" className="ak-btn">
            {t.detail.back}
          </Link>
        </div>

        {/* GEPRÜFTE TIERE: Prüfstatus & Schutz — laienverständlich erklärt. */}
        {(() => {
          const vt = de.verified
          const vs = verifiedStatus.data
          const isVerified = vs?.isVerified === true
          const isProtected = vs != null && vs.isVerified === false
          const drifted = vs?.status === 'drifted'
          const fieldLabel = (path: string) => vt.fieldLabels[path] ?? path
          const runVerify = async () => {
            const r = await verify.run()
            if (r.ok) { toast.success(vt.markSuccess); verifiedStatus.reload(); gerbil.reload() }
            else toast.error(r.error)
          }
          const runUnverify = async (confirmMsg: string) => {
            if (!window.confirm(confirmMsg)) return
            const r = await unverify.run()
            if (r.ok) { toast.success(vt.unmarkSuccess); verifiedStatus.reload(); gerbil.reload() }
            else toast.error(r.error)
          }
          return (
            <section className="ak-card">
              <h2 className="ak-h2">{vt.sectionTitle}</h2>
              <p className="ak-empty">{isProtected ? vt.explainProtected : vt.explainIntro}</p>
              <div className="ak-saverow">
                {!isVerified && (
                  <button
                    type="button"
                    className="ak-btn primary"
                    disabled={verify.pending}
                    onClick={runVerify}
                  >
                    {verify.pending ? vt.marking : vt.markAction}
                  </button>
                )}
                {isVerified && (
                  <button
                    type="button"
                    className="ak-btn"
                    disabled={unverify.pending}
                    onClick={() => runUnverify(vt.unmarkConfirm)}
                  >
                    {vt.unmarkAction}
                  </button>
                )}
                {isProtected && (
                  <button
                    type="button"
                    className="ak-btn"
                    disabled={unverify.pending}
                    onClick={() => runUnverify(vt.releaseConfirm)}
                  >
                    {vt.releaseAction}
                  </button>
                )}
              </div>
              {isVerified && !drifted && <p className="ak-empty">{vt.statusUnchanged}</p>}
              {isVerified && drifted && vs!.importDiff.length > 0 && (
                <>
                  <h3 className="ak-h2" style={{ fontSize: '1rem', marginTop: '0.8rem' }}>
                    {vt.driftHeading}
                  </h3>
                  <p className="ak-empty">{vt.driftHint}</p>
                  <dl className="ak-kvlist">
                    {vs!.importDiff.map((d) => (
                      <Kv key={d.path} label={fieldLabel(d.path)}>
                        <span>{d.goldenValue || '—'}</span>
                        <span className="muted"> → {vt.colImport}: {d.importValue || '—'}</span>
                      </Kv>
                    ))}
                  </dl>
                </>
              )}
            </section>
          )
        })()}

        <section className="ak-card">
          <h2 className="ak-h2">{t.detail.masterData}</h2>
          <dl className="ak-kvlist">
            <Kv label={t.fields.gender}>
              {genderLabel(g.gender)}
              {g.isCastrated && <span style={{ marginLeft: '0.4rem', opacity: 0.8 }}>(Kastrat)</span>}
            </Kv>
            <Kv label={t.fields.status}>{statusLabel(g.status)}</Kv>
            <Kv label={t.fields.dateOfBirth}>{formatDate(g.dateOfBirth)}</Kv>
            {g.status === 'Deceased' && (
              <>
                <Kv label={t.fields.dateOfDeath}>{formatDate(g.dateOfDeath)}</Kv>
                <Kv label={t.fields.causeOfDeath}>{g.causeOfDeath || '—'}</Kv>
              </>
            )}
            <Kv label={t.fields.colorVariety}>
              {storedColorName ? (
                <>
                  <FarbschlagImage name={storedColorName} size={22} />
                  {storedColorName}
                </>
              ) : (
                '—'
              )}
            </Kv>
            {/* Ticket 9f92c834 (CoCo): Scheckungsart bei jeder Schecke zeigen — auch wenn noch
                nicht erfasst (dann Platzhalter), damit sichtbar ist, dass es eine Schecke ist und
                welche Art. Schecke erkannt am Sp-Allel im Genotyp oder am Farbschlag-Namen. */}
            {(() => {
              const isSchecke =
                /Sp/.test(g.genotype ?? '') ||
                (storedColorName?.toLowerCase().includes('schecke') ?? false);
              if (!g.spottingType && !isSchecke) return null;
              return (
                <Kv label={t.fields.spottingType}>
                  {g.spottingType
                    ? de.pages.gerbils.spottingTypes[
                        g.spottingType as keyof typeof de.pages.gerbils.spottingTypes
                      ] || g.spottingType
                    : de.pages.gerbils.spottingTypes.notRecorded}
                </Kv>
              );
            })()}
            {showEnclosure && (
              <Kv label={t.fields.enclosure}>{lookup(enclosureName, g.enclosureId)}</Kv>
            )}
            {/* Ticket 7dedec07: Die „Wurf"-Zeile nur zeigen, wenn das Tier einen eigenen
                Geburtswurf in dieser Zucht hat. Zugekaufte/externe Zuchttiere (z. B. Blacky,
                litterId=null) sind nicht hier geboren → keine Wurf-Zeile. */}
            {g.litterId && (
              <Kv label={t.fields.litter}>
                {litterName.has(g.litterId) ? (
                  <Link to={`/wuerfe/${g.litterId}`}>{litterName.get(g.litterId)}</Link>
                ) : (
                  lookup(litterName, g.litterId)
                )}
              </Kv>
            )}
            {ownLitter && (
              <>
                <Kv label={t.detail.parentLittersRoleVater}>{parentLink(fatherId, father.data)}</Kv>
                <Kv label={t.detail.parentLittersRoleMutter}>{parentLink(motherId, mother.data)}</Kv>
              </>
            )}
            <Kv label={t.fields.origin}>
              {g.originContactId && contactName.has(g.originContactId) ? (
                <Link to={`/kontakte/${g.originContactId}`}>{contactName.get(g.originContactId)}</Link>
              ) : (
                g.originBreeder || '—'
              )}
            </Kv>
            {/* Ticket 24522f5f (JackJack): Das Abgabedatum gehört direkt unter den Abnehmer und
                darf NICHT am Status hängen — Tiere, die abgegeben wurden und später beim
                Abnehmer starben (status=Deceased), haben Abnehmer UND Abgabedatum. */}
            {(g.receiverContactId || g.goHomeDate || g.status !== 'Deceased') && (
              <>
                <Kv label={t.fields.receiver}>{lookup(contactName, g.receiverContactId)}</Kv>
                <Kv label={t.fields.goHomeDate}>{formatDate(g.goHomeDate)}</Kv>
              </>
            )}
            {g.isResident !== false && (partners.data?.items.length ?? 0) > 0 && (
              <Kv label={t.detail.zuchtpartner}>
                {/* Trennkomma HINTEN an den Namen, nicht vorne an den nächsten: .ak-kv-value
                    ist ein Flex-Container mit wrap, jeder Eintrag also ein eigenes Flex-Item.
                    Vorangestellt landete das Komma beim Umbruch am ZEILENANFANG („, Zora"). */}
                {(partners.data?.items ?? []).map((p, i, all) => (
                  <span key={p.id}>
                    <Link to={`/rennmaeuse/${p.id}`}>{p.name || de.pages.gerbils.nameless}</Link>
                    {i < all.length - 1 && ','}
                  </span>
                ))}
              </Kv>
            )}
            <Kv label={t.fields.notes}>{g.notes || '—'}</Kv>
          </dl>
        </section>

        <GerbilAcquisitionSection gerbilId={g.id} />

        <section className="ak-card">
          <h2 className="ak-h2">{t.detail.genetics}</h2>
          {geno ? (
            <dl className="ak-kvlist">
              <Kv label={t.fields.genotype}>
                <code className="ak-genotype">{geno.display}</code>
                {genoInferred && (
                  <span className="ak-inferred" title={t.detail.genotypeInferredTitle}>
                    {' → '}
                    <code className="ak-genotype">{genoInferred.display}</code>{' '}
                    <small className="ak-inferred-chip">⮑ {t.detail.genotypeInferred}</small>
                  </span>
                )}
              </Kv>
              <Kv label={t.detail.resolvedPrefix}>
                {(() => {
                  const resolvedFarbschlag = (genoInferred ?? geno).farbschlag
                  return (
                    <>
                      {resolvedFarbschlag}
                      {/* Vergleich OHNE die Modifier-Zusaetze auf BEIDEN Seiten: der
                          eingetragene Name traegt „Schecke"/„Rex" bereits (formatVarietyName
                          haengt sie aus dem Gencode an), der errechnete ebenfalls. Vorher wurde
                          der Zusatz nur rechts entfernt → jede Schecke bekam faelschlich den
                          Hinweis „Weicht vom eingetragenen Farbschlag ab" (z. B. JackJack:
                          „Saphir Schecke" vs. „Saphir Schecke"). */}
                      {storedColorName &&
                        resolvedFarbschlag !== de.genetics.unknownFarbschlag &&
                        stripVarietyModifiers(storedColorName) !==
                          stripVarietyModifiers(resolvedFarbschlag) && (
                          <small className="ak-mismatch"> ⚠ {t.detail.farbschlagMismatch}</small>
                        )}
                    </>
                  )
                })()}
              </Kv>
            </dl>
          ) : (
            <p className="ak-empty">{t.detail.genotypeNotSet}</p>
          )}
        </section>

        {/* Externe Vorfahren waren nie im eigenen Bestand → Würfe & Charakter
            sind für sie nicht relevant; statt der Abschnitte ein kurzer Hinweis. */}
        {g.isResident === false && (
          <section className="ak-card">
            <p className="ak-empty">{t.detail.nonResidentNote}</p>
            {(offspring.data?.items.length ?? 0) > 0 && (
              <p className="ak-empty">
                {t.detail.nonResidentOffspringLabel}{' '}
                {(offspring.data?.items ?? []).map((child, i, all) => (
                  <span key={child.id}>
                    <Link to={`/rennmaeuse/${child.id}`}>
                      {child.name || de.pages.gerbils.nameless}
                    </Link>
                    {i < all.length - 1 && ','}
                  </span>
                ))}
              </p>
            )}
          </section>
        )}

        {g.isResident !== false && (
        <section className="ak-card">
          <button
            type="button"
            className="ak-card-toggle"
            aria-expanded={charExpanded}
            onClick={() => setCharExpanded((v) => !v)}
          >
            <h2 className="ak-h2">{de.character.sectionTitle}</h2>
            <span className="ak-card-chev" aria-hidden="true">
              {charExpanded ? '▴' : '▾'}
            </span>
          </button>
          {charExpanded && (
            <>
              {TRAIT_CATEGORIES.map((cat) => {
                const count = cat.traits.filter((tr) => selectedTraits.has(tr.key)).length
                return (
                  <div className="ak-cgroup" key={cat.category}>
                <div className="ak-glabel">
                  {cat.category}
                  {count > 0 && <span className="ak-gcount">{count}</span>}
                </div>
                <div className="ak-chips">
                  {cat.traits.map((tr) => {
                    const on = selectedTraits.has(tr.key)
                    return (
                      <button
                        key={tr.key}
                        type="button"
                        className={'ak-chip' + (on ? ' on' : '') + (tr.warn ? ' warn' : '')}
                        aria-pressed={on}
                        onClick={() => toggleTrait(tr.key)}
                      >
                        {tr.warn && <span aria-hidden="true">⚠</span>}
                        {tr.label}
                      </button>
                    )
                  })}
                </div>
              </div>
            )
          })}
          <textarea
            className="ak-notes"
            value={charNote}
            placeholder={de.character.notePlaceholder}
            onChange={(e) => setCharNote(e.target.value)}
          />
          <div className="ak-saverow">
            <button
              type="button"
              className="ak-btn primary"
              disabled={saveCharacter.pending}
              onClick={async () => {
                const r = await saveCharacter.run()
                if (r.ok) {
                  toast.success(de.common.saved)
                  gerbil.reload()
                } else {
                  toast.error(r.error)
                }
              }}
            >
              {saveCharacter.pending ? t.form.saving : de.character.save}
            </button>
            {saveCharacter.error && <span className="error-text">{saveCharacter.error}</span>}
              </div>
            </>
          )}
        </section>
        )}

        {g.isResident !== false && (
        <section className="ak-card">
          <h2 className="ak-h2">{t.detail.parentLittersTitle}</h2>
          {parentLitters.loading && <p className="muted">{de.common.loading}</p>}
          {!parentLitters.loading && (parentLitters.data?.items.length ?? 0) === 0 && (
            <p className="ak-empty">{t.detail.parentLittersEmpty}</p>
          )}
          {(parentLitters.data?.items.length ?? 0) > 0 && (
            <ul className="card-list">
              {(parentLitters.data?.items ?? []).map((litter) => (
                <li key={litter.id}>
                  <Link to={`/wuerfe/${litter.id}`} className="gerbil-card">
                    <span className="gerbil-card__name">{litter.name}</span>
                    <span className="badge badge--active">
                      {litter.fatherId === id
                        ? t.detail.parentLittersRoleVater
                        : t.detail.parentLittersRoleMutter}
                    </span>
                    <span className="gerbil-card__meta">{formatDate(litter.date)}</span>
                    {litter.totalBorn !== null && (
                      <span className="gerbil-card__meta">
                        {litter.totalBorn} {de.pages.litters.countLabel}
                      </span>
                    )}
                    {litter.showInChronicle === false && (
                      <span className="gerbil-card__meta muted">
                        {t.detail.parentLittersNotInChronicle}
                      </span>
                    )}
                  </Link>
                </li>
              ))}
            </ul>
          )}
        </section>
        )}

        {g.isResident !== false && (parentLitters.data?.items.length ?? 0) > 0 && (
        <section className="ak-card">
          <h2 className="ak-h2">{t.detail.offspringInBreedingTitle}</h2>
          {offspring.loading && <p className="muted">{de.common.loading}</p>}
          {!offspring.loading && (breedingOffspring.length === 0) && (
            <p className="ak-empty">{t.detail.offspringInBreedingEmpty}</p>
          )}
          {breedingOffspring.length > 0 && (
            <ul className="card-list">
              {breedingOffspring.map((child) => {
                const childLitter = (parentLitters.data?.items ?? []).find(l => l.id === child.litterId);
                const suffix = child.originBreeder ? ` (${child.originBreeder})` : '';
                return (
                  <li key={child.id}>
                    <Link to={`/rennmaeuse/${child.id}`} className="gerbil-card">
                      <span className="gerbil-card__name">{child.name || de.pages.gerbils.nameless}</span>
                      <span className="badge badge--active">
                        {statusLabel(child.status)}
                      </span>
                      {childLitter && (
                        <span className="gerbil-card__meta">
                          {childLitter.name}
                        </span>
                      )}
                      <span className="gerbil-card__meta muted">
                        {child.gender === 'male' ? 'Bock' : child.gender === 'female' ? 'Weibchen' : 'Unbekannt'}{suffix}
                      </span>
                    </Link>
                  </li>
                );
              })}
            </ul>
          )}
        </section>
        )}

        <section className="ak-card">
          <h2 className="visually-hidden">{t.detail.moreData}</h2>
          <div className="ak-tabs" role="tablist">
            {(['photos', 'health', 'weight', 'exhibitions'] as const).map((key) => (
              <button
                key={key}
                type="button"
                role="tab"
                aria-selected={tab === key}
                className={tab === key ? 'ak-tab active' : 'ak-tab'}
                onClick={() => setTab(key)}
              >
                {t.detail.tabs[key]}
              </button>
            ))}
          </div>
          <div className="ak-tabpanel" role="tabpanel">
            {tab === 'photos' && <GerbilPhotosTab gerbilId={g.id} />}
            {tab === 'health' && <GerbilHealthTab gerbilId={g.id} />}
            {tab === 'weight' && <GerbilWeightTab gerbilId={g.id} />}
            {tab === 'exhibitions' && (
              <GerbilExhibitionsTab
                gerbilId={g.id}
                entityName={gerbilName(g) || de.pages.gerbils.nameless}
              />
            )}
          </div>
        </section>
      </div>

      <ReportErrorDialog
        open={reportOpen}
        onClose={() => setReportOpen(false)}
        context={{ context: 'gerbil-detail', gerbilId: g.id, entityName: g.name || de.pages.gerbils.nameless }}
      />

      <ProvenanceDialog
        open={provenanceOpen}
        onClose={() => setProvenanceOpen(false)}
        provenance={g.provenance}
      />
    </section>
  )
}
