/** FEAT-7: Tests der Statistik-Aggregationen (reine Daten, kein DOM). */
import { describe, expect, it } from 'vitest'
import type { Gerbil, GerbilStatus, Litter } from '../../api/types'
import {
  avgLitterSizePerYear,
  farbschlagDistribution,
  littersPerYear,
  lossesPerYear,
  populationOverTime,
} from '../aggregate'

function makeLitter(date: string, totalBorn: number | null = null): Litter {
  return {
    id: `l-${date}-${Math.abs(totalBorn ?? 0)}-${counter++}`,
    name: 'Wurf',
    date,
    totalBorn,
    expectedGoHomeDate: null,
    notes: null,
    fatherId: null,
    motherId: null,
  }
}
let counter = 0

function makeGerbil(over: Partial<Gerbil> & { id: string }): Gerbil {
  return {
    name: over.id,
    gender: 'unknown',
    status: 'Active' as GerbilStatus,
    dateOfBirth: null,
    dateOfDeath: null,
    causeOfDeath: null,
    goHomeDate: null,
    litterId: null,
    enclosureId: null,
    colorVarietyId: null,
    originContactId: null,
    receiverContactId: null,
    genotype: null,
    notes: null,
    ...over,
  }
}

describe('littersPerYear', () => {
  it('zählt pro Jahr und füllt Lücken mit 0', () => {
    const result = littersPerYear([
      makeLitter('2021-03-01'),
      makeLitter('2021-09-10'),
      makeLitter('2023-01-05'),
    ])
    expect(result).toEqual([
      { year: 2021, value: 2 },
      { year: 2022, value: 0 },
      { year: 2023, value: 1 },
    ])
  })

  it('leere Eingabe → leere Reihe', () => {
    expect(littersPerYear([])).toEqual([])
  })
})

describe('avgLitterSizePerYear', () => {
  it('mittelt nur Würfe mit erfasster Wurfstärke und lässt Jahre ohne Daten aus', () => {
    const result = avgLitterSizePerYear([
      makeLitter('2021-01-01', 4),
      makeLitter('2021-06-01', 6),
      makeLitter('2022-01-01', null), // zählt nicht
      makeLitter('2023-01-01', 5),
    ])
    expect(result).toEqual([
      { year: 2021, value: 5 },
      { year: 2023, value: 5 }, // 2022 fehlt bewusst (kein 0-Durchschnitt)
    ])
  })
})

describe('farbschlagDistribution', () => {
  it('zählt nur aktive Tiere, sortiert absteigend, null-Eimer zuletzt', () => {
    const gerbils = [
      makeGerbil({ id: 'a', colorVarietyId: 'Schwarz' }),
      makeGerbil({ id: 'b', colorVarietyId: 'Schwarz' }),
      makeGerbil({ id: 'c', colorVarietyId: 'Agouti' }),
      makeGerbil({ id: 'd', colorVarietyId: null }),
      makeGerbil({ id: 'e', colorVarietyId: 'Gold', status: 'Deceased' }), // inaktiv
    ]
    const result = farbschlagDistribution(gerbils, (g) => g.colorVarietyId)
    expect(result).toEqual([
      { name: 'Schwarz', count: 2 },
      { name: 'Agouti', count: 1 },
      { name: null, count: 1 },
    ])
  })

  it('sortiert bei Gleichstand alphabetisch (de)', () => {
    const gerbils = [
      makeGerbil({ id: 'a', colorVarietyId: 'Zobel' }),
      makeGerbil({ id: 'b', colorVarietyId: 'Ägypter' }),
    ]
    const names = farbschlagDistribution(gerbils, (g) => g.colorVarietyId).map((e) => e.name)
    expect(names).toEqual(['Ägypter', 'Zobel'])
  })
})

describe('populationOverTime', () => {
  it('bildet Geburt/Tod/Abgabe als Bestandskurve mit Monatsabtastung ab', () => {
    const gerbils = [
      makeGerbil({ id: 'a', dateOfBirth: '2024-01-15' }),
      makeGerbil({ id: 'b', dateOfBirth: '2024-02-20' }),
      makeGerbil({
        id: 'c',
        dateOfBirth: '2024-01-20',
        status: 'Deceased',
        dateOfDeath: '2024-03-10',
      }),
      makeGerbil({
        id: 'd',
        dateOfBirth: '2024-02-01',
        status: 'GivenAway',
        goHomeDate: '2024-04-05',
      }),
    ]
    const points = populationOverTime(gerbils, '2024-04-15')
    expect(points).toEqual([
      { date: '2024-01-01', value: 0 }, // vor allen Ereignissen
      { date: '2024-02-01', value: 3 }, // a, c geboren + d (Geburt genau am Stichtag zählt mit)
      { date: '2024-03-01', value: 4 },
      { date: '2024-04-01', value: 3 }, // c verstorben am 10.03.
      { date: '2024-04-15', value: 2 }, // d abgegeben am 05.04.
    ])
  })

  it('Tiere ohne Geburtsdatum werden übersprungen; leer → []', () => {
    expect(populationOverTime([makeGerbil({ id: 'x' })], '2024-01-01')).toEqual([])
    expect(populationOverTime([], '2024-01-01')).toEqual([])
  })

  it('Endpunkt heute wird nicht doppelt erzeugt, wenn heute ein Monatsanfang ist', () => {
    const gerbils = [makeGerbil({ id: 'a', dateOfBirth: '2024-01-15' })]
    const points = populationOverTime(gerbils, '2024-03-01')
    expect(points[points.length - 1]).toEqual({ date: '2024-03-01', value: 1 })
    expect(points.filter((p) => p.date === '2024-03-01')).toHaveLength(1)
  })
})

describe('lossesPerYear', () => {
  it('zählt Todesfälle pro Jahr (nur Status Verstorben, mit Todesdatum)', () => {
    const gerbils = [
      makeGerbil({ id: 'a', status: 'Deceased', dateOfDeath: '2021-05-01' }),
      makeGerbil({ id: 'b', status: 'Deceased', dateOfDeath: '2023-02-02' }),
      makeGerbil({ id: 'c', status: 'Deceased', dateOfDeath: null }), // ohne Datum: nicht zuordenbar
      makeGerbil({ id: 'd', status: 'GivenAway', goHomeDate: '2022-01-01' }), // kein Todesfall
    ]
    expect(lossesPerYear(gerbils)).toEqual([
      { year: 2021, value: 1 },
      { year: 2022, value: 0 },
      { year: 2023, value: 1 },
    ])
  })
})
