import React from 'react';
import {
    clearModules,
    getModuleTypePolicies,
    initApplicationModule,
    getModuleResourceTypeActions,
} from '../modules';
import { MainContentRoute } from '../types';
import { getRoutes, getRoute } from '../utils';

describe('initApplicationModule', () => {
    beforeEach(() => {
        clearModules();
    });

    test('registers module routes and type policies', () => {
        const name = 'test-module';
        const routes: MainContentRoute[] = [
            { path: '/test1', page: () => <>TEST1</> },
            { path: '/test2', page: () => <>TEST2</> },
        ];

        const typePolicies = {
            test: {},
        };

        initApplicationModule({ name, routes, typePolicies });

        expect(getModuleTypePolicies()).toEqual({
            ...typePolicies,
            Query: { fields: {} },
            Mutation: { fields: {} },
        });

        expect(getRoutes()).toEqual(
            routes.map((route) => ({
                ...route,
                className: name,
                moduleName: name,
            }))
        );
    });

    test('routes can have ids', () => {
        const name = 'test-module';
        const namedRoute = {
            path: '/test1',
            page: () => <>TEST1</>,
            id: 'first',
        };

        const routes: MainContentRoute[] = [namedRoute, { path: '/test2', page: () => <>TEST2</> }];

        initApplicationModule({ name, routes });

        expect(getRoute('second')).toEqual(undefined);
        expect(getRoute('first')).toEqual({
            ...namedRoute,
            className: name,
            moduleName: name,
        });
    });

    test('type policies are shallowly merged', () => {
        const typePolicies1 = {
            test: {},
            Query: {
                fields: {
                    getSomething: {},
                },
            },
            Mutation: {
                fields: {
                    changeSomething: {},
                },
            },
        };

        const typePolicies2 = {
            test: {
                merge: () => {
                    /*noop*/
                },
            },
            test2: {},
            Query: {
                fields: {
                    getRecords: {},
                },
            },
            Mutation: {
                fields: {
                    updateRecord: {},
                },
            },
        };

        initApplicationModule({
            name: 'one',
            routes: [],
            typePolicies: typePolicies1,
        });

        initApplicationModule({
            name: 'two',
            routes: [],
            typePolicies: typePolicies2,
        });

        expect(getModuleTypePolicies()).toEqual({
            ...typePolicies1,
            ...typePolicies2,
            Query: {
                fields: {
                    getSomething: {},
                    getRecords: {},
                },
            },
            Mutation: {
                fields: {
                    changeSomething: {},
                    updateRecord: {},
                },
            },
        });
    });

    test('routes are concatenated', () => {
        const page1 = () => <>home</>;
        const page2 = () => <>about</>;

        const routes1 = [{ path: '/', page: page1 }];
        const routes2 = [
            { path: '/about', page: page2 },
            { path: '/', page: page1 },
        ];

        initApplicationModule({ name: 'one', routes: routes1 });
        initApplicationModule({ name: 'two', routes: routes2 });

        expect(getRoutes()).toEqual([
            { path: '/', page: page1, className: 'one', moduleName: 'one' },
            {
                path: '/about',
                page: page2,
                className: 'two',
                moduleName: 'two',
            },
            { path: '/', page: page1, className: 'two', moduleName: 'two' },
        ]);
    });

    test('routes permissions are inherited and merged', () => {
        const page = () => <>TEST1</>;
        const roles = ['child'];
        const featureFlags = ['child'];

        const routes: MainContentRoute[] = [{ path: '/', page, roles, featureFlags }];

        initApplicationModule({
            name: 'one',
            routes,
            roles: ['parent'],
            featureFlags: ['parent'],
        });

        expect(getRoutes()).toEqual([
            {
                path: '/',
                page,
                className: 'one',
                moduleName: 'one',
                featureFlags: ['parent', 'child'],
                roles: ['parent', 'child'],
            },
        ]);
    });

    test('resourceTypeActions are merged', () => {
        const resourceTypeActions1 = [{ resourceType: 'sound_recording', action: 'create' }];

        const resourceTypeActions2 = [{ resourceType: 'artist', action: 'update' }];

        initApplicationModule({
            name: 'one',
            routes: [],
            resourceTypeActions: resourceTypeActions1,
        });

        initApplicationModule({
            name: 'two',
            routes: [],
            resourceTypeActions: resourceTypeActions2,
        });

        expect(getModuleResourceTypeActions()).toEqual([
            ...resourceTypeActions1,
            ...resourceTypeActions2,
        ]);
    });
});
