"use strict";

const console = require('gifer-console');
const CMD     = require('./cmd/cmd').CMD;
const Service = require('./service');

const commands = {
    sendOffer      : '0001',
    sendAnswer     : '0002',
    sendICE        : '0003',
    receiveOffer   : '0004',
    receiveAnswer  : '0005',
    receiveICE     : '0006',
    // connect        : '0007',
    disconnect     : '0008',
    setID          : '0009',
    // newClient      : '0010',

    nm_ready       : '0011',
    nm_create_room : '0012',
    nm_remove_room : '0013',

    mn_create_room : '0014',
    mn_remove_room : '0015',
    mn_ready       : '0016',

    mn_log         : '0017',

    config         : '0019',
    userLeave      : '0020'
};

function makeIceServers(data){
    /** @namespace data.IPList*/
    /** @namespace data.TURNPort*/
    /** @namespace data.Credential */
    var res = [];
    var ipList = data.IPList.split(',');

    for (var i = 0; i < ipList.length; i++){
        var udp  = 'turn:' + ipList[i] + ':' + data.TURNPort +'?transport=udp';
        var stun = 'stun:' + ipList[i] + ':' + data.TURNPort;

        res.push({
            urls       : [stun, udp],

            credential : data.Credential,
            username   : data.UserName
        });
    }

    return res;
}

