/**
 * Campaign utils nodejs module for send notifications to Android and ios
 * Android use FCM and iOS use APN to send notification
 * @author Manish Yadav
 * @Updation By Saurabh Singh - Tarun Anand(Under Guidance)
 * @copyright Semusi Technologies PVT LTD
 */

  const nodeFCM = require('./semusi-fcm'),
        FCM = require('fcm-push'),
		logger = require('../../logger'),
		webPush = require('./semusi.webPush'),
		apnPush = require('./semusi.apndirectpush.js'),
		common = require('./common'),
		apns = require("apns"),
		Promise = require('bluebird'),
		validate = require('../constants/constants.js'),
		cacheApi = require('./semusi.cache'),
		uuid=require('uuid'),
		fs = require("fs"),
		path = require('path'),
		atob = require('atob'),
		campaignUtils = {};
		let fcmKey;
	/**
	 * get app FCM key and iOS certificates
	 * @param appId is user app id to get GCM Key
	 **/
campaignUtils.getGCMKeyAndiOSCert = function(appId){
	return new Promise( (resolve, reject) =>{
		common.db.collection('apps').findOne({"isAppDeleted":"false","_id": common.db.ObjectID(appId)},function(err,appData){
			if(err){
				return reject(err);
			}
			else if (appData) {
				let keyCert = {
					android: {
						dev: "",
						prod: "",
					},
					ios: {
						dev: {
							cert1: "",
							cert2: "",
							passKey1: "",
							passKey2: "",
						},
						prod: {
							cert1: "",
							cert2: "",
							passKey1: "",
							passKey2: "",
						}
					},
					linkingField: ''
				}
				// check FCM dev certificates
				if (appData.dev_gcm_key) {
					keyCert.android.dev = appData.dev_gcm_key;
				}
				// check FCM prod certificates
				if (appData.gcm_key) {
					keyCert.android.prod = appData.gcm_key;
				}

				// check iOS dev certificates
				if (appData.dev_ios_cert1 && appData.dev_ios_cert1 != "") {
					keyCert.ios.dev.cert1 = appData.dev_ios_cert1;
				}
				// check iOS dev certificates
				if (appData.dev_ios_cert2 && appData.dev_ios_cert2 != "") {
					keyCert.ios.dev.cert2 = appData.dev_ios_cert2;
				}

				//production mode data for push.
				if (appData.ios_cert1 && appData.ios_cert1 != "") {
					keyCert.ios.prod.cert1 = appData.ios_cert1;
				}
				if (appData.ios_cert2 && appData.ios_cert2 != "") {
					keyCert.ios.prod.cert2 = appData.ios_cert2;
				}

				// add linkingField
				if (appData.linkingField) {
					keyCert.linkingField = appData.linkingField;
				}
				keyCert.fcmKey = (appData.isappmodeproduction) ? appData.fcmKey_prod : appData.fcmKey_dev;
				return resolve(keyCert);
			}
			else {
				return reject(false);
			}
		});
	});
}

campaignUtils.getDidsFromAppUsers = function (match, appid) {
	return new Promise((resolve, reject) => {
		try {
			logger.info('match in getDidsFromAppUsers ==>', match)
			common.db.collection('app_users' + appid).find(match, { _id: 0, did: 1 }).toArray(function (err, users) {
				if (err) {
					return reject(err);
				} else {
					const mappedUsers = users.map(item => item.did);
					resolve(mappedUsers)
				}
			})

		} catch (error) {
			logger.error(`error in getDidsFromAppUsers => ${error}`);
			return reject(error);
		}
	})
}

