// url of backend
const url = 'http://shop-roles.node.ed.asmer.org.ua/graphql'

// Вспомогательные функции ========================================================================================================
// getGql - переделка из HW18 функции gql (делаем запрос на бэк)
function getGql(endpoint) {
    return async function gql(query, variables = {}) {

        let headers = {
            'Content-Type': 'application/json;charset=utf-8',
            'Accept': 'application/json',
        }
        if (('authToken' in localStorage)) {
            headers.Authorization = 'Bearer ' + localStorage.authToken
        }

        let result = await fetch(endpoint, {
            method: 'POST',
            headers,
            body: JSON.stringify({
                query,
                variables
            })
        }).then(res => res.json())

        if (('errors' in result) && !('data' in result)) {
            throw new Error(JSON.stringify(result.errors))
        }

        result = Object.values(result.data)[0]

        return result
    }
}

const gql = getGql(url)

//=========================================================================================================
// localStoredReducer
function localStoredReducer(originalReducer, localStorageKey) {
    function wrapper(state, action) {
        if (!state) {
            try {
                return JSON.parse(localStorage[localStorageKey])
            }
            catch (error) {

            }
        }
        const newState = originalReducer(state, action)
        localStorage[localStorageKey] = JSON.stringify(newState)

        return newState
    }

    return wrapper
}


// Redux ========================================================================================================
// createStore
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,
        dispatch,
        subscribe
    }
}

// создание  combineReducers
function combineReducers(reducers) {
    function totalReducer(state = {}, action) {
        const newTotalState = {}
        for (const [reducerName, reducer] of Object.entries(reducers)) {
            const newSubState = reducer(state[reducerName], action)
            if (newSubState !== state[reducerName]) {
                newTotalState[reducerName] = newSubState
            }
        }
        if (Object.keys(newTotalState).length) {
            return { ...state, ...newTotalState }
        }
        return state
    }

    return totalReducer
}

// создание promiseReducer
function promiseReducer(state = {}, { type, status, payload, error, nameOfPromise }) {
    if (type === 'PROMISE') {
        return {
            ...state,
            [nameOfPromise]: { status, payload, error }
        }
    }
    return state
}

// акшоны для promiseReducer
const actionPending = nameOfPromise => ({ nameOfPromise, type: 'PROMISE', status: 'PENDING' })

const actionFulfilled = (nameOfPromise, payload) => ({ nameOfPromise, type: 'PROMISE', status: 'FULFILLED', payload })

const actionRejected = (nameOfPromise, error) => ({ nameOfPromise, type: 'PROMISE', status: 'REJECTED', error })

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

// authReducer
// раскодируем JWT-токен
const jwtDecode = function (token) {
    try {
        let parseData = token.split('.')[1]
        return JSON.parse(atob(parseData))
    }
    catch (e) {
        return undefined
    }
}

function authReducer(state = {}, { type, token }) {
    if (type === 'AUTH_LOGIN') {

        let payload = jwtDecode(token)

        return state = {
            token,
            payload
        }
    }

    if (type === 'AUTH_LOGOUT') {
        localStorage.removeItem('authToken')
        return {}
    }

    return state
}

// акшон для логинизации
const actionAuthLogin = token => ({ type: 'AUTH_LOGIN', token })

// акшон для раззлогинивания
const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })

// cartReducer
function cartReducer(state = {}, { type, count, good }) {
    if (type === 'CART_ADD') {

        return {
            ...state,
            [good._id]: {
                good,
                count: (state[good._id] ? state[good._id].count + count : count)
            }
        }

    }

    if (type === 'CART_SUB') {
        if (state[good._id]) {
            let newCount = state[good._id].count - count

            if (newCount > 0) {
                return {
                    ...state,
                    [good._id]: {
                        good,
                        count: newCount
                    }
                }
            } else {
                delete state[good._id]
                return { ...state }
            }

        } else {
            return undefined
        }
    }

    if (type === 'CART_DEL') {
        delete state[good._id]
        return { ...state }
    }

    if (type === 'CART_SET') {
        if (count > 0) {
            return {
                ...state,
                [good._id]: {
                    good,
                    count
                }
            }
        } else {
            delete state[good._id]
            return { ...state }
        }
    }

    if (type === 'CART_CLEAR') {
        return {}
    }

    return state
}