function init(socketIO) {
    var roomList  = {
        // MID: [wsocket list]
    };
    var mixerSocket = null;

    socketIO.on('connection', function (_webSocketClient) {
        if (_webSocketClient.conn.remoteAddress === "127.0.0.1")
        _webSocketClient.on(commands.mn_ready, function (){
            console.log('=== Mixer ready to create rooms! ===');

            mixerSocket = _webSocketClient;

            // === Signaling CMD ===============================================

            mixerSocket.on(commands.sendOffer, function (_args){
                var args  = Service.StringToObj(_args);
                var uid   = args.uid; //args[0];
                var uin   = args.uin; //args[1];
                var offer = args.offer; //args[2];
                // var toMixer= args[3];

                // console.error('commands.sendOffer: ' + (toRoom ? TypeROOM : webSocketClient.clientID + " to: " + id));
                if (roomList[uid][uin]){
                    // отправляем уже подключенному юзеру офер, так как изменился его список треков, мы добавили туда новый
                    global._internalServer.sendDataFromInternalServer(CMD.ns_media_conf + "=" + JSON.stringify({
                        CID : roomList[uid][uin].cid,
                        UID : uid,
                        cmd : commands.receiveOffer,
                        Data: {
                            offer:  offer
                        }
                    }));
                }
            });

            mixerSocket.on(commands.sendAnswer, function (_args){
                var args   = Service.StringToObj(_args);
                var uid    = args.uid; //args[0];
                var uin    = args.uin; //args[1];
                var answer = args.answer; //args[2];

                // console.error('commands.sendAnswer: ' + webSocketClient.clientID + " to: " + id);

                if (roomList[uid] && roomList[uid][uin]){
                    global._internalServer.sendDataFromInternalServer(CMD.ns_media_conf + "=" + JSON.stringify({
                        CID : roomList[uid][uin].cid,
                        UID : uid,
                        cmd : commands.receiveAnswer,
                        Data: {
                            answer: answer
                        }
                    }));
                }
            });

            mixerSocket.on(commands.sendICE, function (_args){
                var args    = Service.StringToObj(_args);
                var uid     = args.uid; //args[0];
                var uin     = args.uin; //args[1];
                var ice     = args.ice; //args[2];

                if (roomList[uid][uin]){
                    global._internalServer.sendDataFromInternalServer(CMD.ns_media_conf + "=" + JSON.stringify({
                        CID : roomList[uid][uin].cid,
                        UID : uid,
                        cmd : commands.receiveICE,
                        // data: [uid, TypeROOM, ice]
                        Data: {
                            ice: ice
                        }
                    }));
                }
            });

            mixerSocket.on(commands.mn_log, function (args){
                var type = args[0];
                var data = args[1];

                console.important('[MIXER] [' + type + ']: ' + data);
            });

            mixerSocket.on(commands.mn_create_room, function (_args){
                var args = Service.StringToObj(_args);
                var uid  = args[0];
                var info = args[1];

                console.log('[MIXER] room created: ' + uid);

                roomList[uid] = {};
                roomList[uid][info.uin] = info;

                global._internalServer.sendDataFromInternalServer(CMD.ns_media_conf_created + '=' + JSON.stringify(info));
            });

            mixerSocket.on(commands.userLeave, function (_args) {
                var args = Service.StringToObj(_args);
                var uid  = args[0];
                var uin  = args[1];

                if (roomList[uid] && roomList[uid][uin]){
                    roomList[uid][uin] = null;

                    global._internalServer.sendDataFromInternalServer(CMD.ns_media_conf_leave + '=' + JSON.stringify(roomList[uid][uin]));

                    delete roomList[uid][uin];

                    console.log('remove user from MIXER: ' + uin);
                }
            });

            // =================================================================

            mixerSocket.on('timout', function () {
                console.error('[MIXER] WebSocket timeout! ' + mixerSocket.clientID, console.logLevel.ERROR);
            });

            mixerSocket.on('error', function (err) {
                console.error('[MIXER] WebSocket error occurred! ' + mixerSocket.clientID + '\n' + JSON.stringify(err), console.logLevel.ERROR);
            });

            mixerSocket.on('disconnect', function (){
                console.error('[MIXER] disconnected!', console.logLevel.ERROR);
            });
        });
    });

    global._internalServer.addCmdParser(CMD.sn_media_conf_create, function (_data) {
        // uid // cid // uin // type // mediaconf create voice 1 // IPList // Credential // UserName // TURNPort
        var info = Service.StringToObj(_data);
        info.mid = info.uid; // set MID value equals to UID, todo: maybe change...

        if (mixerSocket){
            mixerSocket.emit(commands.config, [JSON.stringify(makeIceServers(info))]);

            mixerSocket.emit(commands.nm_create_room, [info.uid, info]);
        } else {
            // todo: send error mixer not connected
        }
    });

    global._internalServer.addCmdParser(CMD.sn_media_conf_join, function (_data) {
        // uid  // cid  // uin
        var data = Service.StringToObj(_data);

        console.log('sn_media_conf_join: ' + JSON.stringify(_data));

        if (roomList[data.uid] /*&& !roomList[data.uid][data.uin]*/){
            roomList[data.uid][data.uin] = data;
        } else {
        }
    });

    global._internalServer.addCmdParser(CMD.sn_media_conf_leave, function (_data) {
        // uid  // cid  // uin
        var data = Service.StringToObj(_data);

        console.log('sn_media_conf_leave: ' + JSON.stringify(_data));

        if (roomList[data.uid] && roomList[data.uid][data.uin]){
            delete roomList[data.uid][data.uin];

            mixerSocket.emit(commands.userLeave, data);
        }
    });

    global._internalServer.addCmdParser(CMD.sn_media_conf_close, function (_data) {
        // uid  // cid  // uin
        var data = Service.StringToObj(_data);

        console.log('sn_media_conf_close: ' + JSON.stringify(_data));

        mixerSocket.emit(commands.nm_remove_room, [data.uid]);

        if (roomList[data.uid]){
            delete roomList[data.uid];
        }
    });

    global._internalServer.addCmdParser(CMD.sn_media_conf, function (inData) {
        var info = Service.StringToObj(inData);

        console.log("sn_media_conf: " + JSON.stringify(inData));

        info.Data.uid = info.UID;

        switch (info.cmd){
            case commands.sendOffer:
                mixerSocket.emit(commands.receiveOffer, info.Data);
            break;

            case commands.sendAnswer:
                mixerSocket.emit(commands.receiveAnswer, info.Data);
            break;

            case commands.sendICE:
                mixerSocket.emit(commands.receiveICE, info.Data);
            break;

        }
    });
}

module.exports = init;

