// IDBCache unit tests under JSDOM with `fake-indexeddb` standing in
// for the browser's IndexedDB factory. Each case opens a freshly
// named database so state cannot leak across tests.

import "fake-indexeddb/auto";
import { afterEach, beforeEach, describe, expect, test } from "vitest";
import type { IDBPDatabase } from "idb";
import { IDBCache } from "../src/platform/store/idb-cache";
import { openGalaxyDB, type GalaxyDB } from "../src/platform/store/idb";

let db: IDBPDatabase<GalaxyDB>;
let dbName: string;

beforeEach(async () => {
	dbName = `galaxy-ui-test-${crypto.randomUUID()}`;
	db = await openGalaxyDB(dbName);
});

afterEach(async () => {
	db.close();
	indexedDB.deleteDatabase(dbName);
});

describe("IDBCache", () => {
	test("round-trips a typed object", async () => {
		const cache = new IDBCache(db);
		const value = {
			name: "ping",
			payload: new Uint8Array([1, 2, 3]),
			nested: { count: 7 },
		};
		await cache.put("commands", "k1", value);
		const out = await cache.get<typeof value>("commands", "k1");
		expect(out?.name).toBe("ping");
		expect(out?.nested.count).toBe(7);
		expect(Array.from(out?.payload ?? [])).toEqual([1, 2, 3]);
	});

	test("namespaces are isolated", async () => {
		const cache = new IDBCache(db);
		await cache.put("a", "shared-key", "from-a");
		await cache.put("b", "shared-key", "from-b");
		expect(await cache.get("a", "shared-key")).toBe("from-a");
		expect(await cache.get("b", "shared-key")).toBe("from-b");
	});

	test("delete removes a single row without touching neighbours", async () => {
		const cache = new IDBCache(db);
		await cache.put("ns", "k1", "v1");
		await cache.put("ns", "k2", "v2");
		await cache.delete("ns", "k1");
		expect(await cache.get("ns", "k1")).toBeUndefined();
		expect(await cache.get("ns", "k2")).toBe("v2");
	});

	test("clear(namespace) wipes only that namespace", async () => {
		const cache = new IDBCache(db);
		await cache.put("a", "k1", "a1");
		await cache.put("a", "k2", "a2");
		await cache.put("b", "k1", "b1");
		await cache.clear("a");
		expect(await cache.get("a", "k1")).toBeUndefined();
		expect(await cache.get("a", "k2")).toBeUndefined();
		expect(await cache.get("b", "k1")).toBe("b1");
	});

	test("clear() wipes every namespace", async () => {
		const cache = new IDBCache(db);
		await cache.put("a", "k1", "a1");
		await cache.put("b", "k1", "b1");
		await cache.clear();
		expect(await cache.get("a", "k1")).toBeUndefined();
		expect(await cache.get("b", "k1")).toBeUndefined();
	});

	test("get on a missing key returns undefined", async () => {
		const cache = new IDBCache(db);
		expect(await cache.get("absent", "k")).toBeUndefined();
	});
});
