
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, которая удаляет подписчика из списка
                             
    const 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 promiseReducer(state={}, {type, status, payload, error, name}) {
    if (!state) { 
        return {}
            //{ login: {status, payload, error},
            //  catById: {status, payload, error}
            //}
    }

    if (type === 'PROMISE') {         
        return {
            ...state,
            [name]: {
                status: status,
                payload : payload,
                error: error,
            }
        }
    }
    return state
}

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

const store = createStore(promiseReducer)
store.subscribe(() => console.log(store.getState()))


// const delay = (ms) => new Promise((ok) => setTimeout(() => ok(ms), ms))

// store.dispatch(actionPending('delay1000'))
// delay(1000).then(data => store.dispatch(actionResolved('delay1000', data)),
//                  error => store.dispatch(actionRejected('delay1000', error)))

// store.dispatch(actionPending('delay2000'))
// delay(2000).then(data => store.dispatch(actionResolved('delay2000', data)),
//                  error => store.dispatch(actionRejected('delay2000', error)))


const actionPromise = (name, promise) => 
async dispatch => {
    dispatch(actionPending(name))
    try { 
        let data = await promise
        dispatch(actionResolved(name, data))
        return data
    }
    catch(error){
        dispatch(actionRejected(name, error))
    }
}

const getGQL = url =>
  async (query, variables={}) => {
    // try {
      let obj = await fetch(url, {
        method: 'POST',
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ query, variables })
      })
      let a = await obj.json()
      if (!a.data && a.errors) {
          throw new Error(JSON.stringify(a.errors))
      } else {
          return a.data[Object.keys(a.data)[0]]
      }      
    // }
    // catch (error) {
    //   console.log('Что-то не так, Бро ' + error);
    // }
  }

  const backURL = 'http://shop-roles.asmer.fs.a-level.com.ua/'

  const gql = getGQL(backURL + 'graphql');


  const actionRootCats = () => 
  actionPromise('rootCats', gql(`query {
      CategoryFind(query: "[{\\"parent\\":null}]"){
          _id name
      }
  }`))

const actionCatById = (_id) =>  //добавить подкатегории
  actionPromise('catById', gql(`query catById($q: String){
      CategoryFindOne(query: $q){
          _id name goods {
              _id name price images {
                  url
              }
          }
          subCategories {
              _id name 
          }
      }
  }`, {q: JSON.stringify([{_id}])}))

//actionGoodById по аналогии

const actionGoodById = (_id) => 
  actionPromise('goodById', gql(`query goodById($q: String) {
      GoodFindOne(query: $q) {
          _id name price description images {
            url
          }
        }
  }`, {q: JSON.stringify([{_id}])}))


  
store.dispatch(actionRootCats())

store.subscribe(() => {
    const {rootCats} = store.getState()
    if (rootCats?.payload) {
        aside.innerHTML = ''
        for (const {_id, name} of rootCats?.payload) {
            const link = document.createElement('a')
            link.href = `#/category/${_id}`
            link.innerText = name
            aside.append(link)
        }
    }
})


// location.hash - адресная строка после решетки
window.onhashchange = () => {
    const [,route, _id] = location.hash.split('/')

    const routes = {
        category(){
            store.dispatch(actionCatById(_id))
            console.log('страница категорий')           
        },
        good(){ //задиспатчить actionGoodById
            store.dispatch(actionGoodById(_id))
            console.log('страница товара')                
        },
    }
    if (route in routes)
        routes[route]()
}

window.onhashchange()

store.subscribe(() => {
    const {catById} = store.getState()
    const [,route, _id] = location.hash.split('/')
    if (catById?.payload && route === 'category'){
        const {name} = catById.payload;
        main.innerHTML =    `<h1>${name}</h1>`
      
        if (catById.payload.subCategories) {
            for(const {_id, name} of catById.payload.subCategories) {
                const link      = document.createElement('a');
                link.href       = `#/category/${_id}`;
                link.innerText  = name;
                main.append(link);
            }
        }
        
        if (catById.payload.goods) {
            for (const {_id, name, price, images} of catById.payload.goods){
                const card      = document.createElement('div')
                card.innerHTML = `<h2>${name}</h2>
                                  <img src="${backURL}/${images[0].url}" />
                                  <strong>${price}</strong>
                                  <br>
                                  <a href="#/good/${_id}">Перейти на страницу товара</a>
                                    `
                main.append(card)
            }
        }
    }
})

store.subscribe(() => {
    const {goodById} = store.getState();
    const [,route, _id] = location.hash.split('/');
    if (goodById?.payload && route === 'good') {
        main.innerHTML = '';
        const {_id, name, images, price, description}  = goodById.payload;
            const card = document.createElement('div');
            card.innerHTML = `<h2>${name}</h2>
                            <img src="${backURL}/${images[0].url}" />
                            <strong>${price}</strong>
                            <h2>${description}</h2>
                            `;
            main.append(card);
        }
    }
    //ТУТ ДОЛЖНА БЫТЬ ПРОВЕРКА НА НАЛИЧИЕ goodById в редакс
    //и проверка на то, что сейчас в адресной строке адрес ВИДА #/good/АЙДИ
    //в таком случае очищаем main и рисуем информацию про товар с подробностями
)

// store.dispatch(actionPromise('delay1000', delay(1000)))
// store.dispatch(actionPromise('delay2000', delay(2000)))     
// store.dispatch(actionPromise('luke', fetch('https://swapi.dev/api/people/1/').then(res => res.json())))


