// акшоны для cartReducer
// Добавление товара.Должен добавлять новый ключ в state, или обновлять, если ключа в state ранее не было, увеличивая количество
const actionCartAdd = (good, count = 1) => ({ type: 'CART_ADD', good, count })

// Уменьшение количества товара.Должен уменьшать количество товара в state, или удалять его если количество будет 0 или отрицательным
const actionCartSub = (good, count = 1) => ({ type: 'CART_SUB', count, good })

// Удаление товара.Должен удалять ключ из state
const actionCartDel = (good) => ({ type: 'CART_DEL', good })

// Задание количества товара.В отличие от добавления и уменьшения, не учитывает того количества, которое уже было в корзине, а тупо назначает количество поверху(или создает новый ключ, если в корзине товара не было).Если count 0 или отрицательное число - удаляем ключ из корзины;
const actionCartSet = (good, count = 1) => ({ type: 'CART_SET', count, good })

// Очистка корзины.state должен стать пустым объектом { }
const actionCartClear = () => ({ type: 'CART_CLEAR' })

// объект со всеми редьюсерами
const reducers = {
    promise: localStoredReducer(promiseReducer, 'promise'),
    auth: localStoredReducer(authReducer, 'auth'),
    cart: localStoredReducer(cartReducer, 'cart'),
}

const totalReducer = combineReducers(reducers)

const store = createStore(totalReducer)
store.subscribe(() => console.log(store.getState()))  // для контроля выводим все изменения в магазине в консоль


// GraphQL запросы переписанные сразу в акшоны ========================================================================================================
// Запрос на список корневых категорий (без родителей)
const actionCategoryFind = () => actionPromise('CategoryFind', gql(`query baseCategory($searchVariablesCategory: String){
        CategoryFind(query: $searchVariablesCategory){
            _id name parent {
                _id
                name
            }
        }
    }`, {
    searchVariablesCategory: JSON.stringify([{ parent: null }])
}))

store.dispatch(actionCategoryFind()) // и сразу же все запустили, чтоб постоянно отрисовывалась

// Запрос для получения одной категории с товарами и картинками
const actionCategoryFindOne = _id => actionPromise('CategoryFindOne', gql(`query categoryFindOne($searchVariablesCategoryOne: String,) {
        CategoryFindOne(query: $searchVariablesCategoryOne){
      _id name  
        goods{
        _id name  description price 
        images{
                    url
                }
            }
      subCategories{
        _id name
            }
        }
    }`, {
    searchVariablesCategoryOne: JSON.stringify([{ _id }])
}))

// Запрос на получение товара с описанием и картинками
const actionGoodFindOne = _id => actionPromise('GoodFindOne', gql(`query oneGoodWithImages($searchVariablesGoodOne: String) {
        GoodFindOne(query: $searchVariablesGoodOne){
        _id name price description images {
                url
            }
        }
    }`, {
    searchVariablesGoodOne: JSON.stringify([{ _id }])
}))

// Запрос на логин
const actionLogin = (login, password) => actionPromise('login', gql(`query login($login: String, $password: String) {
        login(login: $login, password: $password)
    }`, {
    login,
    password
}))

// показываем ошибку при авторизации, если неправильный логин или пароль
function mistakeLogin() {
    main.innerHTML = `<p style="color: red;">Вы ввели неправильный логин или пароль</p>
    <button id='refreshBtn'>Повторить попытку</button>`

    const refresh = document.getElementById('refreshBtn')
    refresh.addEventListener('click', () => {
        location.reload()
    })
}

