/**
 * Transactional Campaign manage
 * Store campaign and send to end users through FCM and GCM
 * @author Manish Yadav
 * @copyright Semusi Technologies PVT LTD.
 */
const semusiConfig = require('./../../config'),
    common = require('./../../utils/common.js'),
    logger = require('../../../logger'),
    async = require('async'),
    moment = require('moment'),
    path = require('path'),
    campaignUtils = require('./../../utils/campaign.utils'),
    cacheApi = require('./../../utils/semusi.cache.js');

exports.sendTransactionalCampaign = function(params){
    if(params.qstring.camp_data && Array.isArray(params.qstring.camp_data)){
        processMultipleCampaign(params)
    }
    else {
        // process single campaign payload
        processSingleCampaign(params.qstring.camp_data, params, (response) =>{
            // return response to end user
            return common.returnMessage(params, response.statusCode, response.msg);
        })
    }
}

var processMultipleCampaign = function(params){
    var campaigsResponse = [];
    async.forEach(params.qstring.camp_data, (campaign, callback) =>{
        // process single campaign payload
        processSingleCampaign(campaign, params, (response) =>{
            // push campaign user response
            campaigsResponse.push(response);
            callback();
        })
    }, (error, res) =>{
        // return response to end user
        return common.returnMessage(params, 200, campaigsResponse);
    });
}

