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

export interface ReapproInput {
  target: string;
  qty: number;
  repro: Readonly<Record<string, number>>;
  inverted: Readonly<Record<string, boolean>>;
}

export interface ReapproStep {
  race: string;
  gen: number;
  qty: number;
  couples: number;
  parentA: string;
  parentB: string;
  repro: number;
}

export interface Gen1Need {
  name: string;
  total: number;
  m: number;
  f: number;
}

export interface ReapproResult {
  steps: readonly ReapproStep[];
  gen1Needs: readonly Gen1Need[];
  totalGen1: number;
}

export class ReapproCalculator {
  compute(input: ReapproInput): ReapproResult {
    const { target, qty, repro, inverted } = input;
    if (!target || !BREEDING_RECIPES[target]) return { steps: [], gen1Needs: [], totalGen1: 0 };

    const needs: Record<string, { total: number; m: number; f: number }> = {};
    needs[target] = { total: qty, m: 0, f: 0 };
    const steps: ReapproStep[] = [];
    const processed = new Set<string>();
    const targetGen = RACE_GEN[target] ?? 2;

    for (let gen = targetGen; gen >= 2; gen--) {
      const racesAtGen = Object.keys(needs).filter(
        r => !processed.has(r) && (RACE_GEN[r] ?? 0) === gen && !!BREEDING_RECIPES[r]
      );
      for (const race of racesAtGen) {
        const Q = needs[race]!.total;
        if (Q <= 0) { processed.add(race); continue; }
        const R = repro[race] ?? 0;
        const couplesReal = (2 * R >= Q) ? Math.ceil(Q / 2) : (R > 0 ? Q - R : Q);

        const isInv = inverted[race] ?? false;
        const [rawA, rawB] = BREEDING_RECIPES[race]!;
        const a = isInv ? rawB : rawA;
        const b = isInv ? rawA : rawB;

        if (!needs[a]) needs[a] = { total: 0, m: 0, f: 0 };
        if (!needs[b]) needs[b] = { total: 0, m: 0, f: 0 };
        needs[a]!.total += couplesReal;
        needs[a]!.m += couplesReal;
        needs[b]!.total += couplesReal;
        needs[b]!.f += couplesReal;

        steps.push({ race, gen, qty: Q, couples: couplesReal, parentA: a, parentB: b, repro: R });
        processed.add(race);
      }
    }

    const gen1Needs: Gen1Need[] = Object.entries(needs)
      .filter(([n]) => !BREEDING_RECIPES[n] && needs[n]!.total > 0)
      .sort((a, b) => b[1].total - a[1].total)
      .map(([name, d]) => ({ name, total: d.total, m: d.m, f: d.f }));

    const totalGen1 = gen1Needs.reduce((s, n) => s + n.total, 0);

    return { steps, gen1Needs, totalGen1 };
  }
}