// get users gcmids or APN TOKEN from mongo collection
campaignUtils.getUsersMsgToken = function (match, appid, isCampaignId) {
	return new Promise((resolve, reject) => {
		try {
			campaignUtils.getDidsFromAppUsers(match, appid).then((data) => {
				logger.info(`Data from  getDidsFromAppUsers=====>${JSON.stringify(data)}`)
				let nosql = (match.nosql) ? match.nosql : match;
				if (nosql.p == 'Android') {
					nosql.p = 'android';
				}
				common.db.collection('usertoken_' + appid).find({ did: { $in: data } }, { pushtoken: 1, _id: 0, did: 1, p: 1 }).toArray(function (err, users) {
					if (err) {
						return reject(err);
					}
					else {
						logger.info(`Response From User Token for Android ${JSON.stringify(users)}`)
						//get these details to set data into Cache 			
						let [fcmids, dids] = prepareTokensList(users, isCampaignId, appid);
						if (fcmids.length > 0 || dids.length > 0) {

							return resolve([fcmids, dids]);
						} else {
							logger.info(" Error : Failing As Length is Zero in FcmIds and Dids")
							return reject("Corresponding Data Not Found");
						}
					}
				});
			})
		}
		catch (e) {
			logger.error(`cache error=> ${e}`);
			return reject(e);
		}
	})
}

// get users gcmids or APN TOKEN from mongo collection
campaignUtils.getUsersMsgTokenIos = function (didDetails, appid, isCampaignId) {
	return new Promise((resolve, reject) => {
		try {
			let mappedUsers = didDetails.map((item) => item.did)
			common.db.collection('usertoken_' + appid).find({ did: { $in: mappedUsers } }, { pushtoken: 1, _id: 0, did: 1, p: 1 }).toArray(function (err, users) {
				if (err) {
					return reject(err);
				}
				else {
					if (users.length > 0) {
						logger.info(`Response From User Token for IOS ${JSON.stringify(users)}`)
						//get these details to set data into Cache 			
						let [fcmids, dids, gcmids] = prepareTokensList(users, isCampaignId, appid);
						if (gcmids.length > 0 || dids.length > 0) {
							logger.info(`Gcmids are greater than Zero IOS`)
							let matchingItem2 = users.map(item2 => {
								const matchingItem1 = didDetails.find(item1 => item1.did === item2.did);
								return {
									...matchingItem1,
									gcmid: item2.pushtoken
								};
							});
							return resolve(matchingItem2);
						}
					} else {
						logger.info(`Error : Failing as getting Zero Length in Users in the IOS`)
						return resolve([]);
					}
				}
			});
		}
		catch (e) {
			logger.error(`cache error=> ${e}`);
			return reject(e);
		}
	})
}

let prepareTokensList = (users, isCampaignId, appid) => {
	let gcmids = [], fcmids = [], dids = []; dids = []; userId = []; sdkvs = [];
	users
		.map(user => {
			let { pushtoken = null, did = null } = user;
			if (user.p == 'ios') {
				gcmids.push(pushtoken)
			} else {
				fcmids.push(pushtoken);
			}
			dids.push(did);

		});

	// set users into catch
	if (isCampaignId) {
		cacheApi.setKey('transaction_key' + isCampaignId + appid, JSON.stringify(dids));
	}

	return [fcmids, dids, gcmids];
}

// get users keys for web push
campaignUtils.getWebUsersToken = function (match, appid) {
	return new Promise((resolve, reject) => {
		try {
			let nosql = (match.nosql) ? match.nosql : match;
			nosql.p = "Web";
			common.db.collection('app_users' + appid).find(nosql, { fcmid: 1, _id: 0, did: 1, pv: 1 }).toArray(function (err, users) {
				if (err) {
					return reject(err);
				}
				else {
					let fcmid = [];
					users.forEach((user) => {
						if (user.fcmid && user.pv) {
							// fcmid.push(user.fcmid)
							let obj = {
								pv: user.pv,
								fcmid: user.fcmid
							}
							fcmid.push(obj)
						}
					});
					if (fcmid.length > 0) {
						return resolve(fcmid);
					}
					else {
						return reject("Web keys does not found!");
					}
				}
			});
			//}
		}
		catch (e) {
			logger.error(`cache error=> ${e}`);
			return reject(e);
		}
	})
}

