function createStore(reducer) {
    let state = reducer(undefined, {})
    let cbs = []
    function dispatch(action) {
        if (typeof action === 'function') {
            return action(dispatch)
        }
        const newState = reducer(state, action)
        if (state !== newState) {
            state = newState
            cbs.forEach(cb => cb())
        }
    }
    return {
        dispatch,
        subscribe(cb) {
            cbs.push(cb)
            return () => cbs = cbs.filter(c => c !== cb)
        },
        getState() {
            return state
        }
    }
}
function promiseReducer(state = {}, { type, status, payload, error, name }) {
    if (type === 'PROMISE') {
        return {
            ...state,
            [name]: { status, payload, error }
        }
    }
    return state
}


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

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 delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))

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

const getGQL = url => {
    return (query, variables) => {
        return fetch(url, {
            method: 'POST',
            headers: {
                "content-type": "application/json",
                ...(localStorage.authToken ? { Authorization: "Bearer " + localStorage.authToken } : {})
            },
            body: JSON.stringify({ query, variables }),
        }).then(res => res.json())
    }
}

let shopGQL = getGQL('http://shop-roles.asmer.fs.a-level.com.ua/graphql')

let categoryById = async (id) => {
    let query = `query fndcategory($id: String) {
        CategoryFind(query: $id){
          name goods{
              _id name price images {
                  url
              }
          }
        }
      }`

    let qVariables = {
        "id": JSON.stringify([{ "_id": id }])
    }

    let res = await shopGQL(query, qVariables)
    console.log(res)
    return res
}

let goodById = async (id) => {
    let query = `query fndgood($id: String) {
        GoodFind(query: $id){
          name description price images {
              url
          }
        }
      }`

    let qVariables = {
        "id": JSON.stringify([{ "_id": id }])
    }

    let res = await shopGQL(query, qVariables)
    return res
}

let newOrder = async (obj) => {
    let option = Object.entries(obj);
    let orderGoods = [];

    for (let key of option) {
        let i = {
            "count": key[1],
            "good": { "_id": key[0] }
        }
        orderGoods.push(i);
    }

    let query = `mutation sndOrder($order: OrderInput) {
       OrderUpsert(order: $order) {
         _id createdAt total
       }
     }`

    let qVariables = {
        "order": {
            "orderGoods": orderGoods
        }
    }

    let res = await shopGQL(query, qVariables)
    console.log(res)
    return res
}

const actionRootCategories = () =>
    actionPromise('rootCategories', shopGQL(`
            query cats($query:String){
              CategoryFind(query:$query){
                _id name 
              }
            }
        `, { query: JSON.stringify([{ parent: null }]) }))

const actionCategoryById = id => actionPromise('catById', categoryById(id))

const actionGoodById = id => actionPromise('goodById', goodById(id))

const actionBuyGood = (obj) => actionPromise('newOrder', newOrder(obj))

// const actionGoodOrder = (obj) => actionPromise('newOrderGood', newOrderGood(obj))

store.dispatch(actionRootCategories())

window.onhashchange = () => {
    let { 1: route, 2: id } = location.hash.split('/')
    if (route === 'categories') {
        store.dispatch(actionCategoryById(id))
    }

    if (route === 'good') {
        store.dispatch(actionGoodById(id))
    }
}

function drawMainMenu() {
    let cats = store.getState().rootCategories.payload
    if (cats) { //каждый раз дорисовываются в body
        aside.innerText = ''
        for (let { _id, name } of cats.data.CategoryFind) {
            let catA = document.createElement('a')
            catA.href = `#/categories/${_id}`
            catA.innerText = name
            aside.append(catA)
        }
    }
}

store.subscribe(drawMainMenu)

store.subscribe(() => {
    const { 1: route, 2: id } = location.hash.split('/')
    if (route === 'categories') {
        const catById = store.getState().catById?.payload
        if (catById) {
            while (main.lastChild) {
                main.lastChild.remove()
            }

            let categoryName = document.createElement("h2")
            let cards = document.createElement("div")
            cards.className = "cards"
            categoryName.textContent = catById.data.CategoryFind[0].name

            for (let key of catById.data.CategoryFind[0].goods) {
                cardDraw(key, cards)
            }
            main.append(categoryName, cards)
        }
    }
    if (route === 'good') {
        const goodById = store.getState().goodById?.payload
        if (goodById) { //вывести в main страницу товара
            while (main.lastChild) {
                main.lastChild.remove()
            }
            goodDraw(goodById.data.GoodFind[0], main)
            let count = document.createElement("input")
            count.type = "number"
            count.min = 1
            count.value = 1
            let goodBtnBox = document.createElement("div")
            let btn1 = document.createElement("button")
            let btn2 = document.createElement("button")
            goodBtnBox.style.display = "flex"
            goodBtnBox.style.alignItems = "center"
            btn1.textContent = "Купить"
            btn2.textContent = "В корзину"
            goodBtnBox.append(count, btn2, btn1)
            main.lastChild.append(goodBtnBox)
            let value = 1;

            count.oninput = () => value = +count.value

            let order = {
                [id]: value
            }

            btn1.onclick = () => {
                store.dispatch(actionBuyGood(order))
            }
            /* btn2.onclick = () => {
                 store.dispatch(actionGoodOrder(order))
             } */
        }
    }
})

let goodDraw = (obj, parent) => {
    let box = document.createElement("div")
    let goodName = document.createElement("h2")
    let goodIMG = document.createElement("img")
    let description = document.createElement("p")
    let price = document.createElement("span")

    price.textContent = "Цена: " + obj.price + "грн"
    goodIMG.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url
    box.style.width = "40%"
    box.style.margin = "20px"
    box.style.display = "flex"
    box.style.flexDirection = "column"
    goodName.textContent = obj.name
    description.textContent = obj.description

    box.append(goodIMG, goodName, description, price)
    parent.append(box)
}

let cardDraw = (obj, parent) => {
    let box = document.createElement("div");
    let img = document.createElement("img");
    let price = document.createElement("span");
    let productName = document.createElement("h5");

    img.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url;
    productName.textContent = obj.name
    price.textContent = "Цена: " + obj.price + " грн"

    let productBody = document.createElement("div")
    box.className = "card"
    productBody.append(productName, price)
    box.append(img, productBody)
    let a = document.createElement("a")
    a.href = "#/good/" + obj._id
    a.append(box)
    parent.append(a)
}