// Запрос на логин и последующую логинизацию в authReduser (thunk)
const actionFullLogin = (login, password) =>
    async dispatch => {
        const token = await dispatch(actionLogin(login, password))

        if (token != null) {
            if (typeof (token) === 'string') {
                dispatch(actionAuthLogin(token))
                localStorage.authToken = token
            }
        } else {
            mistakeLogin()
        }
    }

// Запрос на регистрацию
const actionUserCreate = (login, password) => actionPromise('UserRegistrate', gql(`mutation registration($login:String,$password:String ){
  UserUpsert(user:{
    login:$login, password:$password
  }){
    _id createdAt
  }
}`, {
    login,
    password
}))

// показываем ошибку при регистрации, если логин занят
function mistakeRegistration() {
    main.innerHTML = `<p style="color: red;">Этот логин занят. Повторите регистрацию с уникальным логином или <a href="#/login/">авторизуйтесь</a></p>
    <button id='refreshBtn'>Повторить попытку</button>`

    const refresh = document.getElementById('refreshBtn')
    refresh.addEventListener('click', () => {
        location.reload()
    })
}

// Запрос на регистрацию и сразу на авторизацию пользователя на странице (thunk)
const actionFullUserCreate = (login, password) =>
    async dispatch => {
        try {
            const registration = await dispatch(actionUserCreate(login, password))
            if (registration._id !== 'null') {
                dispatch(actionFullLogin(login, password))
            }
        }
        catch (e) {
            mistakeRegistration()
        }
    }

// Запрос истории заказов
const actionOrderFind = () => actionPromise('OrderFind', gql(`query order($order: String){
            OrderFind(query: $order){
      createdAt total orderGoods{
        good {
            name price images {
                url
            }
        }
               total  count
                }
            }
        }`, {
    order: JSON.stringify([{}])
}))

// запрос отправку заказа на сервер
const actionOrder = (goods) => actionPromise('orderCreate', gql(`mutation myOrder($createOrder: OrderInput){
OrderUpsert(order: $createOrder) {
     orderGoods{
       count good{
                 _id
                     }
                 }
             }
         }`, {
    createOrder: { orderGoods: goods }
}))

// запрос отправку заказа на сервер с последующей очисткой корзины (thunk)
const actionFillOrder = () =>
    async dispatch => {

        // создаем массив с параметрами для диспатча
        let arrWithGoods = []
        for (const [id, { count }] of Object.entries(store.getState().cart)) {
            arrWithGoods.push({ count: count, good: { _id: id } })
        }

        // оформляем заказ
        await dispatch(actionOrder(arrWithGoods))

        // и как задиспатчится заказ чистим корзину
        store.dispatch(actionCartClear())
    }


// Модуль =========================================================================================================
// отрисовка в main списка товаров из категории 
const drawGoods = () => {
    const [, route] = location.hash.split('/')
    if (route !== 'category') return

    const { status, payload, error } = store.getState().promise.CategoryFindOne
    if (status === 'PENDING') {
        main.innerHTML = `<img src='https://cdn.dribbble.com/users/63485/screenshots/1309731/infinite-gif-preloader.gif'/>`
    }
    if (status === 'FULFILLED') {
        const { _id, name, goods, subCategories } = payload  // подумать, нужны ли ид и субкатегория (субкатегория может ыть нужна, чтобы отрисовать ее в )

        main.innerHTML = `<h1>Категория: ${name}</h1>`

        // рисуем блок для субкатегорий
        const drawSubCat = document.createElement('div')
        drawSubCat.id = 'drawSubCat'
        main.append(drawSubCat)

        // отрисовываем карточки категорий
        // тут проблема. в айфонах subCategories из-за этого вот так с проверкой
        if (subCategories != null) {
            for (const { _id, name } of subCategories) {
                drawSubCat.innerHTML += `<div class="goodListCart" id='drawSubCatBtn'>
            <h2>${name}</h2>
            <a href="#/category/${_id}">Подробнее</a>
            </div>`
            }
        }

        // рисуем блок для товаров в категории
        const goodsList = document.createElement('div')
        goodsList.id = 'goodList'
        main.append(goodsList)

        // отрисовываем карточку товара в разделе категорий
        if (goods != null) {
            for (const { name, description, images, price, _id } of goods) {  // удалить description из запроса и из отрисовки
                let img = url.slice(0, -7) + images[0].url
                goodsList.innerHTML += `
            <div class="goodListCart">
            <img src ="${img}" >
            <h2>${name}</h2>
            <p>Цена: ${price} грн.</p>
            <a href="#/good/${_id}">Подробнее</a>
            </div>`
            }
        }
    }
}
store.subscribe(drawGoods)

