/**
 * Tests for useReferralInteraction hook
 * Tests automatic referral interaction submission
 */

import { vi } from "vitest";

vi.mock("@frak-labs/core-sdk/actions");
vi.mock("../useFrakClient");

import { referralInteraction } from "@frak-labs/core-sdk/actions";
import { renderHook, waitFor } from "@testing-library/react";
import { describe, expect, test } from "../../../tests/vitest-fixtures";
import { useFrakClient } from "../useFrakClient";
import { useReferralInteraction } from "./useReferralInteraction";

describe("useReferralInteraction", () => {
    test("should return processing when client is not available", ({
        queryWrapper,
    }) => {
        vi.mocked(useFrakClient).mockReturnValue(undefined);

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        // Query is disabled when client is not available, status remains pending
        expect(result.current).toBe("processing");
    });

    test("should process referral successfully", async ({
        queryWrapper,
        mockFrakClient,
    }) => {
        vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
        vi.mocked(referralInteraction).mockResolvedValue("success");

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        await waitFor(() => {
            expect(result.current).toEqual("success");
        });

        expect(referralInteraction).toHaveBeenCalledWith(mockFrakClient, {
            options: undefined,
        });
    });

    test("should process referral with options", async ({
        queryWrapper,
        mockFrakClient,
    }) => {
        const options = {
            alwaysAppendUrl: true,
        };

        vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
        vi.mocked(referralInteraction).mockResolvedValue("success");

        const { result } = renderHook(
            () => useReferralInteraction({ options }),
            {
                wrapper: queryWrapper.wrapper,
            }
        );

        await waitFor(() => {
            expect(result.current).toEqual("success");
        });

        expect(referralInteraction).toHaveBeenCalledWith(mockFrakClient, {
            options,
        });
    });

    test("should handle processing state", ({
        queryWrapper,
        mockFrakClient,
    }) => {
        vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);

        // Mock referralInteraction to never resolve (simulate pending)
        vi.mocked(referralInteraction).mockImplementation(
            () => new Promise(() => {})
        );

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        expect(result.current).toBe("processing");
    });

    test("should handle errors", async ({ queryWrapper, mockFrakClient }) => {
        const error = new Error("Referral processing failed");

        vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
        vi.mocked(referralInteraction).mockRejectedValue(error);

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        await waitFor(() => {
            expect(result.current).toEqual(error);
        });
    });

    test("should throw ClientNotFound when client is not available but enabled", async ({
        queryWrapper,
    }) => {
        // Force the query to run despite no client (edge case)
        vi.mocked(useFrakClient).mockReturnValue(undefined);

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        // Query is disabled when client is null, so it stays pending
        expect(result.current).toBe("processing");
    });

    test("should return idle for no-referrer state", async ({
        queryWrapper,
        mockFrakClient,
    }) => {
        vi.mocked(useFrakClient).mockReturnValue(mockFrakClient);
        vi.mocked(referralInteraction).mockResolvedValue(undefined);

        const { result } = renderHook(() => useReferralInteraction(), {
            wrapper: queryWrapper.wrapper,
        });

        await waitFor(() => {
            expect(result.current).toEqual("idle");
        });
    });
});
