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 => { 
        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 reducer(state, {type, ШО, СКОКА, БАБОС}){ //объект action деструктуризируется на три переменных
    if (!state){ //начальная уборка в ларьке:
        return {
            // пиво: 100, //{count: 100, price: 30}
            // чипсы: 100,//{count: 100, price: 25}
            пиво: {count: 100, price: 30},
            чипсы: {count: 100, price: 25},
            сиги: {count: 100, price: 50},
            касса: 0, //при покупках увеличивается
        }
    }
    if (type === 'КУПИТЬ' && 
        state[ШО] && СКОКА > 0 &&
        СКОКА <= state[ШО].count && БАБОС >= state[ШО].price * СКОКА){ //если тип action - КУПИТЬ, то:
        //проверить на:
        //наличие товара как такового (есть ли ключ в объекте)
        //количество денег в action
        //наличие нужного количества товара.
        //и только при соблюдении этих условий обновлять state.
        console.log('bang')
        console.log(store.getState())
        state.касса += truncateFraction(+БАБОС)
        display_hide_error(arguments[1])
        return {
            ...state, //берем все что было из ассортимента
            [ШО]: {count: state[ШО].count - Math.floor(СКОКА), price: state[ШО].price },//и уменьшаем то, что покупается на количество
        }
    }
    display_hide_error(arguments[1])
    return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
}

const store = createStore(reducer)
//надо бы напилить цикл, который в select напихивает ассортимент. 
//возможно, если вы собираетесь выводить (и обновлять) количество,
//это надо делать где в subscribe, иначе оно не будет обновлять количество
let select = document.getElementById('goods')
for(let key in store.getState()) {
    if (key === 'касса') continue;
    let option = document.createElement('option')
    option.innerText = key
    option.value = key
    select.append(option)
}
let quantity = document.getElementById('quantity')
let cash = document.getElementById('cash')



const купи = (ШО, СКОКА, БАБОС) => ({type: 'КУПИТЬ', ШО, СКОКА, БАБОС})

buy.onclick = () => {
    //достает выбранный товар и количество из DOM
//    store.dispatch(купи(....,....))
    store.dispatch(купи(select.value, quantity.value, cash.value))
}

//запомнит функцию во внутреннем массиве cbs. 
//она будет запущена при любом успешном dispatch 
const unsubscribe = store.subscribe(() => console.log(store.getState())) 

//setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например

//происходит запуск редьюсера, который создает новый state. 
//dispatch запускает всех подписчиков из массива cbs
let errorP = document.createElement('p')
errorP.style.color = 'red'
errorP.style.textAlign = 'center'
shop.append(errorP)

function truncateFraction (number) {
    try {
        let strNum = String(number).split('.')
        if(strNum[1].length > 2) {
            strNum[1] = strNum[1].slice(0, 2)
        }
        return Number(strNum.join('.'))
    } catch (e) {
        return number
    }
}

function display_hide_error(obj) {
    errorP.innerText = ''
    if (obj.СКОКА === '' && obj.БАБОС === '') {
        errorP.innerText = 'Мысли я читать не умeю >:^['
        return;
    } else if(obj.СКОКА === '' || obj.СКОКА < 0) {
        errorP.innerText = 'А единиц товара сколько брать будете?'
        return;
    }

    if (obj.СКОКА > store.getState()[obj.ШО].count) {
        errorP.innerText = `У нас нет столько ${obj.ШО}. ${obj.ШО} осталось ${store.getState()[obj.ШО].count}`
        return;
    } else if (obj.БАБОС < store.getState()[obj.ШО].price * obj.СКОКА) {
        errorP.innerText = `Недостаточно денег для покупки ${obj.СКОКА} ед. ${obj.ШО}.
        ${obj.ШО} стоит ${store.getState()[obj.ШО].price} денег за 1 ед. товара
        Стоимость вашего заказа ${store.getState()[obj.ШО].price * obj.СКОКА}`
        return;
    }
}

let table = document.createElement('table')
function drawTable(){
    table.innerHTML = ''
    table.insertAdjacentHTML('afterbegin', `
        <tr>
            <th>Товар</th>
            <th>Кол-во</th>
            <th>Стоимость</th>
        </tr>
    `)
    
    for(let key in store.getState()) {
        if(key === 'касса') continue;
        let tr = document.createElement('tr')
        let tdKey = document.createElement('td')
        let tdCount = document.createElement('td')
        let tdCost = document.createElement('td')
        tdKey.innerText = key
        tdCount.innerText = store.getState()[key].count
        tdCost.innerText = `${store.getState()[key].price} денег`
        tr.append(tdKey, tdCount, tdCost)
        table.append(tr)
    }
    table.insertAdjacentHTML('beforeend', `
        <tr>
            <th>Касса</th>
            <td>${store.getState().касса} денег</td>
        </tr>
    `)
    shop.append(table)
}
drawTable()
store.subscribe(drawTable)
console.log(store.getState())