campaignUtils.sendWebPush = function (match, config, app_id, payload, segmentInfo) {
	let activeCollection = 'campaigns_' + app_id;

	common.db.collection('templates_' + app_id).findOne({ _id: common.db.ObjectID(payload.tid) }, function (error, template) {
		if (error) {
			logger.error(`web push template=> ${error}`);
		}
		else {
			if (segmentInfo != undefined) {
				//control flow only if who with DID based 
				if(segmentInfo.who.length > 0 && segmentInfo.who[0].category=='Device' &&  segmentInfo.who[0].operand=='did' ){
				campaignUtils.getWebUsersToken(match, app_id)
					.then((tokens) =>{
					populateWebPushObject(template.template, payload, app_id);
					if(segmentInfo.what.length > 0 && segmentInfo.what[0].category=='Events'){
						campaignUtils.sendInAppWebPush(app_id, tokens, config, payload.camp_id,template);
					}else{
						let blob = semusiConfig.blobContainerCDN
						if(semusiConfig.uploadAssets[0]=="Azure"){
							blob += app_id 
						}
						campaignUtils.sendWebPushNotification(config, tokens, payload, activeCollection, payload.camp_id, (common.isValidUrl(template.template.icon)) ? template.template.icon :(template.template.icon.includes(validate.getCDN("azureCDN"))) ? template.template.icon.substring(template.template.icon.lastIndexOf('/')) : blob + template.template.icon, app_id);
					}
				})
				.catch(error =>{
					logger.error(`Web push not not sent!=> ${error}`);
					return;
				});
			}
        }
	}
    });
}
// function  to send inapp webpush
campaignUtils.sendInAppWebPush = function (appid, tokens, config, cid, template) {
	logger.info(`call slient web push=> `);
	campaignUtils.getActiveCmpData(appid,cid).then((cmpData) =>{
		let blob = semusiConfig.blobContainerCDN
		if(semusiConfig.uploadAssets[0]=="Azure"){
			blob += app_id 
		}
		campaignUtils.sendWebPushNotification(config, tokens, payload, activeCollection, payload.camp_id, (common.isValidUrl(template.template.icon)) ? template.template.icon :(template.template.icon.includes(validate.getCDN("azureCDN"))) ? template.template.icon.substring(template.template.icon.lastIndexOf('/')) : blob + template.template.icon, app_id);
	})
		.catch(error => {
			logger.info(`error send in app push=> ${error}`);
		});

}

// function toget cmp data  to send inapp webpush 
campaignUtils.getActiveCmpData = function (appId, cid) {
	return new Promise((resolve, reject) => {
		setTimeout(function () {
			common.db.collection('activecampaign_' + appId).find({ '_id': common.db.ObjectID(appId), }, { data: 1 }).toArray(function (err, result) {
				if (!err) {
					let cmpLenght = result[0].data.length;
					let cmp = result[0].data[cmpLenght - 2];
					let cdata = {
						"ai_tag": "ai_pn",
						"activeCampaigns": [cmp],
						"sp": "true"
					};
					resolve(cdata);
				} else {
					reject(err);
				}
			});
		}, 2000);
	})
}

