import { describe, it, expect } from "vitest";
import { computeBadges } from "../badges.js";

const makePayload = (overrides?: {
  progress?: Partial<Record<"easy" | "medium" | "hard" | "expert", number>>;
  totals?: Partial<{
    totalCompletions: number;
    totalMoves: number;
    totalTime: number;
  }>;
  tutorialCompleted?: boolean;
}) => ({
  progress: {
    easy: 0,
    medium: 0,
    hard: 0,
    expert: 0,
    ...overrides?.progress,
  },
  totals: {
    totalCompletions: 0,
    totalMoves: 0,
    totalTime: 0,
    ...overrides?.totals,
  },
  tutorialCompleted: overrides?.tutorialCompleted ?? false,
});

describe("badges", () => {
  it("un compte invité non-admin peut débloquer les badges limités s'il est éligible", () => {
    const badges = computeBadges({
      ...makePayload({ progress: { easy: 100 }, totals: { totalMoves: 5000 } }),
      isGuest: true,
      launchDateMs: Date.parse("2026-02-07T00:00:00Z"),
      userCreatedAtMs: Date.parse("2026-02-08T00:00:00Z"),
      rankSinceLaunch: 1,
    });
    expect(badges).toContain("starter");
    expect(badges).toContain("veteran");
    expect(badges).toContain("steady");
    expect(badges).toContain("early-tester");
    expect(badges).toContain("founder-100");
  });

  it("un compte invité non éligible ne débloque pas les badges limités", () => {
    const launchDateMs = Date.parse("2026-02-07T00:00:00Z");
    const badges = computeBadges({
      ...makePayload({ progress: { easy: 100 }, totals: { totalMoves: 5000 } }),
      isGuest: true,
      launchDateMs,
      // 40 jours après le lancement -> hors fenêtre beta (30 jours)
      userCreatedAtMs: launchDateMs + 40 * 24 * 60 * 60 * 1000,
      rankSinceLaunch: 101,
    });
    expect(badges).not.toContain("early-tester");
    expect(badges).not.toContain("founder-100");
  });

  it("un admin ne débloque pas les badges limités", () => {
    const launchDateMs = Date.parse("2026-02-07T00:00:00Z");
    const badges = computeBadges({
      ...makePayload({ progress: { easy: 1 } }),
      isGuest: false,
      isAdmin: true,
      launchDateMs,
      userCreatedAtMs: launchDateMs + 10 * 24 * 60 * 60 * 1000,
      rankSinceLaunch: 1,
    });
    expect(badges).not.toContain("early-tester");
    expect(badges).not.toContain("founder-100");
  });

  it("badge early-tester pendant le 1er mois après launch_date", () => {
    const launchDateMs = Date.parse("2026-02-07T00:00:00Z");
    const badges = computeBadges({
      ...makePayload({ progress: { easy: 1 } }),
      isGuest: false,
      launchDateMs,
      userCreatedAtMs: launchDateMs + 10 * 24 * 60 * 60 * 1000,
    });
    expect(badges).toContain("early-tester");
  });

  it("badge founder-100 si rankSinceLaunch <= 100", () => {
    const launchDateMs = Date.parse("2026-02-07T00:00:00Z");
    const badges = computeBadges({
      ...makePayload({ progress: { easy: 1 } }),
      isGuest: false,
      launchDateMs,
      userCreatedAtMs: launchDateMs + 10 * 24 * 60 * 60 * 1000,
      rankSinceLaunch: 100,
    });
    expect(badges).toContain("founder-100");
  });

  it("aucun badge si rien n'est complété", () => {
    const badges = computeBadges(makePayload());
    expect(badges).toEqual([]);
  });

  it("badge starter à 1 complétion", () => {
    const badges = computeBadges(makePayload({ progress: { easy: 1 } }));
    expect(badges).toContain("starter");
  });

  it("badge explorer à 10 complétions", () => {
    const badges = computeBadges(makePayload({ progress: { easy: 10 } }));
    expect(badges).toContain("explorer");
    expect(badges).toContain("starter");
  });

  it("badge solver à 25 complétions", () => {
    const badges = computeBadges(makePayload({ progress: { easy: 25 } }));
    expect(badges).toContain("solver");
  });

  it("badge veteran à 100 complétions", () => {
    const badges = computeBadges(makePayload({ progress: { easy: 100 } }));
    expect(badges).toContain("veteran");
  });

  it("badge marathon à 250 complétions", () => {
    const badges = computeBadges(
      makePayload({ progress: { easy: 240, medium: 10 } }),
    );
    expect(badges).toContain("marathon");
  });

  it("badge replay à 50 totalCompletions", () => {
    const badges = computeBadges(
      makePayload({ progress: { easy: 1 }, totals: { totalCompletions: 50 } }),
    );
    expect(badges).toContain("replay");
  });

  it("badge steady à 1000 totalMoves", () => {
    const badges = computeBadges(
      makePayload({ progress: { easy: 1 }, totals: { totalMoves: 1000 } }),
    );
    expect(badges).toContain("steady");
  });

  it("badge endurance à 3600 totalTime", () => {
    const badges = computeBadges(
      makePayload({
        progress: { easy: 1 },
        totals: { totalTime: 3600 * 1000 },
      }),
    );
    expect(badges).toContain("endurance");
  });

  it("badge tutorial si tutorialCompleted", () => {
    const badges = computeBadges(makePayload({ tutorialCompleted: true }));
    expect(badges).toContain("tutorial");
  });

  it("badge all-rounder si tous les modes ont au moins 1", () => {
    const badges = computeBadges(
      makePayload({ progress: { easy: 1, medium: 1, hard: 1, expert: 1 } }),
    );
    expect(badges).toContain("all-rounder");
  });

  it("pas de badge all-rounder si un mode manque", () => {
    const badges = computeBadges(
      makePayload({ progress: { easy: 5, medium: 5, hard: 5, expert: 0 } }),
    );
    expect(badges).not.toContain("all-rounder");
  });

  it("badge specialist à 50% d'une difficulté (120/240)", () => {
    const badges = computeBadges(makePayload({ progress: { easy: 120 } }));
    expect(badges).toContain("specialist");
  });

  it("pas de badge specialist à 49%", () => {
    // 118/240 = 49.17% → Math.round = 49 → pas de specialist
    const badges = computeBadges(makePayload({ progress: { easy: 118 } }));
    expect(badges).not.toContain("specialist");
  });

  it("badge master si toutes les 960 niveaux complétés", () => {
    const badges = computeBadges(
      makePayload({
        progress: { easy: 240, medium: 240, hard: 240, expert: 240 },
      }),
    );
    expect(badges).toContain("master");
  });

  it("pas de badge master à 959 niveaux", () => {
    const badges = computeBadges(
      makePayload({
        progress: { easy: 240, medium: 240, hard: 240, expert: 239 },
      }),
    );
    expect(badges).not.toContain("master");
  });

  it("joueur complet a tous les 12 badges", () => {
    const badges = computeBadges({
      progress: { easy: 240, medium: 240, hard: 240, expert: 240 },
      totals: {
        totalCompletions: 1000,
        totalMoves: 5000,
        totalTime: 10000 * 1000,
      },
      tutorialCompleted: true,
    });
    expect(badges).toHaveLength(12);
    const expected = [
      "starter",
      "explorer",
      "solver",
      "veteran",
      "marathon",
      "replay",
      "steady",
      "endurance",
      "tutorial",
      "all-rounder",
      "specialist",
      "master",
    ];
    for (const b of expected) {
      expect(badges).toContain(b);
    }
  });
});
