Skip to content
import { assertEquals } from "jsr:@std/assert@^1.0.14";
import {
  criticalChance,
  initialProgression,
  isValidProgression,
  maxEnergy,
  maxVigor,
  parseProgression,
  progressionChange,
  progressionPoints,
  skillRankCost,
} from "./progression.ts";

Deno.test("legacy levels become Vigor ranks without unspent attribute points", () => {
  const progression = parseProgression("{}", 4);
  assertEquals(progression.vigor, 3);
  assertEquals(progressionPoints(4, progression), { attribute: 0 });
  assertEquals(maxVigor(64, progression), 88);
});

Deno.test("skill bonuses derive from learned ranks", () => {
  const progression = initialProgression();
  progression.skills.energy = 2;
  progression.skills.critical = 3;
  assertEquals(maxEnergy(3, progression), 5);
  assertEquals(criticalChance(progression), 0.15);
});

Deno.test("attribute budgets and skill rank caps reject invalid progress", () => {
  const progression = initialProgression();
  progression.vigor = 2;
  assertEquals(isValidProgression(2, progression), false);

  progression.vigor = 0;
  progression.skills.energy = 3;
  assertEquals(isValidProgression(10, progression), false);

  progression.skills.energy = 2;
  progression.skills.strength = 2;
  assertEquals(isValidProgression(1, progression), true);
});

Deno.test("skill rank costs increase with the current rank", () => {
  assertEquals(skillRankCost(0), 20);
  assertEquals(skillRankCost(1), 30);
  assertEquals(skillRankCost(4), 60);
});

Deno.test("only one progression rank can change per save", () => {
  const previous = initialProgression();
  const vigor = { ...previous, vigor: 1 };
  assertEquals(progressionChange(previous, vigor), "attribute");

  const skill = {
    ...previous,
    skills: { ...previous.skills, poison: 1 },
  };
  assertEquals(progressionChange(previous, skill), "skill");

  const multiple = {
    ...skill,
    skills: { ...skill.skills, strength: 1 },
  };
  assertEquals(progressionChange(previous, multiple), "invalid");
});

Deno.test("malformed progression is safely normalized", () => {
  assertEquals(parseProgression("not-json", 3).vigor, 2);
  assertEquals(
    parseProgression({ version: 99, vigor: 12 }, 20),
    initialProgression(),
  );
  assertEquals(
    parseProgression({
      version: 1,
      vigor: -5,
      skills: { energy: 99, strength: 1.9, critical: "5" },
    }, 10),
    {
      version: 1,
      vigor: 0,
      skills: { energy: 2, strength: 1, critical: 0, poison: 0 },
    },
  );
});