// check certificates at the path and upload from redis 
campaignUtils.checkCertificates = function (app_id) {
	return new Promise((resolve, reject) => {
		try {
			logger.info(`Checking Certificates on the path ==>`);
			common.db.collection('apps').findOne({ '_id': common.db.ObjectID(app_id) }, async function (err, app) {
				if (err || app == null) {
					logger.error("Error while checking Checking Certificate");
					// return resolve(false)
				} else {
					// this condition is to check if there are certificates uploaded for the selected app or not
					if (app.ios_cert3 !== undefined || app.android_cert3 !== undefined) {
						// Define File names Based On Mode of the app ,be it Prod or Development 
						const mode = app.isappmodeproduction ? "prod" : "dev";
						const iosCertPemFileName = app.isappmodeproduction ? app.ios_cert_pem : app.dev_ios_cert_pem;
						const iosCertPemKeyName = app.isappmodeproduction ? app.ios_cert_key : app.dev_ios_cert_key;
						const iosCertFileName = app.isappmodeproduction ? app.ios_cert3 : app.dev_ios_cert3;
						const androidCertFileName = app.isappmodeproduction ? app.android_cert3 : app.dev_android_cert3;
						try {
							let results;

							// For the case of p12
							if (iosCertPemFileName && iosCertPemKeyName) {
								// Use Promise.all to wait for all 4 checkandSetFiles calls
								results = await Promise.all([
									checkandSetFiles(androidCertFileName, app_id, mode, "androidCertificate"),		// android Certificate								checkandSetFiles(androidCertFileName, app_id, mode, "androidCertificate"),
									checkandSetFiles(iosCertFileName, app_id, mode, "iosCertificate"),
									checkandSetFiles(iosCertPemFileName, app_id, mode, "iosCertificatepem"),
									checkandSetFiles(iosCertPemKeyName, app_id, mode, "iosCertificatepemkey")
								]);
							} else {
							// For the case of p8
								results = await Promise.all([
									checkandSetFiles(iosCertFileName, app_id, mode, "iosCertificate"),				//Ios p8 Certificate
									checkandSetFiles(androidCertFileName, app_id, mode, "androidCertificate")		// android Certificate
								]);
							}

							// Check if all results are true
							const allTrue = results.every(result => result === true);

							if (allTrue) {
								resolve(true);
							} else {
								resolve(false);
							}
						} catch (error) {
							logger.error(`Error While checking Certificates => ${JSON.stringify(error)}`);
							reject(error);
						}

					} else {
						logger.info(` Certificates not found in the db`);
						return resolve(false);
					}
				}
			});
		} catch (e) {
			logger.error(`Error checkIosCertificate => ${e}`);
			return reject(e);
		}
	});
}


function checkandSetFiles(pathfilename, app_id, mode, cacheFilename) {
	// Check if file is undefined, null, or empty string
	if (!pathfilename) {
		logger.error('Invalid pathfilename');
		return false
	}
	let certificatePath = path.join(__dirname, '../../frontend/express/public/appcertificates/', app_id)
	let target_path = path.join(__dirname, '../../frontend/express/public/appcertificates/', app_id, '/', pathfilename)
	if (fs.existsSync(target_path)) {
		logger.info(`Certificate exist ==>${pathfilename}`); // file exists on path
		return true;
	} else {

		logger.info(`Certificate not exist ==>${pathfilename} Will upload from the Cache Now `);

		cacheApi.getKey(cacheFilename + "_" + mode + "_" + app_id, function (err, result) {
			if (err || result == null) {

				logger.error(`Cert of this name ${pathfilename} not found / Error in redis while getting Certs as ====> ${JSON.stringify(err)}`);
				return false;
			} else {
				logger.info(`Cert of this name ${pathfilename} Data Found in Cache `);

				let certData = atob(result);
				fs.mkdir(certificatePath, function (err) {
					if (err) {
						logger.error(`Error while mkdir==${err}`);
					}

					fs.writeFile(target_path, certData, function (err) {
						if (err) {
							logger.info(`Error in create file of ${pathfilename}  from Cache ${err}`);
							return false;
						} else {
							logger.info(`File Created for of ${pathfilename}  from Cache `);
							return true;
						}
					});
				});
			}
		});
	}
}


// set expire of activeCamps in cache
campaignUtils.checkAndSetExpire = function (entireDoc, appId) {
	let dataArray = entireDoc.data;
	let currentDate = parseInt(moment().valueOf() / 1000);
	let secondsToEd = 0;
	dataArray.forEach(function (campData) {
		if ((parseInt(campData.ed) / 1000) - (currentDate) > secondsToEd) {
			secondsToEd = (parseInt(campData.ed) / 1000) - (currentDate);
		}
	});
	cacheApi.expire('activecampaign_' + appId, parseInt(secondsToEd));
}
//When campaign is set to draft this function removes the campaign from ActiveCampaign collection and updates the redis

