import configureMockStore from 'redux-mock-store';
import { ApolloClient } from 'apollo-client';
import { createEpicMiddleware } from 'redux-observable';
import { InMemoryCache } from 'apollo-cache-inmemory';
// import { ITypeDefinitions, IMocks } from 'graphql-tools';
import createReduxActionInterceptor from './create-redux-action-interceptor';
import createMockSchema from './create-mock-schema';
import createMockLink from './create-mock-link';
import { makeExecutableSchema, addMockFunctionsToSchema, IResolvers, ITypeDefinitions, IMocks } from 'graphql-tools';

const setupReduxApolloStore = (
    apollo: {
        apolloClient?: ApolloClient<any>,
        typeDefs?: ITypeDefinitions,
        apolloMocks?: IMocks,
        resolvers?: IResolvers,
    },
    redux: {
        initialState?: any,
        rootEpic: any,
    },
) => {
    const reduxInterceptor = createReduxActionInterceptor();
    let mockApolloClient;
    if (!apollo.apolloClient) {
        const schema = createMockSchema(apollo.typeDefs, apollo.apolloMocks);
        const { link, flush } = createMockLink(schema);
        const cache = new InMemoryCache({});

        mockApolloClient = new ApolloClient({
            cache,
            link,
        });
    }


    const epicMiddleware = createEpicMiddleware({
        dependencies: {
            apolloClient: apollo.apolloClient || mockApolloClient,
        },
    });



    const store = configureMockStore([
        reduxInterceptor.middleware,
        epicMiddleware,
    ])(redux.initialState);

    epicMiddleware.run(redux.rootEpic);

    const expectActionToBeDispatched = (actionType, timeout = 10) =>
        reduxInterceptor.waitForAction(actionType, timeout);

    const expectActionToBeNotDispatched = (actionType, timeout = 10) =>
        reduxInterceptor.waitForAction(actionType, timeout).then(
            () => {
                throw new Error(`Action ${actionType} was dispatched unexpectedly.`);
            },
            () => { },
        );

    const dispatch = (args) => process.nextTick(() => store.dispatch(args));

    return {
        ...store,
        dispatch,
        // flush,
        expectActionToBeDispatched,
        expectActionToBeNotDispatched,
    };
};

export default setupReduxApolloStore;