// отрисовка товара после нажатия на карточку товара
const drawGoodOne = () => {
    const [, route] = location.hash.split('/')
    if (route !== 'good') return

    const { status, payload, error } = store.getState().promise.GoodFindOne
    if (status === 'PENDING') {
        main.innerHTML = `<img src='https://cdn.dribbble.com/users/63485/screenshots/1309731/infinite-gif-preloader.gif'/>`
    }
    if (status === 'FULFILLED') {
        const { _id, name, description, price, images } = payload

        let img = url.slice(0, -7) + images[0].url

        main.innerHTML = `<img src="${img}">
        <h1>${name}</h1>
        <h2>Цена: ${price} грн./шт.</h2>
        <h3>Описание:</h3>
        <p>${description}</p>
        
        <div id=''>
        <label for="lname">Количество товара</label><br>
        <input type="number" min="0" value="0" id="addToCartInput" name="lname"><br><br>
        <input id="addToCartBtn" type="submit" value="Добавить в корзину" disabled="true">
        </div>`

        // включаем кнопку "добавить товар", только если указали количество товара
        addToCartInput.addEventListener('change', () => {
            if (addToCartInput.value == 0) {
                addToCartBtn.disabled = true
            } else {
                addToCartBtn.disabled = false
            }

            // addToCartBtn.disabled = (addToCartInput.value == 0 || false)  // или можно написать вот так эту проверку
        })

        // Добавляем товар в корзину по клику кнопки "добавить"
        addToCartBtn.addEventListener('click', () => {
            store.dispatch(actionCartAdd({ _id, name, description, price, img }, +addToCartInput.value))
        })



    }
}
store.subscribe(drawGoodOne)

//отрисовка истории заказов пользователя
const history = () => {
    const [, route] = location.hash.split('/')
    if (route !== 'history') return

    const { status, payload, error } = store.getState().promise.OrderFind
    if (status === 'PENDING') {
        main.innerHTML = `<img src='https://cdn.dribbble.com/users/63485/screenshots/1309731/infinite-gif-preloader.gif'/>`
    }
    if (status === 'FULFILLED') {
        main.innerHTML = `<h1>История заказов</h1>`
        for (const { createdAt, total, orderGoods } of payload) {
            const orderFindCart = document.createElement('div')
            orderFindCart.classList = 'orderFindCart'
            main.append(orderFindCart)

            // формируем дату создания поста
            const dateOfOrder = new Date(+createdAt)
            const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']

            const dateOfOrderParse = `${dateOfOrder.getDate() < 10 ? '0' + dateOfOrder.getDate() : dateOfOrder.getDate()} ${months[dateOfOrder.getMonth()]} ${dateOfOrder.getFullYear()}  ${dateOfOrder.getHours()}:${dateOfOrder.getMinutes() < 10 ? '0' + dateOfOrder.getMinutes() : dateOfOrder.getMinutes()}`

            orderFindCart.innerHTML = `
                <p>Создано: ${dateOfOrderParse}</p>
                <h2>Сумма заказа: ${total} тугриков</h2>`

            for (const { good: { name, price, images }, count, total } of orderGoods) {
                let img = url.slice(0, -7) + images[0].url

                orderFindCart.innerHTML += `<div class="orderFindCart">
                <img src ="${img}">             
                <div class="orderFindCartDescription">
                <p>Товар: ${name}</p>
                <p>Цена товара: ${price}</p>
                <p>Количество товара в заказе: ${count}</p>
                <p>Итоговая сумма: ${total}</p>
                </div>
                </div>`
            }
        }
    }
}
store.subscribe(history)

