import { describe, test, expect, mock, beforeEach } from "bun:test";
import { dashboardService } from "./dashboard.service";

// Mock DrizzleClient
const mockSelect = mock(() => ({
    from: mock(() => Promise.resolve([{ count: "5" }])),
}));

const mockQuery = {
    transactions: {
        findMany: mock(() => Promise.resolve([])),
    },
    moderationCases: {
        findMany: mock(() => Promise.resolve([])),
    },
};

mock.module("@shared/db/DrizzleClient", () => ({
    DrizzleClient: {
        select: mockSelect,
        query: mockQuery,
    },
}));

describe("dashboardService", () => {
    beforeEach(() => {
        mockSelect.mockClear();
        mockQuery.transactions.findMany.mockClear();
        mockQuery.moderationCases.findMany.mockClear();

        // Reset default mock implementation
        mockSelect.mockImplementation(() => ({
            from: mock(() => Promise.resolve([{ count: "5" }])),
        }));
    });

    describe("getActiveUserCount", () => {
        test("should return active user count from database", async () => {
            mockSelect.mockImplementationOnce(() => ({
                from: mock(() => ({
                    where: mock(() => Promise.resolve([{ count: "5" }])),
                })),
            }));

            const count = await dashboardService.getActiveUserCount();
            expect(count).toBe(5);
            expect(mockSelect).toHaveBeenCalled();
        });

        test("should return 0 when no users found", async () => {
            mockSelect.mockImplementationOnce(() => ({
                from: mock(() => ({
                    where: mock(() => Promise.resolve([{ count: "0" }])),
                })),
            }));

            const count = await dashboardService.getActiveUserCount();
            expect(count).toBe(0);
        });
    });

    describe("getTotalUserCount", () => {
        test("should return total user count", async () => {
            const count = await dashboardService.getTotalUserCount();
            expect(count).toBe(5);
        });
    });

    describe("getRecentTransactions", () => {
        test("should return formatted transaction events", async () => {
            const mockTx = [
                {
                    type: "DAILY_REWARD",
                    description: "Daily reward",
                    createdAt: new Date(),
                    user: { username: "testuser" },
                },
            ] as any;

            mockQuery.transactions.findMany.mockResolvedValueOnce(mockTx);

            const events = await dashboardService.getRecentTransactions(10);

            expect(events).toHaveLength(1);
            expect(events[0]?.type).toBe("info");
            expect(events[0]?.message).toContain("testuser");
            expect(events[0]?.icon).toBe("☀️");
        });

        test("should handle empty transactions", async () => {
            mockQuery.transactions.findMany.mockResolvedValueOnce([]);

            const events = await dashboardService.getRecentTransactions(10);
            expect(events).toHaveLength(0);
        });
    });

    describe("getRecentModerationCases", () => {
        test("should return formatted moderation events", async () => {
            const mockCases = [
                {
                    type: "warn",
                    username: "baduser",
                    reason: "Spam",
                    createdAt: new Date(),
                },
            ] as any;

            mockQuery.moderationCases.findMany.mockResolvedValueOnce(mockCases);

            const events = await dashboardService.getRecentModerationCases(10);

            expect(events).toHaveLength(1);
            expect(events[0]?.type).toBe("error");
            expect(events[0]?.message).toContain("WARN");
            expect(events[0]?.message).toContain("baduser");
            expect(events[0]?.icon).toBe("⚠️");
        });
    });

    describe("getRecentEvents", () => {
        test("should combine and sort transactions and moderation events", async () => {
            const now = new Date();
            const earlier = new Date(now.getTime() - 1000);

            mockQuery.transactions.findMany.mockResolvedValueOnce([
                {
                    type: "DAILY_REWARD",
                    description: "Daily",
                    createdAt: now,
                    user: { username: "user1" },
                },
            ] as any);

            mockQuery.moderationCases.findMany.mockResolvedValueOnce([
                {
                    type: "warn",
                    username: "user2",
                    reason: "Test",
                    createdAt: earlier,
                },
            ] as any);

            const events = await dashboardService.getRecentEvents(10);

            expect(events).toHaveLength(2);
            // Should be sorted by timestamp (newest first)
            expect(events[0]?.timestamp.getTime()).toBeGreaterThanOrEqual(
                events[1]?.timestamp.getTime() ?? 0
            );
        });
    });
});
