import { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';

import { RootState } from '../types/redux.types';
import { useStaticValue } from '../util/hooks-helpers';
import { rootReducer } from './reducers';
import { initialRootState } from './state';
import { useStoreWatchers } from './watchers';

export const useChonkyStore = (chonkyInstanceId: string) => {
    const store = useStaticValue(() => {
        const preloadedState: RootState = {
            ...initialRootState,
            instanceId: chonkyInstanceId,
        };

        return configureStore({
            preloadedState: preloadedState as any,
            reducer: rootReducer,
            middleware: getDefaultMiddleware =>
                getDefaultMiddleware({
                    serializableCheck: false,
                }),
            devTools: { name: `chonky_${chonkyInstanceId}` },
        });
    });
    useStoreWatchers(store);
    return store;
};

/**
 * Hook that can be used with parametrized selectors.
 */
export const useParamSelector = <Args extends Array<any>, Value>(
    parametrizedSelector: (...args: Args) => (state: RootState) => Value,
    ...selectorParams: Args
) => {
    const selector = useCallback(
        (state: RootState) => parametrizedSelector(...selectorParams)(state),
        // eslint-disable-next-line
        [parametrizedSelector, ...selectorParams]
    );
    return useSelector(selector);
};

/**
 * DTE - DispatchThunkEffect. This method is used to decrease code duplication in
 * main Chonky method.
 */
export const useDTE = <Args extends Array<any>>(actionCreator: (...args: Args) => any, ...selectorParams: Args) => {
    const dispatch = useDispatch();
    useEffect(
        () => {
            dispatch(actionCreator(...selectorParams));
        },
        // eslint-disable-next-line
        [dispatch, actionCreator, ...selectorParams]
    );
};

export const usePropReduxUpdate = <Payload extends any>(actionCreator: (payload: Payload) => any, payload: Payload) => {
    const dispatch = useDispatch();
    useEffect(() => {
        dispatch(actionCreator(payload));
    }, [dispatch, actionCreator, payload]);
};
