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

export interface Stock { m: number; f: number; n: number; }
export interface CrossingDetail { aSex: string; bSex: string; }
export interface CrossingResult { name: string; qty: number; parents: readonly [string, string]; gen: number; details: CrossingDetail[]; }
export interface GenerationResult { gen: number; crossings: CrossingResult[]; }
export interface InventaireResult { generations: GenerationResult[]; remaining: Record<string, Stock>; }

export class InventaireCalculator {
  compute(inventaire: Readonly<Record<string, { m: number; f: number }>>): InventaireResult {
    const avail: Record<string, Stock> = {};
    for (const [k, v] of Object.entries(inventaire)) {
      if ((v.m + v.f) > 0) avail[k] = { m: v.m, f: v.f, n: 0 };
    }

    if (Object.keys(avail).length === 0) return { generations: [], remaining: {} };

    const hasMale = (s: Stock) => s.m > 0 || s.n > 0;
    const hasFemale = (s: Stock) => s.f > 0 || s.n > 0;
    const takeMale = (s: Stock) => { if (s.m > 0) s.m--; else s.n--; };
    const takeFemale = (s: Stock) => { if (s.f > 0) s.f--; else s.n--; };
    const totalOf = (s: Stock) => s.m + s.f + s.n;

    const generations: GenerationResult[] = [];

    for (let gen = 2; gen <= 10; gen++) {
      const crossingsAtGen = Object.entries(BREEDING_RECIPES)
        .filter(([name]) => (RACE_GEN[name] ?? 0) === gen)
        .map(([name, parents]) => ({ name, parents }));

      const genResults: CrossingResult[] = [];
      let more = true;
      while (more) {
        more = false;
        for (const cr of crossingsAtGen) {
          const [a, b] = cr.parents;
          const sa = avail[a] ?? { m: 0, f: 0, n: 0 };
          const sb = avail[b] ?? { m: 0, f: 0, n: 0 };
          let ok = false, aSex = '', bSex = '';

          if (a === b) {
            if (totalOf(sa) >= 2 && hasMale(sa) && hasFemale(sa)) {
              takeMale(sa); takeFemale(sa); aSex = '\u2642'; bSex = '\u2640'; ok = true;
            }
          } else if (hasMale(sa) && hasFemale(sb)) {
            takeMale(sa); takeFemale(sb); aSex = '\u2642'; bSex = '\u2640'; ok = true;
          } else if (hasFemale(sa) && hasMale(sb)) {
            takeFemale(sa); takeMale(sb); aSex = '\u2640'; bSex = '\u2642'; ok = true;
          }

          if (ok) {
            if (!avail[a]) avail[a] = sa;
            if (!avail[b]) avail[b] = sb;
            if (!avail[cr.name]) avail[cr.name] = { m: 0, f: 0, n: 0 };
            avail[cr.name]!.n++;
            let entry = genResults.find(r => r.name === cr.name);
            if (!entry) { entry = { name: cr.name, qty: 0, parents: cr.parents as [string, string], gen, details: [] }; genResults.push(entry); }
            entry.qty++;
            entry.details.push({ aSex, bSex });
            more = true;
          }
        }
      }
      if (genResults.length > 0) generations.push({ gen, crossings: genResults });
    }

    return { generations, remaining: avail };
  }
}