campaignUtils.removeAllDataFromDb = function (appId, Cid, api_key) {

	// get the existing document from db
	common.db.collection('activecampaign_' + appId).findOne({ "_id": common.db.ObjectID(appId) }, function (err, result) {
		if (err || result == null) {
			logger.error(`error finding Document in collections  => ${err}`);
		} else {

			let activeCampData = result.data;
			let index = -1;

			// getting the location in the existing document
			for (let i = 0; i < activeCampData.length; i++) {
				if (JSON.stringify(activeCampData[i]._id).localeCompare(JSON.stringify(Cid)) == 0) {
					index = i;
				}
			}
			if (index > -1) {
				activeCampData.splice(index, 1);

				//   call to the insert Function with Appid and , data field with removed element in array
				campaignUtils.insertData(appId, activeCampData, api_key)
					.then((template) => {

					})
					.catch(error => {
						logger.info("Error in Removing Data From Active Campaign Collection");
						logger.error(error);
						return;
					});

			} else {
				logger.info("Couln't find the exisiting Campaign in the Active Collection");
			}
		}
	});
}
// get the template data 
campaignUtils.getTemplateData = function (appId, tid) {
	return new Promise((resolve, reject) => {
		common.db.collection('templates_' + appId).findOne({ "isTemplateDeleted": "false", "_id": common.db.ObjectID(tid) }, function (err, template) {

			if (err) {
				logger.error(`error Couldn't find Template => ${err}`);
			} else {

				return resolve(template.template);
			}
		})
	})
}
// function inserts the data to the DB 
campaignUtils.insertData = async function (appId, activeCampData, api_key) {
	const insertDetails = await common.prepareGetActiveCampaignData(activeCampData, appId, api_key)
	common.db.collection('activecampaign_' +appId).update({'_id':common.db.ObjectID(appId), },{$set:{data:insertDetails,updatedAt:(common.getCurrentEpochTime() * 1000) } },async function (err, result) {
		 if(!err){
			logger.info(`Data Updated in Active Campaign Successfully `)

			 let entireDoc = {
				 _id:common.db.ObjectID(appId),
				 data:insertDetails,
				 updatedAt:( common.getCurrentEpochTime() *1000)
			 }
			 cacheApi.setKey('activecampaign_' +appId, JSON.stringify(entireDoc));
			 campaignUtils.checkAndSetExpire(entireDoc,appId);
			 logger.info(` Inserting campaign in active Campaign collection =>`);
		 }else{
			 logger.error(`Error Updating Document In Activecampaign collection => ${err}`);
		 }  
	 });
}

