import { describe, test, expect, beforeEach, mock, afterEach } from "bun:test";
import { getClientStats, clearStatsCache } from "./clientStats";

// Mock AuroraClient
mock.module("./BotClient", () => ({
    AuroraClient: {
        guilds: {
            cache: {
                size: 5,
            },
        },
        ws: {
            ping: 42,
        },
        users: {
            cache: {
                size: 100,
            },
        },
        commands: {
            size: 20,
        },
        lastCommandTimestamp: 1641481200000,
    },
}));

describe("clientStats", () => {
    beforeEach(() => {
        clearStatsCache();
    });

    test("should return client stats", () => {
        const stats = getClientStats();

        expect(stats.guilds).toBe(5);
        expect(stats.ping).toBe(42);
        expect(stats.cachedUsers).toBe(100);
        expect(stats.commandsRegistered).toBe(20);
        expect(typeof stats.uptime).toBe("number"); // Can't mock process.uptime easily
        expect(stats.lastCommandTimestamp).toBe(1641481200000);
    });

    test("should cache stats for 30 seconds", () => {
        const stats1 = getClientStats();
        const stats2 = getClientStats();

        // Should return same object (cached)
        expect(stats1).toBe(stats2);
    });

    test("should refresh cache after TTL expires", async () => {
        const stats1 = getClientStats();

        // Wait for cache to expire (simulate by clearing and waiting)
        await new Promise(resolve => setTimeout(resolve, 35));
        clearStatsCache();

        const stats2 = getClientStats();

        // Should be different objects (new fetch)
        expect(stats1).not.toBe(stats2);
        // But values should be the same (mocked client)
        expect(stats1.guilds).toBe(stats2.guilds);
    });

    test("clearStatsCache should invalidate cache", () => {
        const stats1 = getClientStats();
        clearStatsCache();
        const stats2 = getClientStats();

        // Should be different objects
        expect(stats1).not.toBe(stats2);
    });
});
