module.exports = class GameServerMessageProtocol {
    handleMessage (data) {
        let command = null;
        const segments = data.split(',');
        return segments.map(s => {
            let arg = null;
            if (this.isCommand(s)) {
                command = s;
                return s;
            }
            switch (command) {
            case 'var':
            case 'prop':
                // eslint-disable-next-line no-console
                // console.log('got command', command, s);
                arg = this.parseArgument(s, command);
                return this.processVariable(arg);
            default:
                // eslint-disable-next-line no-console
                // console.log('unknown command', command, s);
                return null;
            }
        })
            .filter(msg => msg)
            .join(',');
    }

    isCommand (text) {
        return !!text.match(/^(var|prop)$/g);
    }

    /**
   *
   * @param {*} arg Argument like `Hedgehog.cloud:200` for setting local variable (Sprite=Hedgehog),
   *                `cloud:200` for setting global variable. getting variable with `cloud` (without colon :)
   * @param {*} type 'var' or 'prop'
   * @return {object} Object bla
   */
    parseArgument (arg, type) {
    // example: var,a:100,b:400,prop,Balloons[0].x:45,Balloons[0].y
        const parts = arg.split(':');
        const segment = parts[0].split('.');
        // e.g. Player[4] -> ['Player[4]', 'Player', '4']
        const pathsegments = (segment[0] || '').match(/(.*)\[(\d+)\]/);
        const local = segment.length > 1 ? segment[0] : null;

        return {
            local,
            path: pathsegments ? pathsegments[1] : local,
            i: pathsegments ? pathsegments[2] : null,
            set: parts.length > 1,
            name: segment[segment.length - 1],
            fullname: parts[0],
            value: parts[1],
            type
        };
    }

    formatMessage (name, value, type = 'var') {
        return `${type},${name.replace('Stage.', '')}:${value}`;
    }

    stringifyArgument (arg) {
        return `${arg.fullname}:${arg.value}`;
    }

    processVariable (arg) {
        try {
            if (arg.set) return this.stringifyArgument(this.setValue(arg));
            return this.stringifyArgument(this.getValue(arg));
        } catch (error) {
            arg.value = 'ERRORVAR';
            return this.stringifyArgument(arg);
        }
    }

    setValue (arg) {
        if (arg.type === 'var') this.setVar(arg);
        if (arg.type === 'prop') this.setProp(arg);
        return arg;
    }

    getValue (arg) {
        if (arg.type === 'var') arg.value = this.getVar(arg).value;
        if (arg.type === 'prop') arg.value = this.getProp(arg)[arg.name];
        return arg;
    }

    castValue (propertyName, value) {
        switch (propertyName) {
        case 'currentCostume':
        case 'direction':
        case 'size':
        case 'height':
        case 'width':
        case 'zindex':
        case 'tempo':
        case 'videoTransparency':
        case 'volume':
        case 'x':
        case 'y':
            return Number(value);
        case 'draggable':
        case 'visible':
            return value === 'true' || value === '1' || value === 'yes';
        default:
            return value;
        }
    }

    // eslint-disable-next-line no-unused-vars
    getVar (_arg) {
        throw new Error('method not implemented');
    }
    // eslint-disable-next-line no-unused-vars
    setVar (_arg) {
        throw new Error('method not implemented');
    }
    // eslint-disable-next-line no-unused-vars
    getProp (_arg) {
        throw new Error('method not implemented');
    }
    // eslint-disable-next-line no-unused-vars
    setProp (_arg) {
        throw new Error('method not implemented');
    }
};
