// password
function Password(parent, open=false) {
    let _isVisible = open
    let _value = ''
    let input = document.createElement('input')
    input.placeholder = 'password'

    let wrapper = document.createElement('div')

    let btn = document.createElement('button')
    btn.innerText = 'Hide/Show'

    this.getHTMLElements = function() {
        return {
            Password_wrapper: wrapper,
            Password_input: input,
            Password_btn: btn
        }
    }

    this.getValue = function() {
        return _value
    }

    this.setValue = function(newValue) {
        _value = newValue
        input.value = _value
    }

    this.setOpen = (bool) => {
        _isVisible = bool
        let _type = _isVisible? 'text' : 'password'
        input.setAttribute('type', `${_type}`)
        this.onOpenChange()
    } 

    this.getOpen = function() {
        return _isVisible
    }

    this.onChange = function(event) {
        _value = event.target.value
    }

    let closed = () => {}

    this.onOpenChange = (func=null, ...args) => {
        let lockfunc = func
        if(func) {
            (function(){
                closed = lockfunc
                closed(...args)
            })()
        } else {
            closed(...args)
        }
    }

    input.addEventListener('input', this.onChange)

    btn.addEventListener('click', () => {
        this.setOpen(!_isVisible)
    })

    wrapper.setAttribute('class', 'Password')
    this.setOpen(open)

    wrapper.append(input, btn)
    parent.append(wrapper)
}
let pass = new Password(document.body, true)

// login form
function Login (parent) {
    let _value = ''
    let input = document.createElement('input')
    input.type = 'text'
    input.placeholder = 'login'
    input.style.display = 'block'
    parent.append(input)

    this.getHTMLElement = function() {
        return input
    }

    this.getValue = function() {
        return _value
    }

    this.setValue = function(newValue) {
        _value = newValue
        input.value = _value
    }

    this.onChange = function(event) {
        _value = event.target.value
    }

    input.addEventListener('input', this.onChange)
}


// loginForm Constructor
function loginForm(parent, heading='loginForm Constructor') {
    let form = document.createElement('div')
    form.id = 'loginForm'
    form.style.border = '5px double black'
    form.style.width = 'fit-content'
    form.style.textAlign = 'center'
    form.style.padding = '15px'
    form.style.margin = '15px'

    let h2 = document.createElement('h2')
    h2.innerText = heading
    form.append(heading)

    let _login = new Login(form)
    let _password = new Password(form)

    let login_btn = document.createElement('button')
    login_btn.innerText = 'Log in'
    login_btn.disabled = true

    form.append(login_btn)
    for(let item of form.children) {
        item.style.margin = '10px'
    }

    this.getLogin = function() {
        return _login.getValue()
    }

    this.getPassword = function() {
        return _password.getValue()
    }

    this.isPasswordOpened = function() {
        return _password.getOpen()
    }

    this.setPasswordOpened = function(bool) {
        _password.setOpen(bool)
    }

    this.setLogin = function(newLogin) {
        _login.setValue(newLogin)
        checkFields()
    }

    this.setPass = function(newPass) {
        _password.setValue(newPass)
        checkFields()
    }

    function checkFields() {
        if (_login.getValue() && _password.getValue()) {
            login_btn.disabled = false
        } else {
            login_btn.disabled = true
        }
    }

    _login.getHTMLElement().addEventListener('input', checkFields)
    _password.getHTMLElements().Password_input.addEventListener('input', checkFields)

    parent.append(form)
}
let login_form = new loginForm(document.body)

