import { describe, expect, it } from "vitest";
import { BOSS_GROUPS } from "../bossCatalog";
import { BOSS_PET_DROPS, BOSS_PET_DROP_RATE, GROUP_DROP_TABLES, bossGroupDrop, createEmptyCollectionLog, groupDropQuantity, rollBossReward } from "./loot";

describe("group drop tables", () => {
  it("defines five shared drops for every mechanic group", () => {
    for (const group of BOSS_GROUPS) {
      const table = GROUP_DROP_TABLES[group.id];
      expect(Object.keys(table.drops)).toEqual(["initiate", "veteran", "champion", "mythic", "ascendant"]);
      expect(table.drops.veteran.name).toBe(`Green Group ${group.letter} Drop`);
    }
  });

  it("awards the same material from every boss in a group", () => {
    expect(bossGroupDrop("bulldrome", "veteran").id).toBe(bossGroupDrop("bristlequake-boar", "veteran").id);
    expect(bossGroupDrop("bulldrome", "veteran").name).toBe("Green Group A Drop");
  });

  it("rolls group drop quantities at exact boundaries", () => {
    expect(groupDropQuantity(() => 0)).toBe(3);
    expect(groupDropQuantity(() => 0.149999)).toBe(3);
    expect(groupDropQuantity(() => 0.15)).toBe(2);
    expect(groupDropQuantity(() => 0.499999)).toBe(2);
    expect(groupDropQuantity(() => 0.5)).toBe(1);
  });

  it("stacks duplicate group drops while collection counts remain lifetime totals", () => {
    const rolls = [0.1, 1, 0.2, 0];
    const random = () => rolls.shift() ?? 1;
    const first = rollBossReward("bulldrome", "initiate", [], createEmptyCollectionLog(), random);
    const second = rollBossReward("bulldrome", "initiate", first.inventory, first.collectionLog, random);
    expect(first.award.quantity).toBe(3);
    expect(second.award.quantity).toBe(2);
    expect(second.award.duplicate).toBe(true);
    expect(second.inventory[0].quantity).toBe(5);
    expect(second.collectionLog.dropsFound[second.award.drop.id]).toBe(5);
    expect(second.award.pet?.id).toBe("bulldrome-pet");
  });

  it("gives every boss pet an exact 1 in 500 independent roll", () => {
    expect(BOSS_PET_DROP_RATE).toBe(1 / 500);
    for (const pet of Object.values(BOSS_PET_DROPS)) {
      expect(pet.dropRate).toBe(1 / 500);
      expect(pet.chanceLabel).toBe("1 in 500");
    }

    const hitRolls = [1, 1 / 500 - Number.EPSILON];
    const hit = rollBossReward("bulldrome", "initiate", [], createEmptyCollectionLog(), () => hitRolls.shift() ?? 1);
    expect(hit.award.pet?.id).toBe("bulldrome-pet");

    const missRolls = [1, 1 / 500];
    const miss = rollBossReward("bulldrome", "initiate", [], createEmptyCollectionLog(), () => missRolls.shift() ?? 1);
    expect(miss.award.pet).toBeNull();
  });
});