var processSingleCampaign = function(camp_data, params, callback){
    var argProps = {
        'dids':   { 'required': false, 'type': 'Array' },
        'name':  { 'required': true, 'type': 'String' },
        'users':  { 'required': false, 'type': 'Array' },
        'gcmids':  { 'required': false, 'type': 'Array' },
        'payload': { 'required': true, 'type': 'JSON' },
        'platform': { 'required': true, 'type': 'String' },
        'createdAt':{'required':false,'type':'String'}
    },
    newCampaign = {};

    // parse data
    if(camp_data == 'string'){
        camp_data = JSON.parse(camp_data);
    }

    // validate arguments
    if (!(newCampaign = common.validateArgs(camp_data, argProps))) {
        callback({statusCode: 400, errorMsg: 'Not enough arguments'});
        return false;
    }

    newCampaign.createdAt = parseInt(moment().valueOf());
    newCampaign._id = common.db.ObjectID();
    newCampaign.payload.st = parseInt(moment().valueOf());
    //Handling Of custom data (Like RequestIds etc.)
    newCampaign.customData = camp_data.custom;

    // store transactional campaign information
    common.db.collection('transaction_camp_'+params.qstring.app_id).insert(newCampaign, function(err, result){
        if(err){
            logger.error(`campaign creation failed ${err}`);
            return callback({statusCode: 400, errorMsg: 'Campaign creation failed!'});
        }

        // delete all campaign from cache
        cacheApi.deleteKey('trans_campaigns_'+ params.qstring.app_id,function(err,result){});

        newCampaign.platform = newCampaign.platform.toLowerCase();
        newCampaign.payload.camp_id = newCampaign._id;
        newCampaign.payload.cmd = "#transactional";

        // validate cdata if it's more than 2kb send url to get form db
        if(newCampaign.payload.cdata){
            if(common.calculateDataSize(newCampaign.payload.cdata)  > common.config.campaignPayloadSize ){
                cacheApi.setKey('trans_campaigns_template_'+ params.qstring.app_id + newCampaign._id, JSON.stringify(newCampaign.payload.cdata));
                newCampaign.payload.cdata = common.config.host+"/o/templates/getCustomData?app_id="+params.qstring.app_id+"&api_key="+params.qstring.api_key+"&tid="+newCampaign._id+"&ct=trans";
            }
        }

         // get GCM key and iOS APN
        campaignUtils.getGCMKeyAndiOSCert(params.qstring.app_id)
            .then((appKeyCert) =>{
                var sendResponse = false;
                // send push to android
                if(appKeyCert.android && (newCampaign.platform == 'all' || newCampaign.platform == 'android')){
                    // check gcm key and platform for send android user push
                    if(appKeyCert.android.dev || appKeyCert.android.prod || appKeyCert.fcmKey){
                        sendResponse = true;
                        // check production gcm key if not exists use dev gcm key
                        var GCMKEY = (appKeyCert.android.prod)? appKeyCert.android.prod : appKeyCert.android.dev;

                        // send campaign through direct gcm ids
                        if(newCampaign.gcmids && newCampaign.gcmids.length > 0){
                            // send android push
                            campaignUtils.sendAndroidNotification(appKeyCert.fcmKey, GCMKEY, newCampaign.gcmids, [], newCampaign.payload, false, 'transaction_camp_'+params.qstring.app_id);
                        }
                        else if(newCampaign.dids && newCampaign.dids.length > 0){ // send campaign specific users did
                            //var match = {did:{$in:newCampaign.dids}, p:'Android', active:true, gcmid:{$exists:true}};
                            var match = {
                                nosql : {did:{$in:newCampaign.dids}, p:'Android', active:true},
                                sql : " Where active=true and p='Android' and did in('"+ newCampaign.dids.join("','") +"')"
                            };
                            campaignUtils.getUsersMsgToken(match, params.qstring.app_id, newCampaign._id)
                                .then(([gcmids, fcmids]) =>{
                                    campaignUtils.sendAndroidNotification(appKeyCert.fcmKey, GCMKEY, gcmids, fcmids, newCampaign.payload, false, 'transaction_camp_'+params.qstring.app_id);
                                })
                                .catch((error) =>{
                                    logger.error(`Given did gcmids not found! => ${error}`);
                                    return;
                                });
                        }
                        else if(newCampaign.users && newCampaign.users.length > 0){ // send campaign specific users id
                            //var match = {_custom_UserId:{$in:newCampaign.users}, p:'android', active:true, gcmid:{$exists:true}};
                            //var match = {_custom_UserId:{$in:newCampaign.users}, p:'Android', active:true};
                            let users = newCampaign.users.map((user) =>{
                                return '[{"_custom_UserId": '+user+'}]';
                            })
                            var match = {
                                nosql : {_custom_UserId:{$in:newCampaign.users}, p:'Android', active:true},
                                sql : " Where active=true and p='Android' and _custom @> ANY (ARRAY ["+users+"]::jsonb[])"
                            };
                            campaignUtils.getUsersMsgToken(match, params.qstring.app_id, newCampaign._id)
                                .then(([gcmids, fcmids]) =>{
                                    campaignUtils.sendAndroidNotification(appKeyCert.fcmKey, GCMKEY, gcmids, fcmids, newCampaign.payload, false, 'transaction_camp_'+params.qstring.app_id);
                                })
                                .catch((error) =>{
                                    logger.error(`Given userid gcmids not found! => ${error}`);
                                    return ;
                                });
                        }
                    }
                }

                // send push to iOS
                if(appKeyCert.ios && (newCampaign.platform == 'all' || newCampaign.platform == 'ios')){
                    var options = {
                        keyFile : "",
                        certFile : "",
                        debug : true
                     },
                     iosCert ='',
                     iosKey = '';
                     logger.info(`iOS Certificate Entrance`)

                    // dev mode certificates
                    if(appKeyCert.ios.dev.cert1 && appKeyCert.ios.dev.cert1!=""){
                        iosCert = appKeyCert.ios.dev.cert1;
                    }
                    if(appKeyCert.ios.dev.cert2 && appKeyCert.ios.dev.cert2!=""){
                        iosKey = appKeyCert.ios.dev.cert2;
                    }

                    //production mode data for push.
                    if(appKeyCert.ios.prod.cert1 && appKeyCert.ios.prod.cert1!=""){
                        iosCert = appKeyCert.ios.prod.cert1;
                    }
                    if(appKeyCert.ios.prod.cert2 && appKeyCert.ios.prod.cert2!=""){
                        iosKey = appKeyCert.ios.prod.cert2;
                    }
                    if(iosCert && iosKey){
                        sendResponse = true;
                    }
                    logger.info(`iOS Certificate Entrance 1`)

                    // check and validate iOS APN certificates
                    common.checkAppleCertificate(params.qstring.app_id, iosCert, iosKey, function(resCertificate){
                        logger.info(`iOS Certificate Entrance 3`)
                        // if(resCertificate){
                            // include certificates certificates
                            options.certFile = path.join(__dirname,"../../../frontend/express/public/appcertificates/" + params.qstring.app_id +"/"+ iosCert);
                            options.keyFile = path.join(__dirname,"../../../frontend/express/public/appcertificates/" + params.qstring.app_id +"/"+ iosKey);

                            // send campaign through direct gcm ids
                            if(newCampaign.gcmids && newCampaign.gcmids.length > 0){
                                // send android push
                                sendAPN(options, newCampaign.gcmids, [], newCampaign.payload);
                            }
                            else if(newCampaign.dids && newCampaign.dids.length > 0){ // send campaign specific users did
                                //var match = {did:{$in:newCampaign.dids}, p:'iOS', active:true, gcmid:{$exists:true}};
                                //var match = {did:{$in:newCampaign.dids}, p:'iOS', active:true};
                                var match = {
                                    nosql : {did:{$in:newCampaign.dids}, p:'IOS', active:true},
                                    sql : " Where active=true and p='IOS' and did in('"+ newCampaign.dids.join("','") +"')"
                                };
                                campaignUtils.getUsersMsgToken(match, params.qstring.app_id, newCampaign._id)
                                    .then(([gcmids, fcmids]) =>{
                                        logger.info(`gcmid ${gcmids}`)
                                        logger.info(`gcmid ${fcmids}`)
                                        campaignUtils.sendiOSNotification(options, gcmids, fcmids, newCampaign.payload, false, 'transaction_camp_'+params.qstring.app_id);
                                    })
                                    .catch((error) =>{
                                        logger.error(`iOS Given did gcmids not found! ${error}`);
                                        return;
                                    });
                            }
                            else if(newCampaign.users && newCampaign.users.length > 0){ // send campaign specific users id
                                //var match = {_custom_UserId:{$in:newCampaign.users}, p:'iOS', active:true, gcmid:{$exists:true}};
                                //var match = {_custom_UserId:{$in:newCampaign.users}, p:'iOS', active:true};
                                let users = newCampaign.users.map((user) =>{
                                    return '[{"_custom_UserId": '+user+'}]';
                                })
                                var match = {
                                    nosql : {_custom_UserId:{$in:newCampaign.users}, p:'IOS', active:true},
                                    sql : " Where active=true and p='IOS' and _custom @> ANY (ARRAY ["+users+"]::jsonb[])"
                                };
                                campaignUtils.getUsersMsgToken(match, params.qstring.app_id, newCampaign._id)
                                    .then(([gcmids, fcmids]) =>{
                                        campaignUtils.sendiOSNotification(options, gcmids, fcmids, newCampaign.payload, false, 'transaction_camp_'+params.qstring.app_id);
                                    })
                                    .catch((error) =>{
                                        logger.error(`iOS Given users gcmids not found! ${error}`);  
                                        return;
                                    });
                            }
                            else{
                                logger.info(`iOS Please send gcmids OR did OR users as array`);   
                            }
                        // }
                        // else{
                         
                        //     return;
                        // }
                    });
                }

                // send response back to client
                if(sendResponse){
                    return callback({statusCode: 200, customdata : camp_data.custom, msg: {message:"success", campaignID:newCampaign._id, campaignName:newCampaign.name}});
                }
                else{
                    return callback({statusCode: 400, msg: 'GCM/GCM Key or APN cert Does not found!. Please check your app setting.'});
                }
            })
            .catch((error) =>{
                logger.error(`asdasf error =>  ${error}`);
                return callback({statusCode: 400, msg: 'GCM/GCM Key or APN cert Does not found!. Please check your app setting.'});
            });
    });
}

