import { describe, it, expect, mock, beforeEach } from "bun:test";
import { temporaryRoleService } from "@shared/modules/system/temp-role.service";
import { userTimers } from "@db/schema";
import { TimerType } from "@shared/lib/constants";

const mockDelete = mock();
const mockWhere = mock();
const mockFindMany = mock();

mockDelete.mockReturnValue({ where: mockWhere });

// Mock DrizzleClient
mock.module("@shared/db/DrizzleClient", () => ({
    DrizzleClient: {
        delete: mockDelete,
        query: {
            userTimers: {
                findMany: mockFindMany
            }
        }
    }
}));

// Mock AuroraClient
const mockRemoveRole = mock();
const mockFetchMember = mock();
const mockFetchGuild = mock();

mock.module("@/lib/BotClient", () => ({
    AuroraClient: {
        guilds: {
            fetch: mockFetchGuild
        }
    }
}));

mock.module("@shared/lib/env", () => ({
    env: {
        DISCORD_GUILD_ID: "guild123"
    }
}));

describe("temporaryRoleService", () => {
    beforeEach(() => {
        mockDelete.mockClear();
        mockWhere.mockClear();
        mockFindMany.mockClear();
        mockRemoveRole.mockClear();
        mockFetchMember.mockClear();
        mockFetchGuild.mockClear();

        mockFetchGuild.mockResolvedValue({
            members: {
                fetch: mockFetchMember
            }
        });

        mockFetchMember.mockResolvedValue({
            user: { tag: "TestUser#1234" },
            roles: { remove: mockRemoveRole }
        });
    });

    it("should revoke expired roles and delete timers", async () => {
        // Mock findMany to return an expired role timer
        mockFindMany.mockResolvedValue([
            {
                userId: 123n,
                type: TimerType.ACCESS,
                key: 'role_456',
                expiresAt: new Date(Date.now() - 1000),
                metadata: { roleId: '456' }
            }
        ]);

        const count = await temporaryRoleService.processExpiredRoles();

        expect(count).toBe(1);
        expect(mockFetchGuild).toHaveBeenCalledWith("guild123");
        expect(mockFetchMember).toHaveBeenCalledWith("123");
        expect(mockRemoveRole).toHaveBeenCalledWith("456");
        expect(mockDelete).toHaveBeenCalledWith(userTimers);
    });

    it("should still delete the timer even if member is not found", async () => {
        mockFindMany.mockResolvedValue([
            {
                userId: 999n,
                type: TimerType.ACCESS,
                key: 'role_789',
                expiresAt: new Date(Date.now() - 1000),
                metadata: {}
            }
        ]);

        // Mock member fetch failure
        mockFetchMember.mockRejectedValue(new Error("Member not found"));

        const count = await temporaryRoleService.processExpiredRoles();

        expect(count).toBe(1);
        expect(mockRemoveRole).not.toHaveBeenCalled();
        expect(mockDelete).toHaveBeenCalledWith(userTimers);
    });

    it("should return 0 if no expired timers exist", async () => {
        mockFindMany.mockResolvedValue([]);

        const count = await temporaryRoleService.processExpiredRoles();

        expect(count).toBe(0);
        expect(mockDelete).not.toHaveBeenCalled();
    });
});