// отрисовываем левое меню
const leftMenu = () => {
    const { status, payload, error } = store.getState().promise.CategoryFind
    if (status === 'FULFILLED' && payload) {
        aside.innerHTML = ''
        aside.innerHTML = `<a href="/">Главная</a>`
        for (const { _id, name } of payload) {
            aside.innerHTML += `<a href="#/category/${_id}">${name}</a>`
        }
    }
}
store.subscribe(leftMenu)

// изменение цифры количества товаров в корзине (в красном лейбле)
const redLabel = () => {
    let goodCount = 0
    for (let { count } of Object.values(store.getState().cart)) {
        goodCount += count
    }

    document.getElementById('cartIcon').textContent = goodCount
}
store.subscribe(redLabel)

// подписчик для отображения залогинен или нет пользователь, а также для отображения страниц регистрации и логинизации в шапке
const userStatus = () => {
    if (!(store.getState().auth.payload?.sub?.login)) {
        login.innerHTML = `<a href ="#/login/">Авторизоваться</a></br>
        <a href ="#/register/">Зарегистрироваться</a></br>`
    } else {
        login.innerHTML = `Привет, ${store.getState().auth.payload?.sub?.login}</br>
        <a href="#/history/">История заказов</a></br>
        <a href="" id="logout">Выйти</a>`

        logout.onclick = () => {
            store.dispatch(actionAuthLogout())

        }
    }
}
store.subscribe(userStatus)

