import { describe, expect, it } from "vitest";
import { LeaderboardCache } from "./leaderboardCache";
import type { LeaderboardResult } from "./onlineRepository";

function memoryStorage() {
  const values = new Map<string, string>();
  return {
    values,
    getItem: (key: string) => values.get(key) ?? null,
    setItem: (key: string, value: string) => { values.set(key, value); },
  };
}

const result: LeaderboardResult = {
  kind: "roguelike",
  top: [{ rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 12 }],
  current: { rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 12 },
};

describe("leaderboard cache", () => {
  it("persists rankings for signed-in and offline reads", () => {
    const storage = memoryStorage();
    const cache = new LeaderboardCache(storage, () => "2026-07-14T00:00:00.000Z");
    cache.write("hunter", "Aelia", 1, "roguelike", result);

    expect(cache.read(1, "roguelike", "Aelia", "hunter")?.result).toEqual(result);
    expect(cache.read(1, "roguelike", "Aelia", null)?.accountId).toBe("hunter");
    expect(cache.read(1, "roguelike", "Other", null)).toBeNull();
    expect(cache.read(1, "roguelike", "Aelia", "different-account")).toBeNull();
  });

  it("ignores corrupt persisted responses", () => {
    const storage = memoryStorage();
    storage.setItem("i-want-to-heal:leaderboards:cache:v1", JSON.stringify({
      "1:roguelike": { accountId: "hunter", hunterName: "Aelia", slotId: 1, statId: "roguelike", updatedAt: "today", result: {} },
    }));
    expect(new LeaderboardCache(storage).read(1, "roguelike", "Aelia", "hunter")).toBeNull();
  });

  it("preserves Hockey Healing duration tiebreakers", () => {
    const cache = new LeaderboardCache(memoryStorage());
    const hockeyResult: LeaderboardResult = {
      kind: "hockey-healing",
      top: [{ rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 20, secondaryValue: 95.5 }],
      current: { rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 20, secondaryValue: 95.5 },
    };

    cache.write("hunter", "Aelia", 1, "hockey-healing", hockeyResult);
    expect(cache.read(1, "hockey-healing", "Aelia", "hunter")?.result).toEqual(hockeyResult);
  });

  it("validates Blockbreaker metric boards for offline reads", () => {
    const cache = new LeaderboardCache(memoryStorage());
    const blockbreakerResult: LeaderboardResult = {
      kind: "blockbreaker-score",
      top: [{ rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 12_500 }],
      current: { rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 12_500 },
    };
    cache.write("hunter", "Aelia", 1, "blockbreaker-score", blockbreakerResult);
    expect(cache.read(1, "blockbreaker-score", "Aelia", "hunter")?.result).toEqual(blockbreakerResult);
  });

  it("preserves Aether Assault wave tiebreakers for offline reads", () => {
    const cache = new LeaderboardCache(memoryStorage());
    const aetherResult: LeaderboardResult = {
      kind: "aether-assault",
      top: [{ rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 48_500, secondaryValue: 9 }],
      current: { rank: 1, username: "hunter", hunterName: "Aelia", slotId: 1, value: 48_500, secondaryValue: 9 },
    };
    cache.write("hunter", "Aelia", 1, "aether-assault", aetherResult);
    expect(cache.read(1, "aether-assault", "Aelia", "hunter")?.result).toEqual(aetherResult);
  });
});