//When campaign is set to Active this function add the campaign to ActiveCampaign collection and updates the redis
campaignUtils.setAllDataAtDb = function (appId, cid, api_key) {
	let activeCampData = [];
	let allData;
	common.db.collection('campaigns_' + appId).findOne({ "_id": common.db.ObjectID(cid) }, function (err, cmp) {

		if (err || cmp == null) {
			logger.info("Error! Couldn't Find Campaign")
			logger.error(`Error! Couldn't Find Campaign => ${err}`);
		} else {
			allData = cmp;
			let campaign = cmp


			if (campaign.tid == null || campaign.tid == undefined) {
				logger.error("Error! No TemplateId in the Found Campaign")
			} else {

		// call the function to get template data
		campaignUtils.getTemplateData(appId,campaign.tid)
		.then(async (template) =>{

						allData.template = template;
						activeCampData.push(allData);



			common.db.collection('activecampaign_'+appId).findOne({"_id":common.db.ObjectID(appId)}, async function(err, currentActiveObject) {
				if(currentActiveObject ==null){

					const insertDetails = await common.prepareGetActiveCampaignData(activeCampData, appId, api_key)
					// inserting Data for the first time /Creating Collection
					common.db.collection('activecampaign_' + appId).insert({ '_id': common.db.ObjectID(appId), data:insertDetails, updatedAt: (common.getCurrentEpochTime() * 1000) },async function (err, result) {
						 if(!err){
							logger.info(`Data inserrted in Active Campaign Successfully `)
							let entireDoc = {
								_id:common.db.ObjectID(appId),
								data:insertDetails,
								updatedAt:( common.getCurrentEpochTime() *1000)
							}
							 cacheApi.setKey('activecampaign_' +appId, JSON.stringify(entireDoc));
							 campaignUtils.checkAndSetExpire(entireDoc,appId);
						 }else{
							 logger.error(`error Insetrting new Document to collection => ${err}`);
						 }                          
					 });
				}else{
 
					let found = false ; 
					activeCampData = currentActiveObject.data;
 
					 //  for Update  Campaign case:  check if there is Campaign Already in the Collection with same CampID, 

								//  if found update that object in the array in the existing Document 
								for (let i = 0; i < activeCampData.length; i++) {
									if (JSON.stringify(activeCampData[i]._id).localeCompare(JSON.stringify(campaign._id)) == 0) {
										found = true;
										activeCampData[i] = allData;
										//if the campaign is Now Draft add d as true in activeCampaign Data
										if(allData.st == "DRAFT"){
											logger.info(`Campaign Deacticated d set as true`)
											activeCampData[i].d = true
										}
									}
								}
								//if Not found Append the data in the Array in the existing Document
								if (found == false) {
									activeCampData.push(allData)
								}


								//   call to the insert Function with Appid and , data field 
								campaignUtils.insertData(appId, activeCampData, api_key)
									.then((template) => {

									})
									.catch(error => {
										logger.info("Error in Inserting Data");
										logger.error(`Error in Insetrting Data=> ${err}`);
										return;
									});
							}

						});
					})
					.catch(error => {
						logger.error(`error Couldn't get template from collection => ${err}`);
						return;
					});
			}
		}
	});
}

async function populateWebPushObject(template, data, app_id){
    data.title = template.title,
    data.message = template.message,
	data.tid = undefined;
    data.eurl = (template.externalUrl) ? template.externalUrl : undefined,
	data.url = (template.externalUrl) ? template.externalUrl : undefined,
	data.app_id = (app_id) ? app_id : '';
	let blob = semusiConfig.blobContainerCDN
	if(semusiConfig.uploadAssets[0]=="Azure"){
		blob += app_id 
	}
	if(common.isValidUrl(template.icon)){
		data.icon =  template.icon;
	}else{
		data.icon =  (template.icon == "") ? "" : (template.icon.includes(validate.getCDN("azureCDN"))) ? blob + template.icon.substring(template.icon.lastIndexOf('/')) : blob+template.icon ;
	}
	if(common.isValidUrl(template.extendedImage)){
		data.eni =  template.extendedImage;
	}else{
		// we have to check if template.extendedImage exist or not
		data.eni =  (template.eni == "") ? "" : (template.extendedImage && template.extendedImage.includes(validate.getCDN("azureCDN"))) ? blob + template.extendedImage.substring(template.extendedImage.lastIndexOf('/')) : blob+template.extendedImage ;
	}
	data.action = (template.actions) ? template.actions : undefined;
	if (template.cdata) {
		let cdataObj = await common.getCdataObj(template.cdata)
		data.cdata = cdataObj;
	}
}


/**
 * Send FCM playlaod to end users
 * @param fcmids end users registered fcm tokens like
 * [token1, token2]
 * @param payload has #updateCommand
 */
campaignUtils.sendAndroidNotification = (fcmKey, fcmids, dids, payload, pushCommand, active) => {
	if (fcmids.length > 0) {
		while (fcmids.length > 0) {
			let userFcms = fcmids.splice(0, 1000);
			let dids = dids.splice(0, 1000);
			campaignUtils.sendFCMMessageWithPayload(fcmKey, userFcms, dids, payload, active);
		}
	}
	else {
		logger.info(`fcmids :=> ${fcmids} doesn't have any tokens!`);
	}
}

/**
 * Send FCM playlaod to end users
 * @param fcmids end users registered fcm tokens like
 * [token1, token2]
 * @param content has #updateCommand
 */
