import { InMemoryEventBus } from "../hub/eventBus";
import { startYouTubeAdapter } from "../platform/youtube";

function delay(ms: number): Promise<void> {
    return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
}

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

async function main(): Promise<void> {
    const bus = new InMemoryEventBus();
    const seen: Array<{ platform: string; author: string; message: string }> = [];
    let fetchCallCount = 0;
    let videoLookupPart: string | null = null;
    let videoLookupFields: string | null = null;

    bus.on("chat_ingest", async (event) => {
        seen.push({
            platform: event.payload.platform,
            author: event.payload.author,
            message: event.payload.message
        });
    });

    const fakeFetch: typeof fetch = async (input) => {
        fetchCallCount += 1;
        const url = typeof input === "string" ? new URL(input) : input instanceof URL ? input : new URL(input.url);
        if (url.hostname === "oauth2.googleapis.com" && url.pathname === "/token") {
            return {
                ok: true,
                status: 200,
                statusText: "OK",
                json: async () => ({
                    access_token: "oauth-phase13-token",
                    expires_in: 300
                })
            } as Response;
        }
        if (url.pathname.endsWith("/videos")) {
            videoLookupPart = url.searchParams.get("part");
            videoLookupFields = url.searchParams.get("fields");
            return {
                ok: true,
                status: 200,
                statusText: "OK",
                json: async () => ({
                    items: [{ liveStreamingDetails: { activeLiveChatId: "fake-chat-id" } }]
                })
            } as Response;
        }
        return {
            ok: true,
            status: 200,
            statusText: "OK",
            json: async () => ({
                pollingIntervalMillis: 10,
                nextPageToken: "next",
                items: [
                    {
                        id: "youtube-msg-1",
                        snippet: { displayMessage: "hello from youtube" },
                        authorDetails: { displayName: "yt-user" }
                    },
                    {
                        id: "youtube-msg-1",
                        snippet: { displayMessage: "duplicate message id" },
                        authorDetails: { displayName: "yt-user" }
                    }
                ]
            })
        } as unknown as Response;
    };
    const fakeStreamList = async function* () {
        yield {
            nextPageToken: "next",
            items: [
                {
                    id: "youtube-msg-1",
                    snippet: { displayMessage: "hello from youtube" },
                    authorDetails: { displayName: "yt-user" }
                },
                {
                    id: "youtube-msg-1",
                    snippet: { displayMessage: "duplicate message id" },
                    authorDetails: { displayName: "yt-user" }
                }
            ]
        };
    };

    const adapter = startYouTubeAdapter({
        eventBus: bus,
        apiKey: "fake-key",
        oauthClientId: "client-id",
        oauthClientSecret: "client-secret",
        oauthRefreshToken: "refresh-token",
        pollMs: 10,
        discoveryPollMs: 10,
        fetchImpl: fakeFetch,
        streamListImpl: fakeStreamList,
        log: () => {}
    });

    try {
        const result = await adapter.setVideo("dQw4w9WgXcQ");
        assert(result.found, "Expected video URL/ID fallback to resolve a live chat.");
        await delay(60);
        adapter.stop();
        await delay(30);

        assert(fetchCallCount >= 1, "Expected adapter to poll at least once.");
        assert(videoLookupPart === "liveStreamingDetails", "Expected videos lookup part to be liveStreamingDetails.");
        assert(
            videoLookupFields === "items/liveStreamingDetails/activeLiveChatId",
            "Expected videos lookup to request only the active live chat id field."
        );
        assert(seen.length === 1, "Expected one deduplicated chat_ingest.");
        assert(seen[0].platform === "youtube", "Expected platform to be youtube.");
        assert(seen[0].author === "yt-user", "Expected author mapping from YouTube payload.");
        assert(seen[0].message === "hello from youtube", "Expected message mapping.");

        console.log(
            JSON.stringify(
                {
                    ok: true,
                    fetchCallCount,
                    emittedMessages: seen.length
                },
                null,
                2
            )
        );
    } finally {
        adapter.stop();
    }
}

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