import { germplasmRecords } from './lab'; import type { DeckSummary, GermplasmRecord, Rgb, SeedProfile } from './types'; function mean(values: unknown[]): number { const numeric = values.filter((value): value is number => typeof value === 'number' && Number.isFinite(value)); return numeric.length ? Math.round((numeric.reduce((sum, value) => sum + value, 0) / numeric.length) * 10) / 10 : 0; } function increment(target: Record, key: string | number): void { const normalized = String(key); target[normalized] = (target[normalized] ?? 0) + 1; } export function deckSummary(seeds: SeedProfile[]): DeckSummary { const records = germplasmRecords(seeds); const byStage: Record = {}; const byType: Record = {}; const byGenerationRaw: Record = {}; const byBudFamily: Record = {}; for (const record of records) { increment(byStage, record.stage); increment(byType, record.germplasmType); increment(byGenerationRaw, record.generation); increment(byBudFamily, record.budFamily); } const breedable = records.filter((record) => record.canAttempt && record.stage === 'MATURE'); const growing = records.filter((record) => record.stage !== 'MATURE'); const crosses = records.filter((record) => record.parents.every(Boolean)); const recentCrosses = crosses .slice(-6) .reverse() .map((record) => ({ id: record.germplasmDbId, name: record.germplasmName, generation: record.generation, pedigree: record.pedigree, budColor: record.budColor as Rgb, leafColor: record.leafColor as Rgb, THC: record.THC, })); const generationEntries = Object.entries(byGenerationRaw) .map(([generation, count]) => [`F${generation}`, count] as const) .sort(([left], [right]) => left.localeCompare(right)); const topBloom = [...records] .sort((left, right) => right.Bloom - left.Bloom) .slice(0, 6) .map((record) => ({ id: record.germplasmDbId, name: record.germplasmName, generation: record.generation, pedigree: record.pedigree, budColor: record.budColor, leafColor: record.leafColor, budPalette: record.budPalette, Bloom: record.Bloom, Volatility: record.Volatility, budPattern: record.budPattern, colorCount: record.budBloom.colorCount, hueSpread: record.budBloom.hueSpread, THC: record.THC, })); return { accessions: records.length, byStage, byType: sortRecord(byType), byGeneration: Object.fromEntries(generationEntries), byBudFamily: sortRecord(byBudFamily), maxGeneration: maxGeneration(records), breedableCount: breedable.length, growingCount: growing.length, traitAverages: { THC: mean(records.map((record) => record.THC)), CBD: mean(records.map((record) => record.CBD)), Yield: mean(records.map((record) => record.Yield)), GrowTime: mean(records.map((record) => record.GrowTime)), Stability: mean(records.map((record) => record.Stability)), Volatility: mean(records.map((record) => record.Volatility)), Bloom: mean(records.map((record) => record.Bloom)), }, gamut: records.map((record) => record.budColor), recentCrosses, topBloom, breedable: breedable.map((record) => ({ id: record.germplasmDbId, name: record.germplasmName, })), }; } function sortRecord(record: Record): Record { return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right))); } function maxGeneration(records: GermplasmRecord[]): number { return records.length ? Math.max(...records.map((record) => record.generation)) : 0; }