campaignUtils.sendFCMMessageWithPayload = function (jsonFile, userFcms, dids, data, active, app_id, cid, appId, geo, activeCampaign) {
	logger.info(`geo flag :=> ${geo}`);
	//Handle geo Push
	if (geo) {
		// Send Payload to Sender Function	
		campaignUtils.setActiveGeoFenceData(userFcms, jsonFile, dids, app_id, active, cid, geo, activeCampaign);
	} else {
		return new Promise((resolve, reject) => {
			let payload = (data.pushCommand) ? { message: data.pushCommand } : data;
			//Send Notification with Custom Function for Sending Notification 
			common.db.collection(app_id).findOne({ _id: common.db.ObjectID(cid) }, function (err, campaigns) {

				nodeFCM.sendMessageWithPayload(jsonFile, userFcms, dids, data, active, app_id, cid, campaigns, appId)
					.then(res => {
						return resolve(res);
					})
					.catch(err => {
						return reject(err)
					});
			});
		});
	}
}

// Create function to get Active GeoFence Data 
campaignUtils.setActiveGeoFenceData = function (userFcms, fcmKey, dids, app_id, active, cid, geo, activeCampaign) {
	let childApproved;
	let childDeleted;
	let sdkDeletedFlag;
	if (activeCampaign.childIds && activeCampaign.childIds.length > 0) {
		if (activeCampaign.childIds.approved == true) {
			childApproved = true;
		} else {
			childApproved = false;
		}
		if (activeCampaign.childIds.deleted == true) {
			childDeleted = true;
		} else {
			childDeleted = false;
		}
		sdkDeletedFlag = activeCampaign.d;
	} else {
		sdkDeletedFlag = activeCampaign.d;
	}
	let obj = {};
	obj._id = activeCampaign._id;
	obj.tid = activeCampaign.tid;
	obj.t = activeCampaign.t;
	obj.sd = activeCampaign.sd;
	obj.ed = activeCampaign.ed;
	obj.ud = activeCampaign.ud;
	obj.d = sdkDeletedFlag;
	obj.delays = 1;
	if (semusiConfig.appidwithNoDelay.includes(app_id)) {
		obj.delayi = 0;
	} else {
		obj.delayi = 15;
	}
	obj.delayu = 'Seconds';
	obj.fre = {};
	if (activeCampaign.c_event) {
		obj.c_event = activeCampaign.c_event;
		obj.c_period = activeCampaign.c_period;
	}
	obj.fre.dp = 0;
	if (activeCampaign.d == false) {
		obj.fre = activeCampaign.fre;
		obj.fre.dp = 0;
		if (activeCampaign.daySelector == "ALLWEEK") {
			obj.allweek = true;
			obj.days = [];
		} else {
			obj.allweek = false;
			obj.days = activeCampaign.days;
		}
		if (activeCampaign.timeSelector == "ALLDAY") {
			obj.allday = true;
		} else {
			obj.allday = false;
			if (activeCampaign.time && activeCampaign.time.length > 0) {
				obj.time = {
					start: activeCampaign.time[0],
					end: activeCampaign.time[1]
				};
			} else {
				obj.time = {
					start: 8,
					end: 20
				};
			}

		}
	}
	let activePushObject = populatePushObject(activeCampaign.template);
	obj.data = activePushObject;
	obj.aud = JSON.parse(activeCampaign.segmentinfo);
	let payload = [];
	payload.push(obj);
	//Send Notification with Custom Function for Sending Notification 
	return new Promise((resolve, reject) => {
		nodeFCM.sendMessageWithPayload(fcmKey, userFcms, dids, payload, active, app_id, cid, activeCampaign, app_id, geo, activeCampaign)
			.then(res => {
				logger.info(` node FCM Geo Fence res => ${res}`)
				return resolve(res);
			})
			.catch(err => {
				logger.error(`did error=> ${err}`);
				return reject(err)
			});
	});
}


// 'Notification - Type ' - Push 


