/*Person Constructor
Переделайте задание createPerson на функцию конструктор Person.
const a = new Person("Вася", "Пупкин")
const b = new Person("Анна", "Иванова")
const c = new Person("Елизавета", "Петрова")

console.log(a.getFullName()) //Вася Пупкин
a.fatherName = 'Иванович'    //Вася Иванович Пупкин

console.log(b.getFullName()) //Анна Иванова
Для этого методы и свойства заносите не в создаваемый объект, а в this внутри конструктора.*/

{
    const a = new Person("Вася", "Пупкин")
    const b = new Person("Анна", "Иванова")
    const c = new Person("Елизавета", "Петрова")

    console.log(a.getFullName()) //Вася Пупкин
    a.fatherName = 'Иванович'    //Вася Иванович Пупкин

    console.log(b.getFullName()) //Анна Иванова

    function Person(name, surname) {

        this.name = name,
        this.surname = surname,
        this.getFullName = () => `${this.name} ${this.fatherName || ""} ${this.surname}`
    }

}

/*Person Prototype
Переделайте предыдущее задание, вынеся методы в прототип. Для этого вместо присвоения в this занесите их в объект Person.prototype. После этой переделки все должно работать по старому:
const a = createPerson("Вася", "Пупкин")
const b = createPerson("Анна", "Иванова")
const c = createPerson("Елизавета", "Петрова")

console.log(a.getFullName()) //Вася Пупкин
a.fatherName = 'Иванович'    //Вася Иванович Пупкин

console.log(b.getFullName()) //Анна Иванова*/

{
    const a = new Person("Вася", "Пупкин")
    const b = new Person("Анна", "Иванова")
    const c = new Person("Елизавета", "Петрова")

    console.log(a.getFullName()) //Вася Пупкин
    a.fatherName = 'Иванович'    //Вася Иванович Пупкин
    console.log(a.getFullName())
    console.log(b.getFullName()) //Анна Иванова

    function Person(name, surname) {
        Person.prototype.getFullName = function () { return `${this.name} ${this.fatherName || ""} ${this.surname}` }

        this.name = name
        this.surname = surname
    }
}


/*Store (код работает в index.html)
        Переделайте функцию createStore (та, которая хранилище Redux) на конструктор Store. Прототип не используйте; оставьте переменные state, cbs и reducer замкнутыми. Соответственно методы subscribe, dispatch и getState должны быть объявлены внутри функции-конструктора и не могут быть в прототипе. Проверьте переделанный конструктор на вашем ДЗ по ларьку;*/

