import { RACES_DATA, BREEDING_RECIPES } from '@domain/value-objects/Race';

export interface SimulationCrossing {
  parentA: string;
  parentB: string;
  baby: string;
  gen: number;
  count: number;
  pAMale: number;
  pAFemale: number;
  pBMale: number;
  pBFemale: number;
}

export interface SimulationResult {
  crossings: SimulationCrossing[];
  unusedStock: { race: string; m: number; f: number }[];
}

/**
 * Simule tous les croisements possibles depuis un inventaire en stock.
 *
 * Algorithme d'allocation proportionnelle dynamique :
 * Pour chaque croisement à une génération donnée, le stock de chaque parent
 * est divisé équitablement par le nombre de croisements restants qui utilisent
 * encore ce parent. Cela évite qu'un premier croisement épuise tout le stock
 * et prive les suivants (ex. : 3 races Gen2 partagent les mêmes parents de base).
 *
 * Les deux configurations sont utilisées simultanément :
 *   c1 = min(♂A_alloué, ♀B_alloué)   → ♂A × ♀B
 *   c2 = min(♀A_allouée, ♂B_alloué)  → ♀A × ♂B
 *   bred = c1 + c2
 */
export function simulateStock(
  inventaire: Readonly<Record<string, { m: number; f: number }>>,
): SimulationResult {
  const stock: Record<string, { m: number; f: number }> = {};
  for (const [race, entry] of Object.entries(inventaire)) {
    if (entry.m > 0 || entry.f > 0) stock[race] = { m: entry.m, f: entry.f };
  }

  const crossings: SimulationCrossing[] = [];

  for (let g = 2; g <= 10; g++) {
    const racesAtGen = RACES_DATA[g];
    if (!racesAtGen) continue;

    // Crossings possibles à cette génération (les deux parents ont du stock)
    const genCrossings: { baby: string; parentA: string; parentB: string }[] = [];
    for (const raceData of racesAtGen) {
      const recipe = BREEDING_RECIPES[raceData.name];
      if (!recipe) continue;
      const [parentA, parentB] = recipe;
      const sA = stock[parentA];
      const sB = stock[parentB];
      if (!sA || !sB || sA.m + sA.f <= 0 || sB.m + sB.f <= 0) continue;
      genCrossings.push({ baby: raceData.name, parentA, parentB });
    }

    for (let i = 0; i < genCrossings.length; i++) {
      const { baby, parentA, parentB } = genCrossings[i]!;
      const sA = stock[parentA];
      const sB = stock[parentB];
      if (!sA || !sB || sA.m + sA.f <= 0 || sB.m + sB.f <= 0) continue;

      // Croisements restants dont les deux parents ont encore du stock
      const remaining = genCrossings.slice(i).filter(c => {
        const a = stock[c.parentA];
        const b = stock[c.parentB];
        return a && b && a.m + a.f > 0 && b.m + b.f > 0;
      });

      const countA = remaining.filter(c => c.parentA === parentA || c.parentB === parentA).length;
      const countB = remaining.filter(c => c.parentA === parentB || c.parentB === parentB).length;

      const allocAm = Math.floor(sA.m / countA);
      const allocAf = Math.floor(sA.f / countA);
      const allocBm = Math.floor(sB.m / countB);
      const allocBf = Math.floor(sB.f / countB);

      const c1 = Math.min(allocAm, allocBf); // ♂A × ♀B
      const c2 = Math.min(allocAf, allocBm); // ♀A × ♂B
      const bred = c1 + c2;

      if (bred > 0) {
        sA.m -= c1; sB.f -= c1;
        sA.f -= c2; sB.m -= c2;

        crossings.push({
          parentA, parentB, baby, gen: g, count: bred,
          pAMale: c1, pAFemale: c2,
          pBMale: c2, pBFemale: c1,
        });

        if (!stock[baby]) stock[baby] = { m: 0, f: 0 };
        const halfM = Math.ceil(bred / 2);
        stock[baby].m += halfM;
        stock[baby].f += bred - halfM;
      }
    }
  }

  const unusedStock = Object.entries(stock)
    .filter(([, s]) => s.m > 0 || s.f > 0)
    .map(([race, s]) => ({ race, m: s.m, f: s.f }));

  return { crossings, unusedStock };
}
