/**
 * Manage event process and event structure
 * @author Manish Yadav
 * @copyright Semusi Technologies PVT LTD
 */
const cacheApi = require('./semusi.cache.js'),
    Promise = require('bluebird'),
    logger = require('../../logger'),
    common = require('./common'),
    errorHandler = require('./error.handler.js'),
    winstonLogger = require('./winston'),
    dataProducer = require('./common.data.producer.js');

/**
 *
 * @param {*} event has an event data
 */
exports.setSessoinCache = function(event){
    let etime = event.eventTime.toString();
    cacheApi.setKey('session_'+event.appid+event.did+event.sid, etime);
    cacheApi.expire('session_'+event.appid+event.did+event.sid, common.config.sessionKeyExpireTime);
}

/**
 *
 * @param {*} event has an event data
 */
exports.setSessoinLSCache = function(event){
    let etime = event.eventTime.toString();
    cacheApi.setKey('session_ls_'+event.appid+event.did+event.sid, etime);
    cacheApi.expire('session_ls_'+event.appid+event.did+event.sid, common.config.sessionKeyExpireTime); 
}

/**
 *
 * @param {*} event has an event data
 * with out callback
 */
exports.manageUserEventStringOld = function(event){
    cacheApi.getKey('app_evnets'+event.appid, function(error, eventData){
        if(!error && (eventData != null && eventData != '')) {
            // parse event data string
            eventData = JSON.parse(eventData);
            // validate event into cache
            if(eventData[event.key]){
                // get previouse event string
                cacheApi.getKey('eventString'+event.appid+event.did+event.sid, function(error, data){
                    let sid = event.sid; //event.sid.replace(/-/g, '_');
                    if(data == null || data == ''){
                        data = '#' + moment(event.eventTime*1000).format('YYYY-MM-DD') + '#SS' + sid + '#' + eventData[event.key] + '#SE' + sid;
                    }
                    else if(!error) {
                        if(event.key == 'Session_Start'){
                            data += '#' + moment(event.eventTime*1000).format('YYYY-MM-DD') + '#SS' + sid + '#' + eventData[event.key] + '#SE' + sid;
                        }
                        else {
                            data = data.replace('#SE' + sid, '#' + eventData[event.key] + '#SE' + sid )
                        }
                    }

                    // update event string cache
                    cacheApi.setKey('eventString'+event.appid+event.did+event.sid, data);
                    cacheApi.expire('eventString'+event.appid+event.did+event.sid, common.config.sessionKeyExpireTime);
                });
            }
        }
    });
}

/**
 *
 * @param {*} event has an event data
 */
exports.manageUserEventString = function(event, callback){
    cacheApi.getKey('app_evnets'+event.appid, function(error, eventData){
        if(!error && (eventData != null && eventData != '')) {
            // parse event data string
            eventData = JSON.parse(eventData);
             
            // validate event into cache
            if(eventData[event.key]){
                // get previouse event string
                cacheApi.getKey('eventString'+event.appid+event.did+event.sid, function(error, data){
                    let sid = event.sid; //event.sid.replace(/-/g, '_');
                     
                    if(data == null || data == ''){
                        data = '#' + moment(event.eventTime*1000).format('YYYY-MM-DD') + '#SS' + sid + '#' + eventData[event.key] + '#SE' + sid;
                    }
                    else if(!error) {
                        if(event.key == 'Session_Start'){
                            data += '#' + moment(event.eventTime*1000).format('YYYY-MM-DD') + '#SS' + sid + '#' + eventData[event.key] + '#SE' + sid;
                        }
                        else {
                            data = data.replace('#SE' + sid, '#' + eventData[event.key] + '#SE' + sid )
                        }
                    }

                     
                     
                    // update event string cache
                    cacheApi.setKey('eventString'+event.appid+event.did+event.sid, data);
                    cacheApi.expire('eventString'+event.appid+event.did+event.sid, common.config.sessionKeyExpireTime);
                    //event.eventString = data;
                    callback();
                });
            }
            else {
                callback();
            }
        }
        else {
          callback();
        }
    });
}

/**
 *
 * @param {*} event has an event data
 */
exports.getDiffFromCache = function(event){
    return new Promise ( (resolve, reject) =>{
        try{
            getSessionTimeFromCache(event)
                .then((lsEvent) =>{
                    duration = parseInt(event.eventTime) - parseInt(lsEvent);
                    duration = (parseInt(duration) > 0 )? duration : 0;
                    return resolve(duration);
                })
                .catch((error) =>{
                    logger.error(`rror while getSessionTimeFromCache => ${error}`); 
                    return reject(false);
                });
        }
        catch (e){

        }
    });
}

/**
 *
 * @param {*} db has object of mongoDB
 * @param {*} event has an event data
 */
exports.processSessionData = function(db, event){
    return new Promise ( (resolve, reject) =>{
        try{
            let duration = 0;
            if(event.duration){
                duration = parseInt(event.duration);
                duration = (parseInt(duration) > 0 )? duration : 0;
                sendEmail(event,duration,true);
                processData(db, event, duration)
                    .then(res =>{
                        return resolve(true);
                    })
                    .catch(error =>{
                        return reject(error);
                    });
            }
            else{
                return reject("duration key does not exists");
            }
        }
        catch(err){
            logger.error(`error=> ${err}`);
            logger.info(`appid => ${event.appid} ::: user_id=>> ${event.user_id} ::: did =>> ${event.did}`);
            return reject(err.message);
        }
    });
}