{
    function reducer(state, { type, productName, productQuantity, summ }) { //объект action деструктуризируется на три переменных
        if (!state) { //начальная уборка в ларьке:
            return {
                пиво: {
                    quantity: 100,
                    price: 30,
                },
                чипсы: {
                    quantity: 100,
                    price: 52,
                },
                сиги: {
                    quantity: 100,
                    price: 89,
                },
                касса: 0
            }
        }
        if (type === 'КУПИТЬ' && productQuantity <= state[productName].quantity && summ >= state[productName].price * productQuantity) { //если тип action - КУПИТЬ, то:
            return {
                ...state, //берем все что было из ассортимента
                [productName]: {
                    quantity: state[productName].quantity - productQuantity,
                    price: state[productName].price
                },
                касса: state.касса + state[productName].price * productQuantity
                //и уменьшаем то, что покупается на количество
            }
        }

        return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
    }

        /*Store (код работает в index.html)
    Переделайте функцию createStore (та, которая хранилище Redux) на конструктор Store. Прототип не используйте; оставьте переменные state, cbs и reducer замкнутыми. Соответственно методы subscribe, dispatch и getState должны быть объявлены внутри функции-конструктора и не могут быть в прототипе. Проверьте переделанный конструктор на вашем ДЗ по ларьку;*/


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

        this.getState = () => state //функция, возвращающая переменную из замыкания + добавление функции getState в результирующий объект
        this.dispatch = action => {
            const newState = reducer(state, action) //пробуем запустить редьюсер
            if (newState !== state) { //проверяем, смог ли редьюсер обработать action
                state = newState //если смог, то обновляем state 
                for (let cb of cbs) cb() //и запускаем подписчиков
            }
        }
        this.subscribe = cb => (cbs.push(cb),   //запоминаем подписчиков в массиве
            () => cbs = cbs.filter(c => c !== cb)) //добавление subscribe в объект

    }

    function actionCreator(type, productName, productQuantity, summ) {
        return {
            type,
            productName,
            productQuantity,
            summ
        }
    }

    const store = new createStore(reducer)
    myState = store.getState()

    const showcase = document.createElement('section')
    document.body.append(showcase)
    showcase.classList.add('showcase')

    const orderSection = document.createElement('section')
    document.body.append(orderSection)
    orderSection.classList.add('orderSection')

    const orderSelectProd = document.createElement('select')
    orderSection.append(orderSelectProd)

    const orderInputQuantity = document.createElement('input')
    orderInputQuantity.type = 'number'
    orderInputQuantity.min = '0'
    orderSection.append(orderInputQuantity)

    const orderInputQuantityName = document.createElement('div')
    orderInputQuantity.before(orderInputQuantityName)
    orderInputQuantityName.innerText = 'количество товара:'

    const orderSendMoney = document.createElement('input')
    orderSendMoney.type = 'number'
    orderSendMoney.min = '0'
    orderSection.append(orderSendMoney)

    const orderSendMoneyName = document.createElement('div')
    orderSendMoney.before(orderSendMoneyName)
    orderSendMoneyName.innerText = 'сумма:'

    const orderBuyButton = document.createElement('input')
    orderBuyButton.type = 'button'
    orderBuyButton.value = 'КУПИТЬ'
    orderSection.append(orderBuyButton)
    orderBuyButton.onclick = () => { store.dispatch(actionCreator(orderBuyButton.value, orderSelectProd.value, +orderInputQuantity.value, +orderSendMoney.value)) }


    for (const elemProduct in store.getState()) {
        if (elemProduct === 'касса') continue

        const productCard = document.createElement('div')
        const productName = document.createElement('h2')
        const productPrice = document.createElement('div')
        const productQuantity = document.createElement('div')

        productCard.append(productName)
        productCard.append(productQuantity)
        productCard.append(productPrice)
        showcase.append(productCard)

        productCard.classList.add('productCard')
        productName.classList.add('productName')
        productPrice.classList.add('productPrice')
        productQuantity.classList.add('productQuantity')

        productName.innerText = elemProduct
        productPrice.innerText = store.getState()[elemProduct].price + ' грн'
        productQuantity.innerText = store.getState()[elemProduct].quantity + ' шт\nв наличии'

        const selectProdOption = document.createElement('option')
        selectProdOption.value = selectProdOption.innerText = elemProduct
        orderSelectProd.append(selectProdOption)
        const productPriceUnsubscribe = store.subscribe(() => {
            productPrice.innerText = store.getState()[elemProduct].price + ' грн'
        })
        const productQuantityUnsubscribe = store.subscribe(() => {
            productQuantity.innerText = store.getState()[elemProduct].quantity + ' шт\nв наличии'
        })

    }
}

/*Password*/
/*Password*/
{
    function Password(parent, open) {

        const inputPass = document.createElement('input')
        parent.append(inputPass)
        const checkboxPass = document.createElement('input')
        checkboxPass.type = 'checkbox'
        parent.append(checkboxPass)
        
        this.setValue = (value) => {
            inputPass.value = value
            if (typeof this.onChange === 'function') this.onChange() // запускается по событию oninput в поле ввода, передает текст в колбэк
        }      //задает значение
        this.getValue = () => inputPass.value                   //читает значение
        this.setOpen = (open) => {
            if (open) {
                checkboxPass.checked = true
                inputPass.type = "text"
            }
            if (!open) {
                checkboxPass.checked = false
                inputPass.type = "password"
            }
            if (typeof this.onOpenChange === 'function') this.onOpenChange() // запускается по изменению состояния открытости пароля
        } //задает открытость текста в поле ввода
        this.getOpen = () => checkboxPass.checked //читает открытость текста в поле ввода

        this.setOpen(open)
        inputPass.oninput = () => this.onChange(this.getValue())
        checkboxPass.oninput = () => this.setOpen(this.getOpen())

    }

    let p = new Password(document.body, true)

    p.onChange = data => console.log(data)
    p.onOpenChange = open => console.log(open)

    p.setValue('qwerty')
    console.log(p.getValue())

    p.setOpen(false)
    console.log(p.getOpen())
}
/*
Напишите функцию конструктор Password, которая будет в родительском элементе создавать поле ввода для пароля и кнопку/иконку/чекбокс, который будет переключать режим просмотра пароля в поле ввода. (видимый пароль или нет, input type='text' или же input type='password')
Параметры:
parent - родительский элемент
open - стартовое состояние
Методы:
setValue/getValue - задают/читают значения
setOpen/getOpen - задают/читают открытость текста в поле ввода
Колбэки (функции обратного вызова, который возможно, будут заданы снаружи конструктора):
onChange - запускается по событию oninput в поле ввода, передает текст в колбэк
onOpenChange - запускается по изменению состояния открытости пароля
*/

/* LoginForm
С помощью предыдущего кода Password сделайте форму логина, кнопка в которой будет активна только если и login и пароль не пусты.
"С помощью предыдущего кода" значит что в коде формы логина вы используете объект, сконструированный конструктором Password - const password = new Password(........) */