exports.getActiveCampaigns = function(params){
    try{
      cacheApi.getKey('trans_campaigns_'+ params.qstring.app_id,function(err,result){
          if(err || result==null || result ==''){
            logger.info(`getActiveCampaigns transactional call db`); 
              var retVal=[];
              var retAllVal=[];
              common.db.collection('transaction_camp_'+ params.qstring.app_id).find({}).toArray(function(err,campaigns){
                  if(err){
                    logger.error(`error ${err}`); 
                      return common.returnOutput(params,retVal);
                  }
                  else{
                      campaigns.forEach(function(camp){
                            if(camp.payload){
                              camp.payload.camp_id = camp._id;
                              camp.payload.cmd = "#transactional";
                              // validate cdata if it's more than 2kb send url to get form db
                              if(camp.payload && camp.payload.cdata){
                                  if(common.calculateDataSize(camp.payload.cdata)  > common.config.campaignPayloadSize ){
                                      camp.payload.cdata = common.config.host+"/o/templates/getCustomData?app_id="+params.qstring.app_id+"&api_key="+params.qstring.api_key+"&tid="+camp._id+"&ct=trans";
                                  }
                              }

                              // validate lastTPullTime key that is exists or not in request
                              if(params.qstring.lastTPullTime){
                                  // validate st key in campaign
                                  if(camp.payload.st == undefined){
                                      camp.payload.st = camp.createdAt
                                  }

                                  // compare lastTPullTime and campaign start time to get lasted campaign
                                  if(params.qstring.lastTPullTime < camp.payload.st){
                                      retVal.push(camp.payload);
                                  }
                              }
                              else{
                                  retVal.push(camp.payload);
                              }

                              retAllVal.push(camp.payload);
                          }
                      });

                      // set active campaign into cache
                      if(retAllVal.length > 0){
                          cacheApi.setKey('trans_campaigns_'+ params.qstring.app_id,JSON.stringify(retAllVal));
                      }
                      return common.returnOutput(params,retVal);
                  }
              });
          }
          else {
            logger.info(`got in transaction from cache`); 
              let data = JSON.parse(result);
              if(params.qstring.lastTPullTime){
                  let retVal = [];
                  data.forEach(function(camp){
                      if(params.qstring.lastTPullTime && camp.payload && camp.payload.st){
                          if(params.qstring.lastTPullTime < camp.payload.st){
                              retVal.push(camp.payload);
                          }
                      }
                      else{
                          retVal.push(camp.payload);
                      }
                  });
                  return common.returnOutput(params,retVal);
              }else{
                  return common.returnOutput(params,data);
              }
          }
      });
    }
    catch(e){
        logger.error(`error => ${e.message}`);
        return common.returnOutput(params,[]);
    }
}

