/**
 * Unit tests for partner branding service
 */
import { getPartnerBranding, clearBrandingCache, PartnerBranding } from "./partnerBranding";

// Mock fetch globally
global.fetch = jest.fn();

describe("partnerBranding", () => {
    beforeEach(() => {
        // Clear cache before each test
        clearBrandingCache();
        // Clear all mocks
        jest.clearAllMocks();
    });

    describe("getPartnerBranding", () => {
        it("should fetch partner branding from API successfully", async () => {
            const mockBranding: PartnerBranding = {
                partnerCode: "sfl",
                logoUrl: "https://example.com/logo.png",
                primaryColor: "#1a5f7a",
                backgroundColor: "#f5f5f5",
                companyName: "Surefire Local",
                companyWebsite: "https://surefire.com",
            };

            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: {
                        public: {
                            partnerBranding: mockBranding,
                        },
                    },
                }),
            });

            const result = await getPartnerBranding("sfl");

            expect(result).toEqual(mockBranding);
            expect(global.fetch).toHaveBeenCalledWith(
                "https://api.xapp.ai/graphql",
                expect.objectContaining({
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                })
            );
        });

        it("should return null when partner not found", async () => {
            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: {
                        public: {
                            partnerBranding: null,
                        },
                    },
                }),
            });

            const result = await getPartnerBranding("unknown");

            expect(result).toBeNull();
        });

        it("should return null when GraphQL returns errors", async () => {
            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    errors: [{ message: "Partner not found" }],
                }),
            });

            const result = await getPartnerBranding("unknown");

            expect(result).toBeNull();
        });

        it("should return null when HTTP request fails", async () => {
            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: false,
                status: 500,
                statusText: "Internal Server Error",
            });

            const result = await getPartnerBranding("sfl");

            expect(result).toBeNull();
        });

        it("should return null when fetch throws an error", async () => {
            (global.fetch as jest.Mock).mockRejectedValueOnce(new Error("Network error"));

            const result = await getPartnerBranding("sfl");

            expect(result).toBeNull();
        });

        it("should cache successful results", async () => {
            const mockBranding: PartnerBranding = {
                partnerCode: "sfl",
                logoUrl: "https://example.com/logo.png",
                primaryColor: "#1a5f7a",
                backgroundColor: "#f5f5f5",
                companyName: "Surefire Local",
                companyWebsite: "https://surefire.com",
            };

            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: {
                        public: {
                            partnerBranding: mockBranding,
                        },
                    },
                }),
            });

            // First call
            const result1 = await getPartnerBranding("sfl");
            expect(result1).toEqual(mockBranding);
            expect(global.fetch).toHaveBeenCalledTimes(1);

            // Second call should use cache
            const result2 = await getPartnerBranding("sfl");
            expect(result2).toEqual(mockBranding);
            expect(global.fetch).toHaveBeenCalledTimes(1); // Still 1, not called again
        });

        it("should cache null results to avoid repeated failed requests", async () => {
            (global.fetch as jest.Mock).mockResolvedValueOnce({
                ok: true,
                json: async () => ({
                    data: {
                        public: {
                            partnerBranding: null,
                        },
                    },
                }),
            });

            // First call
            const result1 = await getPartnerBranding("unknown");
            expect(result1).toBeNull();
            expect(global.fetch).toHaveBeenCalledTimes(1);

            // Second call should use cache
            const result2 = await getPartnerBranding("unknown");
            expect(result2).toBeNull();
            expect(global.fetch).toHaveBeenCalledTimes(1); // Still 1, not called again
        });

        it("should clear cache when clearBrandingCache is called", async () => {
            const mockBranding: PartnerBranding = {
                partnerCode: "sfl",
                logoUrl: "https://example.com/logo.png",
                primaryColor: "#1a5f7a",
                backgroundColor: "#f5f5f5",
                companyName: "Surefire Local",
                companyWebsite: "https://surefire.com",
            };

            (global.fetch as jest.Mock).mockResolvedValue({
                ok: true,
                json: async () => ({
                    data: {
                        public: {
                            partnerBranding: mockBranding,
                        },
                    },
                }),
            });

            // First call
            await getPartnerBranding("sfl");
            expect(global.fetch).toHaveBeenCalledTimes(1);

            // Clear cache
            clearBrandingCache();

            // Second call should fetch again
            await getPartnerBranding("sfl");
            expect(global.fetch).toHaveBeenCalledTimes(2); // Called twice now
        });
    });
});