// Password Verify
class PasswordVerify extends Password {
    constructor(parent, open=false) {
        super(parent, open);
        let _repeatWrapper = document.createElement('div')
        let _repeatField = document.createElement('input')
        let _successBtn = document.createElement('button')


        let displayRepeat = () => {
            if(this.getOpen() === false) {
                _repeatField.style.marginTop = '10px'
                _repeatField.type = 'password'
                _repeatField.placeholder = 'repeat password'
                _repeatField.value = ''

                _successBtn.innerText = 'no match!'
                _successBtn.disabled = true
                _successBtn.style.display = 'inline-block'
                _successBtn.style.backgroundColor = 'transparent'

                _repeatWrapper.append(_repeatField)
                _repeatWrapper.append(_successBtn)
                
                this.getHTMLElements().Password_wrapper.append(_repeatWrapper)
            } else {
                try {
                    for(let child of _repeatWrapper.children) {
                        _repeatWrapper.remove(child)
                    }
                } catch(e){}
            }
        }
        this.onOpenChange(displayRepeat)

        let isMatch= () => {
            if(this.getHTMLElements().Password_input.value && _repeatField.value) {
                if(this.getHTMLElements().Password_input.value === _repeatField.value) {
                    return true
                } 
            }
            return false
        }

        let btnActivate = (bool) => {
            if(bool) {
                _successBtn.disabled = false
                _successBtn.style.backgroundColor = 'chartreuse'
                _successBtn.innerText = 'passwords match'
            } else {
                _successBtn.disabled = true
                _successBtn.style.backgroundColor = 'transparent'
                _successBtn.innerText = 'no match!'
            }
        }

        this.getHTMLElements().Password_input.addEventListener('input', () => {
            btnActivate(isMatch())
        })

        _repeatField.addEventListener('input',() => {
            btnActivate(isMatch())
        })
    }
}
document.body.insertAdjacentHTML('beforeend', `
    <div id=verif></div>
`)
let verif = document.getElementById('verif')
let passverif = new PasswordVerify(verif, true)

// login form 
function Form(el, data, okCallback, cancelCallback){
    let formBody = document.createElement('div')
    let okButton = document.createElement('button')
    okButton.innerHTML = 'OK'
    this.validators     = {isValid:{}}

    let cancelButton = document.createElement('button')
    cancelButton.innerHTML = 'Cancel'

    formBody.innerHTML = '<h2>Form</h2>'
    if (typeof okCallback === 'function'){
        formBody.appendChild(okButton);
        okButton.onclick = (e) => {
            console.log(this)
            this.okCallback(this.data)
        }
    }

    if (typeof cancelCallback === 'function'){
        formBody.appendChild(cancelButton);
        cancelButton.onclick = () => {
            this.cancelCallback(data)
            okButton.disabled = true
        }
    }

    el.appendChild(formBody)
    
    this.checkInfo = (value, key, data, input, err) => {
        let validCheck
        let keyFormated = key
        okButton.disabled = true
        
        try {
            if(key[0] === "*") {
                keyFormated = key.substring(1)
                if(this.validators.mandatoryErr(value, key) === true) {
                    validCheck = this.validators[keyFormated]? this.validators[keyFormated](value, keyFormated) : true
                    input.style.backgroundColor = 'transparent'
                    input.style.color = 'black'
                    err.innerText = ''
                } else {
                    err.innerText = this.validators.mandatoryErr(value, keyFormated)
                    this.validators.isValid[key] = false
                }

            } else {
                validCheck = this.validators[keyFormated]? this.validators[keyFormated](value, keyFormated) : false
            }

            if(typeof validCheck === 'string') {
                input.style.backgroundColor = 'firebrick'
                input.style.color = 'white'
                err.innerText = validCheck
                this.validators.isValid[key] = validCheck

            } else if(typeof validCheck === 'boolean' && validCheck === true) {
                input.style.backgroundColor = 'transparent'
                input.style.color = 'black'
                err.innerText = ''
                this.validators.isValid[key] = validCheck
            }

            if(Object.values(this.validators.isValid).every((item) => item === true)) {
                okButton.disabled = false
            } else {
                okButton.disabled = true
            }
        } catch(e){/*sample text*/}

        // try {
        //     if(Object.values(this.validators.isValid).every((item) => item === true)) {
        //         okButton.disabled = false
        //     } else {
        //         okButton.disabled = true
        //     }
        // } catch(e) {}
    }

    let inputCreators = {
        string: (key, value, func ) => {
            let wrap = document.createElement('div')
            let input
            let small = document.createElement('small')
            small.style.color = 'red'
            small.innerText = ''

            if(/^[*]+$/.test(this.data[key])) {
                let div = document.createElement('div')
                input = new Password(div, true)
                input.getHTMLElements().Password_input.value = ''
                wrap.append(input.getHTMLElements().Password_wrapper, small)
                this.validators.isValid[key] = false

                input.getHTMLElements().Password_input.oninput = (e) => {
                    func(input.getHTMLElements().Password_input.value)
                    this.checkInfo(input.getHTMLElements().Password_input.value, key, {}, input.getHTMLElements().Password_input, small)
                }
                
            } else {
                input = document.createElement('input')
                input.type = 'text'
                input.style.display = 'block'
                input.placeholder = key
                input.value = value
                wrap.append(input, small)

                input.oninput  = () => {
                    func(input.value)
                    this.checkInfo(input.value, key, {}, input, small)
                }
            }
            return wrap
        },

        boolean: (key, value, func) => {
            let wrap = document.createElement('div')

            let input = document.createElement('input')
            input.type = 'checkbox'
            input.placeholder = key
            input.checked = value

            let small = document.createElement('small')
            small.style.color = 'red'
            small.innerText = ''

            wrap.append(input, small)

            input.onchange  = (e) => {
                func(input.checked)
                this.checkInfo(input.checked, key, {}, input, small)
            }
            return wrap
        },

        date: (key, value, func) => {
            let wrap = document.createElement('div')

            let input = document.createElement('input')
            input.type = 'datetime-local'
            input.style.display = 'block'
            input.placeholder = key
            input.value = new Date(value).toISOString().slice(0, -1)
            
            let small = document.createElement('small')
            small.style.color = 'red'
            small.innerText = ''
            
            wrap.append(input, small)

            input.onchange  = () => {
                func(new Date(input.value))
                this.checkInfo(input.value, key, {}, input, small)
            }
            return wrap
        },
    }

    let formTable = document.createElement('table')
    formTable.border = 1
    this.insertInTable = (data) => {
        for(let i = formTable.children.length-1; i >= 0; i--) {
            formTable.removeChild(formTable.children[i])
        }
        this.validators.isValid = {}
        this.initialData = Object.assign({}, this.initialData)
        this.data = data
        for(let key in data) {
            let tr = document.createElement('tr')
            let tdKey = document.createElement('td')
            let tdInput = document.createElement('td')
            let input = inputCreators[(data[key].constructor.name).toLowerCase()](key, data[key],(value) => {
                data[key] = value 
            })
            this.checkInfo(data[key], key)
            tdKey.innerHTML = key[0] ==='*'? `<span><span style="color: red;">*&nbsp</span>${key.substring(1)}</span>`:`<span>${key}</span>`
    
            tdInput.append(input)
            tr.append(tdKey, tdInput)
            formTable.append(tr)
        }
        okButton.before(formTable)
    }
    this.insertInTable(data)

    

    this.okCallback     = okCallback
    this.cancelCallback = cancelCallback

    this.initialData    = Object.assign({}, data)
    this.data           = data
}
let formContainer = document.createElement('div')
formContainer.id = 'formContainer'
document.body.append(formContainer)