// функция для страницы корзины. из-за тго, что очень массивная страница с большим функционалом, отрисовывааем ее отдельно
function cartPage() {

    const [, route] = location.hash.split('/')
    if (route !== 'cart') return

    if (Object.keys(store.getState().cart).length !== 0) {

        main.innerHTML = '<h1>Корзина</h1>'

        // подсчитываем сумму всего заказа (изначально при входе в корзину)
        let summ = 0
        for (const { count, good: { price } } of Object.values(store.getState().cart)) {
            summ += (count * price)
        }

        // создаем с помощью цикла карточки товаров в заказе
        for (const [id, { count, good: { description, img, name, price, _id } }] of Object.entries(store.getState().cart)) {

            const goodInCart = document.createElement('div')
            goodInCart.id = "goodInCart"
            goodInCart.innerHTML = `<h2>${name}</h2>`
            main.append(goodInCart)

            const goodInCartContent = document.createElement('div')
            goodInCartContent.id = 'goodInCartContent'
            goodInCart.append(goodInCartContent)

            const goodInCartIimg = document.createElement('div')
            goodInCartIimg.id = 'goodInCartIimg'
            goodInCartIimg.innerHTML = `<img src="${img}">`
            goodInCartContent.append(goodInCartIimg)

            const goodInCartIDescription = document.createElement('div')
            goodInCartIDescription.id = 'goodInCartIDescription'
            goodInCartContent.append(goodInCartIDescription)

            // рисуем кнопки на карточке товара
            //кнопка удаления
            const delBtn = document.createElement('button')
            delBtn.innerHTML = '-'
            goodInCartIDescription.append(delBtn)

            const goodInCartValue = document.createElement('input')
            goodInCartValue.id = 'goodInCartValue'
            goodInCartValue.value = count
            goodInCartIDescription.append(goodInCartValue)

            // кнопка добавления
            const addBtn = document.createElement('button')
            addBtn.innerHTML = '+'
            goodInCartIDescription.append(addBtn)

            // создаем блок с кнопками управления
            const blockWithButtons = document.createElement('div')
            goodInCartIDescription.append(blockWithButtons)

            //кнопка универсального добавления товара
            const cartSetBtn = document.createElement('button')
            cartSetBtn.innerHTML = 'Добавить товар'
            blockWithButtons.append(cartSetBtn)

            // кнопка удаления товара из корзины
            const cartDelBtn = document.createElement('button')
            cartDelBtn.innerHTML = 'Удалить товар'
            blockWithButtons.append(cartDelBtn)

            const goodInCartAbout = document.createElement('p')
            goodInCartAbout.innerHTML = `Описание: ${description}.</br></br>Цена за ед. ${price} тугриков.`
            goodInCartIDescription.append(goodInCartAbout)

            const goodInCartFullPrice = document.createElement('p')
            goodInCartFullPrice.innerHTML = `Итоговая стоимость за товар: ${count * price} тугриков`
            // goodInCartFullPrice.innerHTML = `Итоговая стоимость за товар: ${store.getState().cart[_id].count * price} тугриков`
            goodInCartIDescription.append(goodInCartFullPrice)

            // блок колбеков на кнопках
            // коллбек на кнопку +
            addBtn.addEventListener('click', async () => {
                await store.dispatch(actionCartAdd({ _id, name, description, price, img }))

                const newCount = store.getState().cart[_id].count
                goodInCartValue.value = newCount

                // изменяем стоимость на карточке товара
                goodInCartFullPrice.innerHTML = `Итоговая стоимость за товар: ${newCount * price} тугриков`
            })

            // коллбек на кнопку -
            delBtn.addEventListener('click', async () => {
                await store.dispatch(actionCartSub({ _id, name, description, price, img }))

                // прверяем, если после этого товара не осталось (удалили последний товар), перерисовываем страницу. если товар еще есть в заказе, просто понимажем его счетчик
                if (store.getState().cart[_id]) {

                    const newCount = store.getState().cart[_id].count
                    goodInCartValue.value = newCount

                    // изменяем стоимость карточки
                    goodInCartFullPrice.innerHTML = `Итоговая стоимость за товар: ${newCount * price} тугриков`
                } else {
                    cartPage()
                }
            })

            // коллбек на кнопку "Добавить товар"
            cartSetBtn.addEventListener('click', async () => {

                const newCount = goodInCartValue.value

                // проверяем число на 0 или больше
                if (newCount > 0) {
                    await store.dispatch(actionCartSet({ _id, name, description, price, img }, +newCount))

                    // изменяем стоимость карточки
                    goodInCartFullPrice.innerHTML = `Итоговая стоимость за товар: ${newCount * price} тугриков`

                    // изменяем общую сумму заказа
                    // cartOrderFullPrice.innerHTML = `Сумма заказа: ${summ} тугриков`
                } else {
                    await store.dispatch(actionCartDel({ _id }))

                    // и сразу обновляем страницу корзины
                    cartPage()
                }
            })

            // коллбек на кнопку "Удалить товар"
            cartDelBtn.addEventListener('click', async () => {
                await store.dispatch(actionCartDel({ _id }))

                // и сразу обновляем страницу корзины
                cartPage()
            })
        }

        // отрисовываем блок под карточками товаров с общей стоимостью покупки и кнопками "Оформить заказ" и "Очистить корзину"
        const cartOrderFullPrice = document.createElement('p')
        cartOrderFullPrice.innerHTML = `Общая сумма заказа: ${summ} тугриков`
        main.append(cartOrderFullPrice)

        const cartOrderCreate = document.createElement('button')
        cartOrderCreate.id = 'cartOrderCreateBtn'
        cartOrderCreate.innerHTML = 'Оформить заказ'
        main.append(cartOrderCreate)

        const breakLine = document.createElement('br')
        main.append(breakLine)

        const cartClean = document.createElement('button')
        cartClean.innerHTML = 'Очистить корзину'
        main.append(cartClean)

        // коллбек на кнопку очистки корзины
        cartClean.addEventListener('click', async () => {
            await store.dispatch(actionCartClear())

            // и сразу обновляем страницу корзины
            cartPage()
        })

        // коллбек на кнопку оформления заказа
        cartOrderCreate.addEventListener('click', async () => {
            await store.dispatch(actionFillOrder())

            // и сразу обновляем страницу корзины
            cartPage()
        })

        // подписчик для изменения отображения на странице корзины
        const summFinally = () => {
            // просчитываем полную сумму заказа
            let summ = 0
            for (const { count, good: { price } } of Object.values(store.getState().cart)) {
                summ += (count * price)
            }

            // меняем общую стоимость заказа при изменении стора
            cartOrderFullPrice.innerHTML = `Сумма заказа: ${summ} тугриков`
        }
        store.subscribe(summFinally)

    } else {
        main.innerHTML = `<p>Ваша корзина пуста.Чтобы сделать заказ, сначала добавьте товары.</p>`
    }
}

