File size: 3,764 Bytes
1a343cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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<string, number>, 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<string, number> = {};
  const byType: Record<string, number> = {};
  const byGenerationRaw: Record<string, number> = {};
  const byBudFamily: Record<string, number> = {};

  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<string, number>): Record<string, number> {
  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;
}