import React from 'react';
import { render } from '@testing-library/react';
import { ResourceBrowserContext, ResourceBrowserContextProps, ResourceBrowserContextProvider } from './ResourceBrowserContext';
import { mockSource } from '../__mocks__/MockModels';

describe('ResourceBrowserContext', () => {
    it('Should render with expected default value', () => {
        let defaultContext: ResourceBrowserContextProps | undefined;

        render(
            <ResourceBrowserContext.Consumer>
                {(value) => {
                    defaultContext = value;
                    return null;
                }}
            </ResourceBrowserContext.Consumer>,
        );

        expect(defaultContext).toEqual({
            onRequestSources: expect.any(Function),
            plugins: [],
            searchEnabled: false,
        });
        expect(() => defaultContext?.onRequestSources()).toThrow('onRequestSources has not been configured.');
    });

    it('Should add memoization to data fetching functions', async () => {
        let context: ResourceBrowserContextProps | undefined;
        const sources = [mockSource({ id: '10', type: 'dam' }), mockSource({ id: '20', type: 'dam' })];
        const onRequestSources = jest.fn().mockResolvedValue(sources);

        render(
            <ResourceBrowserContextProvider
                value={{
                    onRequestSources,
                    plugins: [],
                    searchEnabled: false,
                }}
            >
                <ResourceBrowserContext.Consumer>
                    {(value) => {
                        context = value;
                        return null;
                    }}
                </ResourceBrowserContext.Consumer>
            </ResourceBrowserContextProvider>,
        );

        const result = await Promise.all([context?.onRequestSources?.(), context?.onRequestSources?.()]);

        // mocked data should be returned for all invocations of memoized function
        expect(result).toEqual([sources, sources]);

        // memoized function should only be called when different arguments are provided
        expect(onRequestSources).toHaveBeenCalledTimes(1);
    });

    it('Should not cache failures from data fetching functions', async () => {
        let context: ResourceBrowserContextProps | undefined;
        const sources = [mockSource({ id: '10' })];
        const onRequestSources = jest.fn().mockRejectedValueOnce(new Error('Cannot fetch sources.')).mockResolvedValueOnce(sources);

        render(
            <ResourceBrowserContextProvider
                value={{
                    onRequestSources,
                    plugins: [],
                    searchEnabled: false,
                }}
            >
                <ResourceBrowserContext.Consumer>
                    {(value) => {
                        context = value;
                        return null;
                    }}
                </ResourceBrowserContext.Consumer>
            </ResourceBrowserContextProvider>,
        );

        await expect(context?.onRequestSources?.()).rejects.toThrow(new Error('Cannot fetch sources.'));
        await expect(context?.onRequestSources?.()).resolves.toEqual(sources);
        expect(onRequestSources).toHaveBeenCalledTimes(2);
    });
});
