import { describe, test, expect, mock, beforeEach } from "bun:test";

// Mock DrizzleClient before importing service
const mockFindMany = mock();
const mockLimit = mock();

// Helper to support the chained calls in getLeaderboards
const mockChain = {
    from: () => mockChain,
    orderBy: () => mockChain,
    limit: mockLimit
};

mock.module("@shared/db/DrizzleClient", () => ({
    DrizzleClient: {
        select: () => mockChain,
        query: {
            lootdrops: {
                findMany: mockFindMany
            }
        }
    }
}));

// Import service after mocking
import { dashboardService } from "./dashboard.service";

describe("dashboardService", () => {
    beforeEach(() => {
        mockFindMany.mockClear();
        mockLimit.mockClear();
    });

    describe("getActiveLootdrops", () => {
        test("should return active lootdrops when found", async () => {
            const mockDrops = [
                {
                    messageId: "123",
                    channelId: "general",
                    rewardAmount: 100,
                    currency: "Gold",
                    createdAt: new Date(),
                    expiresAt: new Date(Date.now() + 3600000),
                    claimedBy: null
                }
            ];
            mockFindMany.mockResolvedValue(mockDrops);

            const result = await dashboardService.getActiveLootdrops();
            expect(result).toEqual(mockDrops);
            expect(mockFindMany).toHaveBeenCalledTimes(1);
        });

        test("should return empty array if no active drops", async () => {
            mockFindMany.mockResolvedValue([]);
            const result = await dashboardService.getActiveLootdrops();
            expect(result).toEqual([]);
        });
    });

    describe("getLeaderboards", () => {
        test("should combine top levels and wealth", async () => {
            const mockTopLevels = [
                { username: "Alice", level: 10, avatar: "a.png" },
                { username: "Bob", level: 5, avatar: null },
                { username: "Charlie", level: 2, avatar: "c.png" }
            ];
            const mockTopWealth = [
                { username: "Alice", balance: 1000n, avatar: "a.png" },
                { username: "Dave", balance: 500n, avatar: "d.png" },
                { username: "Bob", balance: 100n, avatar: null }
            ];

            // Mock sequential calls to limit()
            // First call is topLevels, second is topWealth
            mockLimit
                .mockResolvedValueOnce(mockTopLevels)
                .mockResolvedValueOnce(mockTopWealth);

            const result = await dashboardService.getLeaderboards();

            expect(result.topLevels).toEqual(mockTopLevels);
            // Verify balance BigInt to string conversion
            expect(result.topWealth).toHaveLength(3);
            expect(result.topWealth[0]!.balance).toBe("1000");
            expect(result.topWealth[0]!.username).toBe("Alice");
            expect(result.topWealth[1]!.balance).toBe("500");
            expect(mockLimit).toHaveBeenCalledTimes(2);
        });

        test("should handle empty leaderboards", async () => {
            mockLimit.mockResolvedValue([]);

            const result = await dashboardService.getLeaderboards();
            expect(result.topLevels).toEqual([]);
            expect(result.topWealth).toEqual([]);
        });
    });
});