// функция - конструктор формы логин/пароль =========================================================================================================
function LoginForm(parent) {
    function Password(parent, open) {
        // отображение формы для пароля
        const inputPassword = document.createElement('input')
        inputPassword.type = 'password'
        inputPassword.placeholder = 'Insert password'
        parent.append(inputPassword)

        // создание и отображение чекбокса (открыть/скрыть пароль)
        const inputCheckbox = document.createElement('input')
        inputCheckbox.type = 'checkbox'
        inputCheckbox.checked = false
        parent.append(inputCheckbox)

        // создаем геттеры
        this.getValue = () => inputPassword.value
        this.getOpen = () => inputCheckbox.checked

        // создаем сеттеры
        this.setValue = (value) => inputPassword.value = value
        this.setOpen = (open) => {
            if (open === true) {
                inputPassword.type = 'text'
                inputCheckbox.checked = true
            }
            if (open === false) {
                inputPassword.type = 'password'
                inputCheckbox.checked = false
            }
            return inputPassword.type, inputCheckbox.checked
        }

        // starting onChange
        inputPassword.addEventListener('input', () => {
            this.onChange(inputPassword.value)
        })

        // starting onOpenChange + change inputPasswor hide/see
        inputCheckbox.addEventListener('change', () => {
            this.setOpen(inputCheckbox.checked)
            this.onOpenChange(inputCheckbox.checked)
        })
    }

    function Login(parent) {
        // создаем и отрысовываем поле для ввода логина
        const inputLogin = document.createElement('input')
        inputLogin.type = 'text'
        inputLogin.placeholder = 'Insert login'
        parent.append(inputLogin)

        // создаем геттеры
        this.getValue = () => inputLogin.value

        // создаем сеттеры
        this.setValue = (value) => inputLogin.value = value

        // starting onChange
        inputLogin.addEventListener('input', () => {
            this.onChange(inputLogin.value)
        })
    }

    // создание и отрисовывание формы для логина/пароля
    // const form = document.createElement('form')  // если формируем форму, а не обычный див, тогда не работает запрос и появляется в адресной строке "?" после домена в урле
    const form = document.createElement('div')
    parent.append(form)

    const loginLabel = document.createElement('label')
    loginLabel.innerText = 'Login:'
    form.append(loginLabel)

    let breakSymbol = document.createElement('br')
    form.append(breakSymbol)

    // отрисовываем поле логина
    const login = new Login(form)

    breakSymbol = document.createElement('br')
    form.append(breakSymbol)

    const passwordLabel = document.createElement('label')
    passwordLabel.innerText = 'Password:'
    form.append(passwordLabel)

    breakSymbol = document.createElement('br')
    form.append(breakSymbol)

    // отрисовываем поле для пароля
    const password = new Password(form, true)

    breakSymbol = document.createElement('br')
    form.append(breakSymbol)

    // создание и отрисовывание кнопки для входа
    const confirmBtn = document.createElement('button')
    confirmBtn.innerText = 'Confirm'
    confirmBtn.id = 'confirmBtn'
    confirmBtn.type = 'submit'
    confirmBtn.style.marginTop = '10px'
    confirmBtn.disabled = true
    form.append(confirmBtn)

    // change confirmBtn.disabled
    function checkButton() {
        if (login.getValue() !== '' && password.getValue() !== '') {
            confirmBtn.disabled = false
        } else {
            confirmBtn.disabled = true
        }
        return confirmBtn.disabled
    }
    checkButton()

    // listening password and login
    login.onChange = password.onChange = checkButton

    // create getters
    this.getPasswordValue = () => password.getValue()
    this.getPasswordOpen = () => password.getOpen()
    this.getLoginValue = () => login.getValue()
    this.getButtonStatus = () => confirmBtn.disabled

    // create setters
    this.setPasswordValue = (value) => password.setValue(value)
    this.setLoginValue = (value) => login.setValue(value)
    this.setPasswordOpen = (status) => password.setOpen(status)

    // create callbacks
    this.onOpenChange = open => password.onOpenChange = open
}

