import * as apollo from '@apollo/client';
import { renderHook } from '@testing-library/react-hooks';
import getBulkSessionQuery from '../GetBulkSessionQuery.gql';
import { useGetBulkSessionQuery } from '../index';

describe('useGetBulkSessionQuery', () => {
    const mockBulkSessionData = {
        getBulkSession: {
            id: 'session-123',
            metadataStatus: 'valid',
            assetStatus: 'transferring',
            downloadLink: 'https://example.com/download',
            vendorUuid: 'vendor-uuid-456',
            subaccountId: 789,
            latestUploadFile: {
                originalFilename: 'test-file.xlsx',
            },
            ingestion: {
                ingestionStatus: null,
            },
            latestAssetTransferJob: {
                jobStatus: 'in_progress',
                totalAssets: 100,
                completedAssets: 50,
            },
        },
    };

    let mockQuery: jest.Mock;

    beforeEach(() => {
        mockQuery = jest.fn();
        jest.spyOn(apollo, 'useApolloClient').mockReturnValue({
            query: mockQuery,
        } as unknown as apollo.ApolloClient<object>);
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    test('uses the correct gql query with proper variables', async () => {
        mockQuery.mockResolvedValue({ data: mockBulkSessionData });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        await queryFn('session-123');

        expect(mockQuery).toHaveBeenCalledWith({
            query: getBulkSessionQuery,
            variables: { input: 'session-123' },
        });
    });

    test('returns transformed session data when getBulkSession exists', async () => {
        mockQuery.mockResolvedValue({ data: mockBulkSessionData });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('session-123');

        expect(response).toEqual({
            metadataStatus: 'valid',
            assetStatus: 'transferring',
            downloadLink: 'https://example.com/download',
            vendorUuid: 'vendor-uuid-456',
            subaccountId: 789,
            originalFilename: 'test-file.xlsx',
            ingestionStatus: null,
            latestAssetTransferJob: {
                jobStatus: 'in_progress',
                totalAssets: 100,
                completedAssets: 50,
            },
        });
    });

    test('returns null when getBulkSession is null', async () => {
        mockQuery.mockResolvedValue({
            data: { getBulkSession: null },
        });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('non-existent-session');

        expect(response).toBeNull();
    });

    test('handles null latestUploadFile gracefully', async () => {
        const dataWithNullUploadFile = {
            getBulkSession: {
                ...mockBulkSessionData.getBulkSession,
                latestUploadFile: null,
            },
        };
        mockQuery.mockResolvedValue({ data: dataWithNullUploadFile });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('session-123');

        expect(response?.originalFilename).toBeUndefined();
    });

    test('handles null ingestion gracefully', async () => {
        const dataWithNullIngestion = {
            getBulkSession: {
                ...mockBulkSessionData.getBulkSession,
                ingestion: null,
            },
        };
        mockQuery.mockResolvedValue({ data: dataWithNullIngestion });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('session-123');

        expect(response?.ingestionStatus).toBeUndefined();
    });

    test('handles null latestAssetTransferJob gracefully', async () => {
        const dataWithNullAssetTransferJob = {
            getBulkSession: {
                ...mockBulkSessionData.getBulkSession,
                latestAssetTransferJob: null,
            },
        };
        mockQuery.mockResolvedValue({ data: dataWithNullAssetTransferJob });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('session-123');

        expect(response?.latestAssetTransferJob).toEqual({
            jobStatus: undefined,
            totalAssets: undefined,
            completedAssets: undefined,
        });
    });

    test('handles all nullable fields being null', async () => {
        const dataWithAllNulls = {
            getBulkSession: {
                id: 'session-123',
                metadataStatus: null,
                assetStatus: null,
                downloadLink: null,
                vendorUuid: null,
                subaccountId: null,
                latestUploadFile: null,
                ingestion: null,
                latestAssetTransferJob: null,
            },
        };
        mockQuery.mockResolvedValue({ data: dataWithAllNulls });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        const response = await queryFn('session-123');

        expect(response).toEqual({
            metadataStatus: null,
            assetStatus: null,
            downloadLink: null,
            vendorUuid: null,
            subaccountId: null,
            originalFilename: undefined,
            ingestionStatus: undefined,
            latestAssetTransferJob: {
                jobStatus: undefined,
                totalAssets: undefined,
                completedAssets: undefined,
            },
        });
    });

    test('can be called multiple times with different IDs', async () => {
        mockQuery.mockResolvedValue({ data: mockBulkSessionData });

        const { result } = renderHook(() => useGetBulkSessionQuery());
        const queryFn = result.current;

        await queryFn('session-1');
        await queryFn('session-2');

        expect(mockQuery).toHaveBeenCalledTimes(2);
        expect(mockQuery).toHaveBeenNthCalledWith(1, {
            query: getBulkSessionQuery,
            variables: { input: 'session-1' },
        });
        expect(mockQuery).toHaveBeenNthCalledWith(2, {
            query: getBulkSessionQuery,
            variables: { input: 'session-2' },
        });
    });
});
