import { parseSubResponse, parseResponse } from "frontblock-generic/Service";
var bsock = require('bsock')

/**
 * Dynamic library to communicate with FrontblockService remotely
 *
 * This will be automatically injected into the webpages served by FrontblockService
 * Will ask it's service for available RPCs and parse them into methods of this object
 * for convenient access.
 */
export class FrontblockConfigLib{
    private socket
    
    constructor(){
        this.socket = bsock.connect(20000, 'localhost', false/*tls*/)
        this.init()
    }

    // need this-context for eval-magic below 
    // DO NOT REMOVE. They're not really unused
    private parseSubResponse = parseSubResponse
    private parseResponse = parseResponse

    private async init(){
        const info = await this.info()
        for (const i of info) {
            let f: any
            switch (i.info.type) {
                case 'call':
                    f = this.callGenerator(i.name, i.args)    
                    break                
                case 'hook':
                    f = this.hookGenerator(i.name, i.args)                    
                    break
                case 'unhook':
                    f = this.unhookGenerator(i.name, i.args)                    
                    break
            }

            this[i.name] = f
            this[i.name].bind(this)
        }
    }

    async info(){
        return await this.socket.call('info')
    }

    private callGenerator(fnName, fnArgs): Function{
        return eval( '( () => async ('+fnArgs+') => { return await this.socket.call("'+fnName+'", '+fnArgs+')} )()' )
    }

    private hookGenerator(fnName, fnArgs): Function{
        return eval( `( () => async (`+fnArgs+(fnArgs.length!==0?",":"")+` callback) => {
                            const r = await this.socket.call("`+fnName+`", `+fnArgs+`)
                            const res = await this.parseSubResponse(r);
                            if(res.uid != null){
                                this.socket.hook(res.uid, callback)
                            }
                            return res
                        } )()` )
    }
    private unhookGenerator(fnName, fnArgs): Function{
        return eval( `( () => async (`+fnArgs+`) => {
                            const r = await this.socket.call("`+fnName+`", `+fnArgs+`)
                            const res = await this.parseResponse(r)
                            if(res.uid != null)
                                this.socket.unhook(res.uid)
                            return res
                        } )()` )
    }

}

window['fb'] = new FrontblockConfigLib()