// проверяем, что сейчас находится в урле и, исходя из приставки в урле, запускаем нужную функцию
window.onhashchange = () => {
    const [, route, _id] = location.hash.split('/')

    const routes = {
        category() {
            store.dispatch(actionCategoryFindOne(_id))
        },
        good() {
            store.dispatch(actionGoodFindOne(_id))
        },
        login() {
            if (!localStorage.authToken) { // если пользователь залогинен, то ему больше не рисовать форму логина
                main.innerHTML = '<h2>Авторизуйтесь</h2>'
                //нарисовать форму логина, которая по нажатию кнопки Login делает store.dispatch(actionFullLogin(login, password))
                const logForm = new LoginForm(main)

                confirmBtn.addEventListener('click', async () => {
                    localStorage.removeItem('authToken') // на всякий случай (а нужно ли?) удаляю старый authToken перед регистрацией
                    await store.dispatch(actionFullLogin(logForm.getLoginValue(), logForm.getPasswordValue()))
                    // if (store.getState().promise.login.payload != null) {
                    if ((Object.keys(store.getState().auth)).length) {
                        main.innerHTML = `<h2>С возвращением, ${logForm.getLoginValue()}!<h2>`
                    }
                })
            }
        },
        register() {
            if (!localStorage.authToken) { // если пользователь залогинен, то ему больше не отображать страницу регистрации (не рисовать форму)
                main.innerHTML = `<h2>Зарегистрируйтесь</h2>`
                // Запрос на регистрацию. Страница # / register /.В onhashchange НЕ происходит dispatch, вместо этого рисуется форма логина из предыдущих ДЗ, по логину же происходит dispatch
                const regForm = new LoginForm(main)

                confirmBtn.addEventListener('click', async () => {
                    localStorage.removeItem('authToken') // на всякий случай (а нужно ли?) удаляю старый authToken перед регистрацией
                    await store.dispatch(actionFullUserCreate(regForm.getLoginValue(), regForm.getPasswordValue()))
                    if ((Object.keys(store.getState().auth)).length) {
                        main.innerHTML = `<h2>Поздравляем, регистраций прошла успешно!<h2>`
                    }
                })
            }
        },
        history() {
            store.dispatch(actionOrderFind())
        },
        cart() {
            if (localStorage.authToken) { // если пользователь авторизован - показываем корзину, если нет - предлагаем авторизоваться!
                cartPage()
            } else {
                main.innerHTML = `<h1> Корзина</h1>
                <p>Для просмотра корзины Вам необходимо авторизоваться!</p>
                <a href="#/login/">Авторизация</a>`
            }
        }
    }

    if (route in routes) {
        routes[route]()
    }
}

window.onhashchange()



// 3. разобраться с тем, почему корзина хуйней страдает
// 6. сonst form = document.createElement('form')  // если формируем форму, а не обычный див на логине, тогда не работает запрос и появляется в адресной строке "?" после домена в урле
