<header>reducers</header>

<body>
    <div id="testDiv">
        Test
    </div>

    <script>
        function promiseReducer(state = {}, action) {                   // диспетчер обработки
            if (action) {
                if (action.type === 'PROMISE') {
                    let newState = { ...state };
                    newState[action.name] = { status: action.status, payload: action.payload, error: action.error };
                    return newState;
                }
            }
            return state;
        }

        function createStore(reducer) {
            let state = reducer(undefined, {})              //стартовая инициализация состояния, запуск редьюсера со state === undefined
            let cbs = []                                      //массив подписчиков

            const getState = () => state                   //функция, возвращающая переменную из замыкания
            const subscribe = cb => (cbs.push(cb),            //запоминаем подписчиков в массиве
                () => cbs = cbs.filter(c => c !== cb))      //возвращаем функцию unsubscribe, которая удаляет подписчика из списка

            function dispatch(action) {
                if (typeof action === 'function') {         //если action - не объект, а функция
                    return action(dispatch, getState)       //запускаем эту функцию и даем ей dispatch и getState для работы
                }
                const newState = reducer(state, action)      //пробуем запустить редьюсер
                if (newState !== state) {                    //проверяем, смог ли редьюсер обработать action
                    state = newState                        //если смог, то обновляем state 
                    for (let cb of cbs) cb()                //и запускаем подписчиков
                }
            }

            return {
                getState,                                   //добавление функции getState в результирующий объект
                dispatch,
                subscribe                                   //добавление subscribe в объект
            }
        }

        function actionPromise(name, promise) {
            return async function Exec(dispatch) {
                dispatch(actionPending(name))               //сигнализируем redux, что промис начался
                try {
                    const payload = await promise           //ожидаем промиса;
                    dispatch(actionFulfilled(name, payload)); //сигнализируем redux, что промис успешно выполнен
                    return payload                              //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
                }
                catch (error) {
                    dispatch(actionRejected(name, error))           //в случае ошибки - сигнализируем redux, что промис несложился
                }
            };
        }

        const actionPending = (name) => ({ type: 'PROMISE', name: name, status: 'PENDING' });
        const actionFulfilled = (name, payload) => ({ type: 'PROMISE', name: name, payload: payload, status: 'FULFILLED' });
        const actionRejected = (name, error) => ({ type: 'PROMISE', name: name, error: error, status: 'REJECTED' });

        const store = createStore(promiseReducer);

        store.subscribe(() => {
            console.log(store.getState())
        });

        store.dispatch(actionPromise('luke', fetch("https://swapi.dev/api/people/1").then(res => res.json())))


        //let execFunc = actionPromise({ name: "auth", promise: signIn("test457", "123123", "http://shop-roles.node.ed.asmer.org.ua/graphql") });
       // store.dispatch(execFunc);

        /*
                const actionPending = () => ({ type: 'PROMISE', status: 'PENDING' })
                const actionFulfilled = payload => ({ type: 'PROMISE', status: 'FULFILLED', payload })
                const actionRejected = error => ({ type: 'PROMISE', status: 'REJECTED', error })
        
        
                store.subscribe(() => console.log(store.getState()))
        
                store.dispatch({ type: 'COUNTER_INC' })
                store.dispatch({ type: 'BOOLEAN_SET' })
                store.dispatch({ type: 'COUNTER_INC' })
                store.dispatch({ type: 'BOOLEAN_TOGGLE' })
                store.dispatch({ type: 'COUNTER_DEC' })
                store.dispatch({ type: 'ДИЧЬ' }) //не вызывает подписчика
        */

    </script>
</body>