// process app background data
function processData(db, event, duration){
    return new Promise( (resolve, reject) =>{
        // update tsd and lsd in app user collection
        let updatedAt = common.getCurrentEpochTime();

        // push app users data into array
        let ausersArray = [{appid:event.appid, op:'update', data:{"_id":event.user_id, $inc:{'tsd':duration},$set:{'lsd':duration, 'ls_st':parseInt(event.eventTime-duration), 'updatedAt':updatedAt}}}];
        // check active user Asl boundary
        event.duration = duration;
        let bulk_timely_user_sessions = db.collection('timely_users_session').initializeUnorderedBulkOp();
        // check active user ASl
        common.checkActiveUserAsl(event, function(err, stdata){
            if(stdata){
                // push end session optimisation query into array
                let tusessionArray = [{appid:event.appid, op:'update', isUpsert:true, data:stdata, key:'$inc', keyData:'updateSessionUserObj'}];
                for(let j=0; j<stdata.length; j++){
                    bulk_timely_user_sessions.find({'_id':stdata[j].id}).upsert().update({'$inc': stdata[j].updateSessionUserObj});
                }
                // execute bulk query
                bulk_timely_user_sessions.execute(function(err, result){
                    if (err){
                        // send data into queue if mongo got error
                        errorQueue(tusessionArray, 'mongo', 'timely_users_session', 'processEndSessionData', function(status){
                            logger.error(`Error:processBeginSessionData:bulk_timely_user_sessions=> ${err}`);
                        });
                        return reject(err);
                    }
                    else{
                        tusessionArray = [];
                        // run single query to update tsd
                        db.collection('app_users'+event.appid).update({"_id":event.user_id},{$inc:{'tsd':duration},$set:{'lsd':duration, 'ls_st':parseInt(event.eventTime-duration), 'updatedAt':updatedAt}}, function(error, operation){
                            if(error){
                                // send data into queue if mongo got error
                                errorQueue(ausersArray, 'mongo', 'app_users'+event.appid, 'processEndSessionData', function(status){
                                    logger.error(`Error:processBeginSessionData: => ${error}`);
                                    logger.info(`user_sessions=> ${event.appid}`); 
                                });
                            }
                            return resolve(true);
                        });
                    }
                });
            }
            else{
                return reject("stdata is not exists")
            }
        });
    });
}

function getSessionTimeFromCache (event){
    return new Promise ((resolve, reject) =>{
        cacheApi.getKey('session_'+event.appid+event.did+event.sid, (error, eventTime) =>{
            if(eventTime == null){
                getSessionTimeSessionStart(event)
                    .then((ls_st) =>{
                        if(ls_st){
                            return resolve(parseInt(ls_st));
                        }
                        else{
                            return reject("getSessionTimeFromDB Event time not found!");
                        }
                    })
                    .catch((error) =>{
                        return reject(`getSessionTimeFromDB Event time not found! ${error}` );
                    })
            }
            else if(eventTime != null){
                return resolve(parseInt(eventTime));
            }
        });
    });
}

function getSessionTimeSessionStart (event){
    return new Promise ((resolve, reject) =>{
        // common.collection('app_users'+appid).findOne({_id:user_id}, function(error, user){
        //     if(error){
        //         return reject(error);
        //     }
        //     else{
        //         return resolve(user.ls_st);
        //     }
        // });
        cacheApi.getKey('session_ls_'+event.appid+event.did+event.sid, (error, eventTime) =>{

            if( eventTime != null){
                return resolve(parseInt(eventTime));
            }
            else if(eventTime == null){
                return reject("diff not found!");
            }
        });
    });
}

// send data to error queue
function errorQueue (eventsData, type, col, method, callback){
    let obj = {
        method  : method,
        col		: col,
        type 	: type,
        events  : eventsData,
        key 	: "errors"
    };
    dataProducer.writeDataToSQS(obj, function(status){
        if(callback){
            return callback(status);
        }
        return;
    });
}

// notification while duration too much
function sendEmail(event, duration, isEventDuration){
    if(duration > 2500){
        // write a file
        winstonLogger.init('duration_'+event.appid+"_"+event.key, true);
        let eventArray = {};
        cacheApi.getKey('event_session_'+event.appid+event.did+event.sid, (error, eventData) =>{
            if(!error && eventData != null){
                //errorHandler.sendError({ab:event, af:JSON.parse(eventData), d:duration, isED:isEventDuration});
                eventArray = {ab:event, af:JSON.parse(eventData), d:duration, isED:isEventDuration};
                winstonLogger.writeData(eventArray);
            }
            else if(eventData == null){
                cacheApi.getKey('event_session_ls_'+event.appid+event.did+event.sid, (error, eventData) =>{
                    if(!error && eventData != null){
                        //errorHandler.sendError({ab:event, ss:JSON.parse(eventData), d:duration, isED:isEventDuration});
                        eventArray = {ab:event, ss:JSON.parse(eventData), d:duration, isED:isEventDuration}
                        winstonLogger.writeData(eventArray);
                    }
                    else if(eventData == null){
                        //errorHandler.sendError({ab:event, ss:eventData, d:duration, isED:isEventDuration});
                        eventArray = {ab:event, ss:eventData, d:duration, isED:isEventDuration}
                        winstonLogger.writeData(eventArray);
                    }
                });
            }
        });
    }
}

exports.errorQueue = errorQueue;