{
    function Password(parent, open) {

        const inputPass = document.createElement('input')
        parent.append(inputPass)

        const checkboxPass = document.createElement('input')
        checkboxPass.type = 'checkbox'
        parent.append(checkboxPass)

        this.setValue = (value) => {
            inputPass.value = value
            if (typeof this.onChange === 'function') this.onChange() // запускается по событию oninput в поле ввода, передает текст в колбэк
        }      //задает значение
        this.getValue = () => inputPass.value                   //читает значение
        this.setOpen = (open) => {
            if (open) {
                checkboxPass.checked = true
                inputPass.type = "text"
            }
            if (!open) {
                checkboxPass.checked = false
                inputPass.type = "password"
            }
            if (typeof this.onOpenChange === 'function') this.onOpenChange() // запускается по изменению состояния открытости пароля
        } //задает открытость текста в поле ввода
        this.getOpen = () => checkboxPass.checked //читает открытость текста в поле ввода

        this.setOpen(open)
        inputPass.oninput = () => this.onChange(this.getValue())
        checkboxPass.oninput = () => this.setOpen(this.getOpen())

    }

    const LoginForm = document.createElement('div')
    document.body.append(LoginForm)

    const inputLogin = document.createElement('input')
    LoginForm.append(inputLogin)

    let p = new Password(LoginForm, false)
    
    const inputButton = document.createElement('input')
    inputButton.type = 'button'
    inputButton.value = 'войти'
    LoginForm.append(inputButton)
    inputButton.disabled = true

    p.onChange = () => checkButtonDisabled()
    inputLogin.oninput = () => checkButtonDisabled()

    function checkButtonDisabled () {
        if (p.getValue() && inputLogin.value) inputButton.disabled = false
        else inputButton.disabled = true
    }
}

/*LoginForm Constructor
оформите предыдущую задачу как функцию-конструктор. Продумайте и предусмотрите геттеры, сеттеры и колбэки.*/

{
    function LoginForm(parent, passOpenDefault){
        function Password(parent, open) {

            const inputPass = document.createElement('input')
            parent.append(inputPass)
    
            const checkboxPass = document.createElement('input')
            checkboxPass.type = 'checkbox'
            parent.append(checkboxPass)
    
            this.setValue = (value) => {
                inputPass.value = value
                if (typeof this.onChange === 'function') this.onChange() // запускается по событию oninput в поле ввода, передает текст в колбэк
            }      //задает значение
            this.getValue = () => inputPass.value                   //читает значение
            this.setOpen = (open) => {
                if (open) {
                    checkboxPass.checked = true
                    inputPass.type = "text"
                }
                if (!open) {
                    checkboxPass.checked = false
                    inputPass.type = "password"
                }
                if (typeof this.onOpenChange === 'function') this.onOpenChange() // запускается по изменению состояния открытости пароля
            } //задает открытость текста в поле ввода
            this.getOpen = () => checkboxPass.checked //читает открытость текста в поле ввода
    
            this.setOpen(open)
            inputPass.oninput = () => this.onChange(this.getValue())
            checkboxPass.oninput = () => this.setOpen(this.getOpen())
    
        }
    
        const LoginForm = document.createElement('div')
        parent.append(LoginForm)
    
        const inputLogin = document.createElement('input')
        LoginForm.append(inputLogin)
    
        let p = new Password(LoginForm, passOpenDefault)
        
        const inputButton = document.createElement('input')
        inputButton.type = 'button'
        inputButton.value = 'войти'
        LoginForm.append(inputButton)
        inputButton.disabled = true
    
        p.onChange = () => checkButtonDisabled()
        inputLogin.oninput = () => checkButtonDisabled()
    
        function checkButtonDisabled () {
            if (p.getValue() && inputLogin.value) inputButton.disabled = false
            else inputButton.disabled = true
        }

        this.getLogin = () => inputLogin.value
        this.setLogin = (value) => {
            inputLogin.value = value
            checkButtonDisabled()

        }
        this.getPass = () => p.getValue()
        this.setPass = (value) => {
            p.setValue(value)
            checkButtonDisabled()
        }
        
        inputButton.onclick = () => {
        if (typeof this.inputButtonOnclick === 'function') this.inputButtonOnclick() //функция при нажатии на кнопку войти
        }
    }

    const t = new LoginForm (document.body, false)
    t.setPass("1111")
    t.setLogin("Абырвалг")
    t.inputButtonOnclick = () => alert ('заходи - не бойся, выходи - не плачь')
}

/*Password Verify
С помощью Password сделайте пару инпутов, которые проверяют введеный пароль (в двух полях ввода) на совпадение. Подсвечивайте поля красным цветом/бордером когда пароли не совпадают При открытом пароле в первом поле ввода (которое реализуется с помощью объекта класса Password второе поле вводы должно пропадать с экрана Таким образом:
Когда Password в скрытом режиме - появляется второй инпут (<input type='password'>) с паролем в скрытом режиме
Когда Password в открытом режиме - второй инпут пропадает*/

