import { describe, expect, type TestContext, test } from "vitest";
import { describeDriverMatrix } from "./shared-matrix";
import { setupDriverTest } from "./shared-utils";

describeDriverMatrix("Actor Kv", (driverTestConfig) => {
	type KvTextHandle = {
		putText: (key: string, value: string) => Promise<unknown>;
		getText: (key: string) => Promise<string | null>;
		listText: (
			prefix: string,
		) => Promise<Array<{ key: string; value: string }>>;
		listTextRange: (
			start: string,
			end: string,
			options?: {
				reverse?: boolean;
				limit?: number;
			},
		) => Promise<Array<{ key: string; value: string }>>;
		deleteTextRange: (start: string, end: string) => Promise<unknown>;
	};

	type KvArrayBufferHandle = {
		roundtripArrayBuffer: (
			key: string,
			bytes: number[],
		) => Promise<number[]>;
	};

	describe("Actor KV Tests", () => {
		test("supports text encoding and decoding", async (c: TestContext) => {
			const { client: rawClient } = await setupDriverTest(
				c,
				driverTestConfig,
			);
			const client = rawClient as any;
			const kvHandle = client.kvActor.getOrCreate([
				"kv-text",
			]) as unknown as KvTextHandle;

			await kvHandle.putText("greeting", "hello");
			const value = await kvHandle.getText("greeting");
			expect(value).toBe("hello");

			await kvHandle.putText("prefix-a", "alpha");
			await kvHandle.putText("prefix-b", "beta");

			const results = await kvHandle.listText("prefix-");
			const sorted = results.sort((a, b) => a.key.localeCompare(b.key));
			expect(sorted).toEqual([
				{ key: "prefix-a", value: "alpha" },
				{ key: "prefix-b", value: "beta" },
			]);
		});

		test("supports range scans and range deletes", async (c: TestContext) => {
			const { client: rawClient } = await setupDriverTest(
				c,
				driverTestConfig,
			);
			const client = rawClient as any;
			const kvHandle = client.kvActor.getOrCreate([
				"kv-range",
			]) as unknown as KvTextHandle;

			await kvHandle.putText("a", "alpha");
			await kvHandle.putText("b", "bravo");
			await kvHandle.putText("c", "charlie");
			await kvHandle.putText("d", "delta");

			const range = await kvHandle.listTextRange("b", "d");
			expect(range).toEqual([
				{ key: "b", value: "bravo" },
				{ key: "c", value: "charlie" },
			]);

			const reversed = await kvHandle.listTextRange("a", "d", {
				reverse: true,
				limit: 2,
			});
			expect(reversed).toEqual([
				{ key: "c", value: "charlie" },
				{ key: "b", value: "bravo" },
			]);

			await kvHandle.deleteTextRange("b", "d");
			const remaining = await kvHandle.listText("");
			expect(remaining).toEqual([
				{ key: "a", value: "alpha" },
				{ key: "d", value: "delta" },
			]);
		});

		test("supports arrayBuffer encoding and decoding", async (c: TestContext) => {
			const { client: rawClient } = await setupDriverTest(
				c,
				driverTestConfig,
			);
			const client = rawClient as any;
			const kvHandle = client.kvActor.getOrCreate([
				"kv-array-buffer",
			]) as unknown as KvArrayBufferHandle;

			const values = await kvHandle.roundtripArrayBuffer(
				"bytes",
				[4, 8, 15, 16, 23, 42],
			);
			expect(values).toEqual([4, 8, 15, 16, 23, 42]);
		});
	});
});
