import { describe, test, expect, afterAll, mock } from "bun:test";
import type { WebServerInstance } from "./server";
import { createWebServer } from "./server";

interface MockBotStats {
    bot: { name: string; avatarUrl: string | null };
    guilds: number;
    ping: number;
    cachedUsers: number;
    commandsRegistered: number;
    uptime: number;
    lastCommandTimestamp: number | null;
}

// 1. Mock DrizzleClient (dependency of dashboardService)
mock.module("@shared/db/DrizzleClient", () => {
    const mockBuilder = {
        where: mock(() => Promise.resolve([{ count: "5", balance: 1000n, level: 5, dailyStreak: 2 }])),
        then: (onfulfilled: any) => onfulfilled([{ count: "5", balance: 1000n, level: 5, dailyStreak: 2 }]),
    };

    const mockFrom = {
        from: mock(() => mockBuilder),
    };

    return {
        DrizzleClient: {
            select: mock(() => mockFrom),
            query: {
                transactions: { findMany: mock(() => Promise.resolve([])) },
                moderationCases: { findMany: mock(() => Promise.resolve([])) },
                users: {
                    findFirst: mock(() => Promise.resolve({ username: "test" })),
                    findMany: mock(() => Promise.resolve([])),
                },
            }
        },
    };
});

// 2. Mock Bot Stats Provider
mock.module("../../bot/lib/clientStats", () => ({
    getClientStats: mock((): MockBotStats => ({
        bot: { name: "TestBot", avatarUrl: null },
        guilds: 5,
        ping: 42,
        cachedUsers: 100,
        commandsRegistered: 10,
        uptime: 3600,
        lastCommandTimestamp: Date.now(),
    })),
}));

// 3. System Events (No mock needed, use real events)

describe("WebServer Security & Limits", () => {
    const port = 3001;
    let serverInstance: WebServerInstance | null = null;

    afterAll(async () => {
        if (serverInstance) {
            await serverInstance.stop();
        }
    });

    test("should reject more than 10 concurrent WebSocket connections", async () => {
        serverInstance = await createWebServer({ port, hostname: "localhost" });
        const wsUrl = `ws://localhost:${port}/ws`;
        const sockets: WebSocket[] = [];

        try {
            // Attempt to open 12 connections (limit is 10)
            for (let i = 0; i < 12; i++) {
                const ws = new WebSocket(wsUrl);
                sockets.push(ws);
                await new Promise(resolve => setTimeout(resolve, 5));
            }

            // Give connections time to settle
            await new Promise(resolve => setTimeout(resolve, 800));

            const pendingCount = serverInstance.server.pendingWebSockets;
            expect(pendingCount).toBeLessThanOrEqual(10);
        } finally {
            sockets.forEach(s => {
                if (s.readyState === WebSocket.OPEN || s.readyState === WebSocket.CONNECTING) {
                    s.close();
                }
            });
        }
    });

    test("should return 200 for health check", async () => {
        if (!serverInstance) {
            serverInstance = await createWebServer({ port, hostname: "localhost" });
        }
        const response = await fetch(`http://localhost:${port}/api/health`);
        expect(response.status).toBe(200);
        const data = (await response.json()) as { status: string };
        expect(data.status).toBe("ok");
    });

    describe("Administrative Actions Authorization", () => {
        test("should reject administrative actions without token", async () => {
            const response = await fetch(`http://localhost:${port}/api/actions/reload-commands`, {
                method: "POST"
            });
            expect(response.status).toBe(401);
        });

        test("should reject administrative actions with invalid token", async () => {
            const response = await fetch(`http://localhost:${port}/api/actions/reload-commands`, {
                method: "POST",
                headers: { "Authorization": "Bearer wrong-token" }
            });
            expect(response.status).toBe(401);
        });

        test("should accept administrative actions with valid token", async () => {
            const { env } = await import("@shared/lib/env");
            const response = await fetch(`http://localhost:${port}/api/actions/reload-commands`, {
                method: "POST",
                headers: { "Authorization": `Bearer ${env.ADMIN_TOKEN}` }
            });
            expect(response.status).toBe(200);
        });

        test("should reject maintenance mode with invalid payload", async () => {
            const { env } = await import("@shared/lib/env");
            const response = await fetch(`http://localhost:${port}/api/actions/maintenance-mode`, {
                method: "POST",
                headers: {
                    "Authorization": `Bearer ${env.ADMIN_TOKEN}`,
                    "Content-Type": "application/json"
                },
                body: JSON.stringify({ not_enabled: true }) // Wrong field
            });
            expect(response.status).toBe(400);
            const data = await response.json() as { error: string };
            expect(data.error).toBe("Invalid payload");
        });
    });
});
