import { rmSync } from "node:fs";
import { resolve } from "node:path";
import { FileDataStore } from "../db/fileStore";
import { ExtensionLoader } from "../extensions/loader";
import type { ExtensionDefinition } from "../extensions/types";
import { InMemoryEventBus } from "../hub/eventBus";
import { createEvent } from "../hub/events";
import { HubStateRegistry } from "../hub/stateRegistry";

function assert(condition: boolean, message: string): void {
    if (!condition) {
        throw new Error(message);
    }
}

async function main(): Promise<void> {
    const smokeDataFile = resolve(
        process.cwd(),
        "data",
        `phase7-smoke-${process.pid}-${Date.now()}.json`
    );
    const store = new FileDataStore(smokeDataFile);
    const bus = new InMemoryEventBus();
    const stateRegistry = new HubStateRegistry();
    const logs: string[] = [];
    const wsOutEvents: Array<{ streamId: string; event: string; count: number }> = [];

    await store.init();
    const stream = await store.createStream({ name: "phase7-smoke" });

    bus.on("ws_out", async (event) => {
        wsOutEvents.push({
            streamId: event.payload.streamId,
            event: event.payload.event,
            count: Number((event.payload.data as { count?: unknown }).count ?? 0)
        });
    });

    const testExtension: ExtensionDefinition = {
        id: "phase7-test",
        async init(api) {
            await api.db.createStream({ name: "phase7-extension-db-check" });
            api.log("init_complete");

            api.on("admin_command", async (event) => {
                const current = api.getState<number>(event.payload.streamId, "commandCount", 0);
                const next = current + 1;
                api.setState(event.payload.streamId, "commandCount", next);

                await api.emit("ws_out", {
                    streamId: event.payload.streamId,
                    target: "admin",
                    event: "phase7_count",
                    data: { count: next }
                });
            });
        }
    };

    const loader = new ExtensionLoader(bus, stateRegistry, store, (message, fields = {}) => {
        logs.push(`${message}:${JSON.stringify(fields)}`);
    });

    try {
        await loader.load([testExtension]);

        await bus.emit(
            createEvent("admin_command", {
                streamId: stream.id,
                tokenId: "phase7-admin-token",
                sessionId: "phase7-session-1",
                command: "one",
                args: [],
                actorRole: "admin"
            })
        );
        await bus.emit(
            createEvent("admin_command", {
                streamId: stream.id,
                tokenId: "phase7-admin-token",
                sessionId: "phase7-session-1",
                command: "two",
                args: [],
                actorRole: "admin"
            })
        );

        const finalCount = stateRegistry.getState<number>(stream.id, "phase7-test", "commandCount", 0);
        assert(finalCount === 2, "Expected extension state to increment via API set/get.");
        assert(wsOutEvents.length === 2, "Expected extension emit() to publish ws_out events.");
        assert(
            wsOutEvents[0].count === 1 && wsOutEvents[1].count === 2,
            "Expected emitted ws_out event payload counts to increase."
        );
        assert(
            logs.some((line) => line.includes("\"extensionId\":\"phase7-test\"")),
            "Expected loader log output to include extension id."
        );

        console.log(
            JSON.stringify(
                {
                    ok: true,
                    finalCount,
                    wsOutEvents
                },
                null,
                2
            )
        );
    } finally {
        rmSync(smokeDataFile, { force: true });
    }
}

main().catch((error: unknown) => {
    const message = error instanceof Error ? error.message : String(error);
    console.error(message);
    process.exit(1);
});
