import { describe, it, expect } from 'vitest';
import {
  computePactMultiplier,
  computePactInsightMultiplier,
} from '../utils/pact-utils';
import { getGuardianForFloor } from '../data/guardian-encounters';
// Helper: compute actual multiplier values
function getDamageMult(mult: number, extraPacts: number, mitigation: number): number {
  const numAdditional = extraPacts;
  const basePenalty = 0.5 * numAdditional;
  const mitigationReduction = Math.min(mitigation, 5) * 0.1;
  const effectivePenalty = Math.max(0, basePenalty - mitigationReduction);
  
  if (mitigation >= 5) {
    const synergyBonus = (mitigation - 5) * 0.1;
    return mult * (1 + synergyBonus);
  }
  
  return mult * (1 - effectivePenalty);
}

// Apply the actual calculation to test values
function _computeTestResult( multipliers: number[], extraPacts: number, mitigation: number): number {
  const baseMult = multipliers.reduce((a, b) => a * b, 1);
  return getDamageMult(baseMult, extraPacts, mitigation);
}

// ─── computePactMultiplier ────────────────────────────────────────────────────

describe('computePactMultiplier', () => {
  it('should return 1.0 with no signed pacts', () => {
    const result = computePactMultiplier({ signedPacts: [] });
    expect(result).toBe(1.0);
  });

  it('should apply penalty for multiple non-guardian floors', () => {
    // Non-guardian floors don't have GUARDIANS entries
    // With 3 pacts: numAdditional = 2, penalty = 1.0, result = 1 * (1 - 1) = 0
    const result = computePactMultiplier({ signedPacts: [5, 15, 25] });
    expect(result).toBe(0);
  });

  it('should return guardian damage multiplier for a single guardian pact', () => {
    const floor10 = getGuardianForFloor(10)!;
    const result = computePactMultiplier({ signedPacts: [10] });
    expect(result).toBe(floor10.damageMultiplier);
  });

  it('should multiply damage multipliers for multiple guardian pacts', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const result = computePactMultiplier({ signedPacts: [10, 20] });
    // With 2 pacts: baseMult = f10 * f20, then penalty = 0.5 * 1 = 0.5
    // effectivePenalty = max(0, 0.5 - 0) = 0.5
    // result = baseMult * (1 - 0.5) = baseMult * 0.5
    const expected = floor10.damageMultiplier * floor20.damageMultiplier * 0.5;
    expect(result).toBe(expected);
  });

  it('should apply interference mitigation to reduce penalty', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const baseMult = floor10.damageMultiplier * floor20.damageMultiplier;

    // No mitigation: penalty = 0.5, result = baseMult * 0.5
    const noMitigation = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 0,
    });

    // Full mitigation (5): penalty = max(0, 0.5 - 0.5) = 0, result = baseMult
    const fullMitigation = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 5,
    });

    expect(fullMitigation).toBeGreaterThan(noMitigation);
    expect(fullMitigation).toBe(baseMult);
  });

  it('should apply synergy bonus when mitigation exceeds 5', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const baseMult = floor10.damageMultiplier * floor20.damageMultiplier;

    // mitigation = 6: synergyBonus = (6-5)*0.1 = 0.1, result = baseMult * 1.1
    const result = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 6,
    });
    expect(result).toBe(baseMult * 1.1);
  });

  it('should scale synergy bonus with higher mitigation', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const baseMult = floor10.damageMultiplier * floor20.damageMultiplier;

    const mit5 = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 5,
    });
    const mit7 = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 7,
    });
    const mit10 = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 10,
    });

    expect(mit5).toBe(baseMult); // no penalty, no bonus
    expect(mit7).toBe(baseMult * 1.2); // synergy = 0.2
    expect(mit10).toBe(baseMult * 1.5); // synergy = 0.5
  });

  it('should handle three pacts with penalty', () => {
    const _floor10 = getGuardianForFloor(10)!;
    const _floor20 = getGuardianForFloor(20)!;
    const _floor30 = getGuardianForFloor(30)!;

    // 3 pacts: numAdditional = 2, basePenalty = 1.0, effectivePenalty = 1.0
    // result = baseMult * (1 - 1.0) = 0
    const result = computePactMultiplier({
      signedPacts: [10, 20, 30],
      pactInterferenceMitigation: 0,
    });
    expect(result).toBe(0);
  });

  it('should handle three pacts with partial mitigation', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const floor30 = getGuardianForFloor(30)!;
    const baseMult = floor10.damageMultiplier * floor20.damageMultiplier * floor30.damageMultiplier;

    // 3 pacts: numAdditional = 2, basePenalty = 1.0
    // mitigation = 3: reduction = 0.3, effectivePenalty = 0.7
    const result = computePactMultiplier({
      signedPacts: [10, 20, 30],
      pactInterferenceMitigation: 3,
    });
    // Use toBeCloseTo for floating point comparison
    expect(result).toBeCloseTo(baseMult * 0.3, 10);
  });

  it('should handle mix of guardian and non-guardian floors', () => {
    const floor10 = getGuardianForFloor(10)!;
    // Non-guardian floors contribute nothing (no entry in GUARDIANS)
    const result = computePactMultiplier({ signedPacts: [5, 10] });
    // Only floor 10 counts: baseMult = floor10.damageMultiplier
    // 2 pacts but only 1 guardian: baseMult = f10.damageMultiplier
    // numAdditional = 1, penalty = 0.5
    expect(result).toBe(floor10.damageMultiplier * 0.5);
  });

  it('should default pactInterferenceMitigation to 0', () => {
    const withDefault = computePactMultiplier({ signedPacts: [10, 20] });
    const withZero = computePactMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 0,
    });
    expect(withDefault).toBe(withZero);
  });
});