exports.getTransactionCampaignResponse = function(params){
    // validate arguments
    if (params.qstring.campid == '' || params.qstring.campid == undefined) {
        return common.returnMessage(params, 400, "campid is missing or blank");
    }
    else {
        if(params.qstring.isTransactional){
            // store transactional campaign information
            common.db.collection('transaction_camp_'+params.qstring.app_id).findOne({_id:common.db.ObjectID(params.qstring.campid)}, function(err, result){

                 
                if(err){
                    return common.returnMessage(params, 400, "campaign not found!");
                }
                else {
                    // get campaign response result
                    common.db.collection('response_transaction_camp_'+params.qstring.app_id).findOne({_id:'transaction_camp_'+params.qstring.app_id+params.qstring.campid}, function(err, campRes){
                        logger.info(`transactional campaign information 1 => ${campRes}`);  
                        if(err){
                            return common.returnMessage(params, 400, "campaign not found!");
                        }
                        else {
                            campaignResponse(params, result, campRes);
                        }
                    });
                }
            });
        }
        else{
            // store engagement campaign information
            common.db.collection('campaigns_'+params.qstring.app_id).findOne({_id:common.db.ObjectID(params.qstring.campid)}, function(err, result){
                logger.info(`transactional campaign information 2 => ${result}`);   
                if(err){
                    return common.returnMessage(params, 400, "campaign not found!");
                }
                else {
                    // get campaign response result
                    common.db.collection('response_campaigns_'+params.qstring.app_id).findOne({_id:'campaigns_'+params.qstring.app_id+params.qstring.campid}, function(err, campRes){
                        logger.info(`transactional campaign information 3 => ${campRes}`);  
                        if(err){
                            return common.returnMessage(params, 400, "campaign not found!");
                        }
                        else {
                            campaignResponse(params, result, campRes);
                        }
                    });
                }
            });
        }
    }
}

// campaign Response
var campaignResponse = (params, result, campRes)=>{
    let response = {success:[], failed:[]}
    try{
        if(campRes && campRes.fcm && campRes.fcm.results){
            campRes.fcm.results.forEach((res, index)=>{
                //delete res.token;
                res.did = (result.dids)? (result.dids[index])? result.dids[index] : result.dids[0] : (result.users)? (result.users[index])? result.users[index] : result.users[0] : (result.gcmids)? (result.gcmids[index])? result.gcmids[index] : result.gcmids[0] : '';
                if(res.message_id){
                    response.success.push(res.did);
                }
                else {
                    response.failed.push(res);
                }
            });
        }

        if(campRes && campRes.gcm && campRes.gcm.results){
            campRes.gcm.results.forEach((res, index)=>{
                //delete res.token;
                res.did = (result.dids)? (result.dids[index])? result.dids[index] : result.dids[0] : (result.users)? (result.users[index])? result.users[index] : result.users[0] : (result.gcmids)? (result.gcmids[index])? result.gcmids[index] : result.gcmids[0] : '';
                if(res.message_id){
                    response.success.push(res.did);
                }
                else {
                    response.failed.push(res);
                }
            });
        }
        response.custom = result.customData;
        logger.info(`data ${result.customData}`);
        if(!(campRes && campRes.gcm && campRes.gcm.results) && !(campRes && campRes.fcm && campRes.fcm.results)){
            response.failed = (result.dids)? result.dids : (result.users)? result.users : (result.gcmids)? result.gcmids : [];
            response.error = "Campaign delivery failed!"
        }

        return common.returnMessage(params, 200, response);
    }
    catch (e){
        logger.error(`error : ${e.message}`); 
        response.error = "Campaign delivery failed!"
        return common.returnMessage(params, 400, response);
    }
}
