import { rmSync } from "node:fs";
import { resolve } from "node:path";
import { FileDataStore } from "../db/fileStore";
import { discoverExternalExtensions } from "../extensions/external";
import { ExtensionLoader } from "../extensions/loader";
import { QuickActionRegistry } from "../extensions/quickActions";
import { attachQuickActionController } from "../hub/quickActionController";
import { InMemoryEventBus } from "../hub/eventBus";
import { createEvent } from "../hub/events";
import { HubStateRegistry } from "../hub/stateRegistry";

type WsOutRecord = {
    event: string;
    data: Record<string, unknown>;
};

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

async function main(): Promise<void> {
    const smokeDataFile = resolve(
        process.cwd(),
        "data",
        `phase15-smoke-${process.pid}-${Date.now()}.json`
    );
    const store = new FileDataStore(smokeDataFile);
    const bus = new InMemoryEventBus();
    const stateRegistry = new HubStateRegistry();
    const quickActions = new QuickActionRegistry();
    const loader = new ExtensionLoader(bus, stateRegistry, store, () => {}, quickActions);
    const wsOut: WsOutRecord[] = [];

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

    bus.on("ws_out", async (event) => {
        wsOut.push({
            event: event.payload.event,
            data: event.payload.data
        });
    });

    attachQuickActionController(bus, quickActions, () => {});

    try {
        const externalExtensions = await discoverExternalExtensions();
        loader.register(externalExtensions, "external");
        for (const extension of externalExtensions) {
            await loader.enable(extension.id);
        }

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

        const manifestEvent = wsOut.find((item) => item.event === "quick_actions_manifest");
        assert(Boolean(manifestEvent), "Expected quick_actions_manifest event.");
        const actions = (manifestEvent?.data.actions as Array<{ id?: string }> | undefined) ?? [];
        assert(
            actions.some((item) => item.id === "polls.status"),
            "Expected polls.status quick action in manifest."
        );

        wsOut.length = 0;
        await bus.emit(
            createEvent("admin_command", {
                streamId: stream.id,
                tokenId: "phase15-admin-token",
                sessionId: "phase15-session",
                command: "action",
                args: ["run", "polls.status"],
                actorRole: "admin"
            })
        );

        assert(
            wsOut.some((item) => item.event === "quick_actions_result"),
            "Expected quick_actions_result after running action."
        );
        assert(
            wsOut.some((item) => item.event === "poll_update"),
            "Expected poll_update from polls.status action run."
        );

        console.log(
            JSON.stringify(
                {
                    ok: true,
                    quickActionsRegistered: actions.length
                },
                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);
});