async function populatePushObject(template) {
	let data = {};
	data.nh = template.notificationHeader;
	data.nd = template.notificationDescription;
	data.ni = template.notificationImage;
	data.end = template.expandedNotificationDescription;
	data.eni = template.expandedNotificationImage;
	data.eurl = template.externalUrl;
	data.et = template.notificationType;
	data.actions = template.actions;
	data.sound = template.sound;
	data.vibrate = template.vibrate;
	data.badge = template.badge;
	if (template.cdata) {

		let cdataObj = await common.getCdataObj(template.cdata)
		data.cdata = cdataObj;
	}
	return data;
}

// send apn to ios
campaignUtils.sendAPNMessageWithPayload = function (options, token, fcmids, payload, active) {
	let connection, notification;
	connection = new apns.Connection(options);
	notification = new apns.Notification();
	notification.payload = payload;
	notification.badge = 1;
	notification.expiry = Math.floor(Date.now() / 1000) + 86400; // Expires 1 Day from now.
	notification.alert = payload.nh;
	notification.device = new apns.Device(token);
	connection.sendNotification(notification);
}


/**
 * Send APN playlaod to end users
 * @param options has iOS certificates, ky file and pass - phrase
 * @param tokens end users registered apn to-kens like
 *   [token1, token2]
 * @param fcmids end users registered fcm to-kens like
 * [token1, token2]
 * @param payload has #updateCommand
 */
campaignUtils.sendiOSNotification = (options, tokens, fcmids, payload) => {
	let j = 0;
	let deviceArr = [];
	for (let i = 0; i < tokens.length; i++) {
		if (j == 100 || (i + 1 == tokens.length)) {
			deviceArr.push(tokens[i]);
			let responseData = apnPush.pushTransactional(options, deviceArr, payload);
			j = 0;
			deviceArr = [];
		}
		else {
			deviceArr.push(tokens[i]);
			j++;
		}
	}
}

/**
 * Send web push notification
 * @param {*} config
 * @param {*} tokens
 * @param {*} content
 * @param {*} active
 */
campaignUtils.sendWebPushNotification = function (config, tokens, payload, active, campid, icon, app_id) {
	//if(tokens.length > 1000){
	while (tokens.length > 0) {
		let [userToken] = tokens.slice(0, 1);
		if (userToken.pv.includes('Mac')) {
			payload.icon = (payload.eni) ? payload.eni : icon;
		} else {
			payload.icon = icon;
		}
		let { fcmid } = userToken;
		delete userToken.pv;

		webPush.pushNotifications(fcmid, payload, config)
			.then((res) => {
				logger.info(`storing web push :: ${res}`);
				campaignUtils.increaseCountResult(app_id, campid)
				storeCampaignResponse(active, campid, {$push:{'web':res}});
			})
			.catch((error) => {
				logger.error(`web push error => ${error}`);
			});
		tokens.splice(0, 1);
	}
}


let storeCampaignResponse = function (collection, campaign_id, response) {
	campaign_id = collection + "" + campaign_id;
	collection = "response_" + collection;
	// update push to count into campaign table
	// common.db.collection(collection).update({_id:campaign_id},response, {'upsert':true}, function(error, dbres){

	// });
}
// Funvtion for increase pushTo count after send push successfully
campaignUtils.increaseCountResult = function(app_id, campid, increment = 1){
	logger.info(`Increasing Count for the campid ===>  ${campid} with Increament as ${increment}`)
	common.db.collection('campaign_statsdata_' + app_id).updateOne({
		_id: campid.toString()
	}, {
		$inc: {
			'reach':increment,
			'pushedTo': increment
		},
	}, {
		upsert: true
	}, function(err, result) {
        if (err) {
			logger.error(`Error While updating Count of Push / Reach for campid  ===>  ${campid} `)
        } else {
            if (result.modifiedCount > 0 || result.upsertedCount > 0) {
               logger.info(`Pushed / Reach increamented Sucessfully for campid ===>  ${campid} `);
            } else {
				logger.info(`No doc mathed for this ${campid}`)
            }
        }
    });
}

// export module
module.exports = campaignUtils;
