'use strict'
/**    
         __  __  
        (  )(  ) ___  ____  ____ 
        )(  )( / __)( ___)(  _ \
        )(__)( \__ \ )__)  )   /
        (______)(___/(____)(_)\_)
                            By Nike
        
    This file is part of P42 implementation of SPARC.
 * @category MyEic
 * @subcategory Libraries
 * @extends User
 */
class myUser extends app.LoadedClasses.User {    
    
    authUrl = '';
    preferences = {}
    
    /**
     * 
     */
    constructor() { super(); }

    /**
     * Checks if user belongs to a role 
     * @param {string} role 
     * @returns {boolean}
     */
    hasRole(role) { return(this.roles.indexOf(role)>-1); }

    /**
     * 
     * @returns {Array<string>}
     */
    getRoles() { return(app.User.roles); }

    /**
     * 
     * @returns {Promise<Array>}
     */    
    fetchServices() {
        return(fetch('/app/assets/json/global/services.json?'+crypto.randomUUID(), {
                        method: 'GET'
                    })
                .then(response => response.text())
                .then(response => JSON.parse(response))
                .then(response => app.config.api = response.payload)
        ) 
    }

    /**
     * 
     * @param {*} callBack 
     */
    async checkAuthenticated(callBack){
        const startbtn = document.querySelector('#startbtn')
        const gobtn = document.querySelector('#login-dialog button')

        gobtn.addEventListener('click', () => this.launchLogin(callBack))

        startbtn.addEventListener('click', async () => {
            startbtn.disabled = true
            this.isAuthenticated = false
            const response = await fetch(app.config.userLib.checkauthEndpoint+'?'+crypto.randomUUID())
            let jsonresp = null
            if(response.ok) { jsonresp = await response.json() }
            if(!jsonresp ||(!jsonresp.payload)) {
                console.error('No valid response from checkauth !?')
                startbtn.disabled = false
            } else if(!jsonresp.payload.authenticated){
                document.querySelector('div.loginerr').classList.remove('show')
                document.getElementById('login-dialog').classList.add('show')
                document.querySelector('input[name="username"]').focus()
                document.getElementById('login-dialog').addEventListener('keyup',(event)=>{
                    if(event.key=='Enter') this.launchLogin(callBack)
                })
                if(jsonresp.payload.locked){
                    document.querySelector('div.loginerr').classList.add('show')
                    document.querySelector('div.loginerr').innerHTML = `
                        The account has been locked !<br>
                        (Ask an admin to unlock it.)
                    `
                }
            } else {
                console.log('authenticated!')
                this.isAuthenticated = true
                this.identity = jsonresp.payload.userInfos.identity
                this.roles = jsonresp.payload.userInfos.roles
                this.loadUserModel()
                callBack()
            }

        })    
    }


    async launchLogin(callBack){
        const gobtn = document.querySelector('#login-dialog button')
        gobtn.disabled = true            
        if(await this.login()) {
            document.querySelector('div.loginerr').classList.remove('show')
            console.log('Successful login !!!')
            this.loadUserModel()
            callBack()
        } else {
            gobtn.disabled = false
        }
    }

    loadUserModel(){
        app.events.addEvent('core.mvcReady', async () => {
            await Loader.loadScripts({ 
                'scripts':[app.config.userLib.modelPath],
                'dependencies':[],
            })
            this.model = new MyUserModleModel()
            this.loadPreferences()
            this.fetchServices()
        }, 'myUser')
    }

    /**
     * 
     * @returns {string}
     */
    getMessageBusUserInfo() { return(this.identity.username) }

    async login(){
        const response = await fetch(app.config.userLib.loginEndpoint+'?'+crypto.randomUUID(), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                username: document.querySelector('input[name="username"]').value,
                passwd: document.querySelector('input[name="password"]').value,
            })
        })
        let jsonresp = null
        if(response.ok) { jsonresp = await response.json() }
        if(jsonresp && jsonresp.success && jsonresp.payload){
            if(jsonresp.payload.authenticated){
                this.isAuthenticated = true
                this.identity = jsonresp.payload.userInfos.identity
                this.roles = jsonresp.payload.userInfos.roles
                return(true)
            } else {
                document.querySelector('div.loginerr').classList.add('show')
                if(!jsonresp.payload.locked){
                    document.querySelector('div.loginerr').innerHTML = `
                        Bad username or password !<br>
                        (${jsonresp.payload.trials} trials left.)
                    `
                } else {
                    document.querySelector('div.loginerr').innerHTML = `
                        The account has been locked !<br>
                        (Ask an admin to unlock it.)
                    `
                }    
            }
        }
        this.isAuthenticated = false
        this.identity = null
        return(false)
    }

    /**
     * 
     * @param {string} jumpTo 
     */
    logout(jumpTo='') {
        jumpTo = jumpTo ? jumpTo : this.logoutUrl
        fetch(app.config.userLib.logoutEndpoint+'?'+crypto.randomUUID(),{
            method: 'GET',
            credentials: 'include'
        }).then((resp) =>{
                window.onbeforeunload = null  // If user confirmed to logout, not need to have him confirm he's leaving the app !
                document.location.href = jumpTo;
            });
    }

    /**
     * This is separated, so that upper layer has a chance to use a login button, or avoid redirection loops. 
     */
    gotoLogin() { 
        window.onbeforeunload = null // If  user asks to relogin, not need to have him confirm he's leaving the app !
        document.location.href = this.authUrl;
     }

    /**
     * 
     * @param {*} info 
     */
    async parseUserInfo(info) {
        
        this.identity = {
            uuid: info.euLoginId,
            firstname: info.family_name,
            lastname: info.given_name,
            email: info.email
        };
        this.roles = info.userRoles  || []
    }

    loadPreferences() {
        this.model.getPreferences().then(settings => {
                this.preferences = settings.value || {}
            })        
    }

    savePreferences() {
        this.model.setPreferences({ 
                key: `${this.identity.uuid}:userPrefs`, 
                value: this.preferences
            })
    }

    getPreference(path) {
        let value = null;
        let segments = path.split('.');
        let pointer = this.preferences;
        if(pointer) {
            for(let segment of segments) {
                if(pointer[segment]) {
                    if(typeof pointer[segment] == 'object') {
                        pointer = pointer[segment];
                    } else {
                        value = pointer[segment];
                    }
                } else {
                    break;
                }
            }
        }

        return value;
    }
    
    setPreference(path, value) {
        const segments = path.split('.')
        let pointer = this.preferences
        
        for (let i = 0; i < segments.length - 1; i++) {
            const segment = segments[i]
            if (!pointer[segment] || typeof pointer[segment] !== 'object') {
                pointer[segment] = {}
            }
            pointer = pointer[segment]
        }
        
        const lastKey = segments.at(-1)
        const existing = pointer[lastKey]
        if ((typeof(value) == 'object') && (value !== null) && (typeof(existing) == 'object') && (existing !== null)) { // merge instead of overwrite
            Object.assign(existing, value)
        } else {
            pointer[lastKey] = value
        }
        
        this.savePreferences()
    }


}

app.registerClass('User', myUser, true); // for Sparc to use
app.registerClass('myUser', myUser, true); // Just to avoid double-loading if squeezed