// ─── computePactInsightMultiplier ─────────────────────────────────────────────

describe('computePactInsightMultiplier', () => {
  it('should return 1.0 with no signed pacts', () => {
    const result = computePactInsightMultiplier({ signedPacts: [] });
    expect(result).toBe(1.0);
  });

  it('should apply penalty for multiple non-guardian floors', () => {
    // Non-guardian floors don't have GUARDIANS entries
    // With 3 pacts: numAdditional = 2, penalty = 1.0, result = 1 * (1 - 1) = 0
    const result = computePactInsightMultiplier({ signedPacts: [5, 15, 25] });
    expect(result).toBe(0);
  });

  it('should return guardian insight multiplier for a single guardian pact', () => {
    const floor10 = getGuardianForFloor(10)!;
    const result = computePactInsightMultiplier({ signedPacts: [10] });
    expect(result).toBe(floor10.insightMultiplier);
  });

  it('should multiply insight multipliers for multiple guardian pacts', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const result = computePactInsightMultiplier({ signedPacts: [10, 20] });
    const expected = floor10.insightMultiplier * floor20.insightMultiplier * 0.5;
    expect(result).toBe(expected);
  });

  it('should apply interference mitigation to reduce penalty', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const baseMult = floor10.insightMultiplier * floor20.insightMultiplier;

    const noMitigation = computePactInsightMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 0,
    });
    const fullMitigation = computePactInsightMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 5,
    });

    expect(fullMitigation).toBeGreaterThan(noMitigation);
    expect(fullMitigation).toBe(baseMult);
  });

  it('should apply synergy bonus when mitigation exceeds 5', () => {
    const floor10 = getGuardianForFloor(10)!;
    const floor20 = getGuardianForFloor(20)!;
    const baseMult = floor10.insightMultiplier * floor20.insightMultiplier;

    const result = computePactInsightMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 8,
    });
    // synergyBonus = (8-5)*0.1 = 0.3
    expect(result).toBe(baseMult * 1.3);
  });

  it('should handle three pacts with full penalty', () => {
    const _floor10 = getGuardianForFloor(10)!;
    const _floor20 = getGuardianForFloor(20)!;
    const _floor30 = getGuardianForFloor(30)!;

    const result = computePactInsightMultiplier({
      signedPacts: [10, 20, 30],
      pactInterferenceMitigation: 0,
    });
    // 3 pacts: numAdditional = 2, basePenalty = 1.0, effectivePenalty = 1.0
    // result = baseMult * (1 - 1.0) = 0
    expect(result).toBe(0);
  });

  it('should default pactInterferenceMitigation to 0', () => {
    const withDefault = computePactInsightMultiplier({ signedPacts: [10, 20] });
    const withZero = computePactInsightMultiplier({
      signedPacts: [10, 20],
      pactInterferenceMitigation: 0,
    });
    expect(withDefault).toBe(withZero);
  });
});
