import '../../../__mocks__/matchMedia';
import VisualizationService from '../VisualizationService';
import ServiceLocator from '../../ServiceLocator';
import StoreService from '../../../Framework/Services/StoreService';
import { createAppStore } from '../../Store';
import { selectDesignView } from '../../Reducers/DesignView/Actions';
import { receiveDesignerData } from '../../Reducers/Configurator/Actions';

const vs = new VisualizationService();
const textureUpdateInfoObject = { test: 'test value for texture update' };
const textureUpdateInfoObject2 = { test: 'another test value for texture update' };
const updateFn = jest.fn();

describe('Services/VisualizationService', () => {
    test(
        'updateTexture(textureUpdateInfo) stores the data internally if no update handler function registered' +
            'and when the function is added its being called with the stored data',
        () => {
            vs.updateTexture(textureUpdateInfoObject);
            vs.registerTextureUpdateFunction(updateFn);
            expect(updateFn.mock.calls[0][0]).toBe(textureUpdateInfoObject);
        }
    );

    test('after calling registerTextureUpdateFunction the update function should be called directly on updates', () => {
        vs.updateTexture(textureUpdateInfoObject2);
        expect(updateFn.mock.calls[1][0]).toBe(textureUpdateInfoObject2);
    });

    test('testTextureIntersection returns the correct result', () => {
        const filteredDesignAreas = [
            {
                position: {
                    x: 5,
                    y: 5,
                    width: 10,
                    height: 10,
                },
            },
            {
                position: {
                    x: 16,
                    y: 5,
                    width: 10,
                    height: 10,
                },
            },
        ];
        // mock services
        class StoreService {
            static serviceName = 'StoreService';
            observeStore() {}
            get state() {
                return {
                    designArea: {
                        filteredDesignAreas,
                    },
                };
            }
        }
        class DesignDataService {
            static serviceName = 'DesignDataService';
            getDesignAreas() {
                return filteredDesignAreas;
            }
        }
        // add the mock services
        ServiceLocator.provide(new StoreService());
        ServiceLocator.provide(new DesignDataService());

        // it finds the first area
        const area1 = vs.testTextureIntersection({
            x: 6,
            y: 8,
            width: 2048,
            height: 2048,
        });
        expect(area1).toBe(filteredDesignAreas[0]);

        // it finds the second area
        const area2 = vs.testTextureIntersection({
            x: 19,
            y: 8,
            width: 2048,
            height: 2048,
        });
        expect(area2).toBe(filteredDesignAreas[1]);

        // area not found
        const area3 = vs.testTextureIntersection({
            x: 20,
            y: 16,
            width: 2048,
            height: 2048,
        });
        expect(area3).toBe(false);
    });

    // note: the following test is an example for testing store observer callbacks
    test('[INTEGRATION] change of the selected view triggers setView on the visualization component', () => {
        const store = createAppStore();
        const storeService = new StoreService();
        storeService.setStore(store);

        class DesignDataService {
            static serviceName = 'DesignDataService';
            registerDesignAreaListChangeListener = () => {};
        }

        ServiceLocator.provide(new DesignDataService());
        ServiceLocator.provide(storeService);

        const vs = new VisualizationService();
        vs.init();
        const visualizationAdapter = {
            observable: {
                on: () => {},
            },
            setView: jest.fn(),
        };
        vs.setComponent(visualizationAdapter);

        const designViews = [{ identifier: 'view1' }, { identifier: 'view2' }];
        store.dispatch(receiveDesignerData({ designViews }));
        store.dispatch(selectDesignView('view2'));
        expect(visualizationAdapter.setView).toHaveBeenLastCalledWith(designViews[1]);
    });
});