let form = new Form(formContainer, {
    "*name": 'Anakin',
    surname: 'Skywalker',
    "*married": true,
    birthday: new Date((new Date).getTime() - 86400000 * 30*365),
    "*password": '**'
}, () => console.log('ok'),() => console.log('cancel') )
form.okCallback = (obj) => console.log('your data:', obj)
form.cancelCallback = () => form.insertInTable(form.initialData)

form.validators.surname = (value, key, data, input) => value !== '' && value.length > 2 && 
                                                    value[0].toUpperCase() == value[0] && 
                                                    !/[0-9 \W]/.test(value) ? true : `Wrong ${key}`

form.validators.name = form.validators.surname

form.validators.mandatoryErr = (value, key, data, input) => {
    if(typeof value === 'boolean') {
        return value === true? value : `${key} is mandatory`
    } else {
        return value === ''? `${key} is mandatory`:  value.length > 0 && value !== '' && /^([^\W\s]+)$/.test(value)? true : `invalid ${key} format`
    }
}

form.validators.birthday = (value, key, data, input) => {
    let today = new Date()
    let given = new Date(value)
    let lowest = new Date()
    lowest.setFullYear(1900)
    lowest.setHours(0,0,0,0)
    today.setHours(0,0,0,0)
    given.setHours(0,0,0,0)

    if(given >= today || given < lowest || value === '') {
        return `Wrong ${key}`
    }else {
        return true
    }
}

for(let key in form) {
    form.checkInfo(form[key], key,)
}

console.log(form)