var journey = {},
    common = require('./../../utils/common.js'),
    logger = require('../../../logger'),
    async = require('async'),
    moment = require('moment'),
    gcm = require('node-gcm'),
    crypto = require('crypto'),
    apn = require('apn'),
    _ = require('underscore'),
    fs = require('fs');
    //async = require('./../../utils/async.min.js'),
    semusiConfig = require('./../../config.js'),
    //client = require('node-rest-client').Client,
    //proxy = new client(),
    json2csv = require('./../../utils/json-2-csv.js'),
    cacheApi = require('./../../utils/semusi.cache.js'),
    pgsql = require('./../../utils/pgsql.utils.js'),
    Promise = require('bluebird'),
    moment = require("moment"),

    (function (journey) {
        function finalJourneyQuery(tempTable, startDate, app_id){
            var journey = "select journey from " + tempTable + " where dt = '" + startDate  + "'";
            logger.info(`journey=>>  ${journey}`)
            // common.returnMessage(params, 200, "Failed");

            pgsql.executeQuery(journey)
            .then((result) => {
                 
                // var dropTable = "drop table " + tempTable;
                // pgsql.executeQuery(dropTable)
                // var AppEventsquery = "select distinct id,name from app_events_"+ app_id +" where name NOT IN('App_Background','App_Foreground','Session_End','Session_Start','Campaign_Received','Campaign_Deleted','Campaign_Clicked','nan','Campaign_Viewed','_app_crash')";
                 
                
                // var appEventsDataSets =[]
            //     pgsql.executeQuery(AppEventsquery)
            //     .then((resultDataSets) => {
             
            //         // appEventsDataSets = resultDataSets[0];
            //         // var resultData = {
            //         //     links: result,
            //         //     nodes: appEventsDataSets
            //         // };
            //         // // var dropTable = "drop table " + tempTable;
            //         // // pgsql.executeQuery(dropTable)    
             
            //         common.returnMessage(params, 200, "Failed");

            //     })
            //     .catch((error) => {
             
            //         common.returnMessage(params, 200, "Failed");
            //     })
            // })
            // .catch((error) => {
             
                common.returnMessage(params, 200, "Failed");
            })    
        }

        function processCustomQuery(tempTable, startDate, endDate, app_id){
            var listDate = [];
            var startArray = [];
            var endArray = [];
            var dateMove = new Date(startDate);
            var strDate = startDate;

            while (strDate < endDate){
              var strDate = dateMove.toISOString().slice(0,10);
              listDate.push(strDate);
              dateMove.setDate(dateMove.getDate()+1);
            }
             

            while(listDate.length>1){
                for(var i=1; i<listDate.length;i=i+1){
                    startArray.push(listDate[i-1])
                    endArray.push(listDate[i]);
                    listDate.splice(i,1);
                }
            }

            const forLoop = async _ => {

              for (let index = 0; index < startArray.length; index++) {
                var jsonMerge = "select jsonb_merge('"+ tempTable + "', '"+ startArray[index] +"' , '"+ endArray[index] +"')";
                await pgsql.executeQuery(jsonMerge)
                .then((result) => {
                    if(index == (startArray.length-1)){
                        finalJourneyQuery(tempTable, startDate, app_id);
                    }
                    
                })
                .catch((error) => {
                    logger.error(`error => ${error}`); 
                })
              }
            }

            forLoop();
        }

        journey.getjourneyData = function (params) {
    // Define argument properties
    var argProps = {
      'platform': {
        'required': true,
        'type': 'String'
      },
      'journeyRange': {
        'required': true,
        'type': 'String'
      },
    };
    // Validate arguments
    var eventParams = common.validateArgs(params.qstring.args, argProps);
    if (!eventParams) {
      common.returnMessage(params, 400, 'Not enough args');
      return false;
    }
    // Define filter variable
    var filter = params.qstring.args.journeyRange;
    // Handle custom filter
    if (filter == 'custom') {
      var randomString = crypto.randomBytes(3).toString('hex');
      var tempTable = 'journeyquery' + randomString;
      var createTable = {
        text: 'create table $1 as select dt, journey from journeyobject_$2 where pfilter = $3 and dt >= $4 and dt <= $5',
        values: [tempTable, params.qstring.app_id, params.qstring.args.platform, eventParams.startDateNew, eventParams.endDateNew]
      };
      logger.info(`create table=> ${createTable.text}`)
      pgsql.executeQuery(createTable)
      .then((result) => {
        var journey = processCustomQuery(tempTable, eventParams.startDateNew, eventParams.endDateNew, params.qstring.app_id);
        common.returnMessage(params, 200, journey);
      })
      .catch((error) => {
        logger.error(`create table error => ${error}`);
        common.returnMessage(params, 200, "Failed");
      });
    }
        // var Platformvalue = -1
        // if(params.qstring.args.platform=="all"){ Platformvalue = -1
        // }
        // else if(params.qstring.args.platform=="android"){ Platformvalue  = 0
        // }
        // else if(params.qstring.args.platform=="ios"){ Platformvalue = 1
        // }
        // else if(params.qstring.args.platform=="web"){ Platformvalue = 2
        // }
    
        // //Run query for Default Statements
        // if(Platformvalue == -1){
        //     var Journeyquery = "select * FROM journey11_" + params.qstring.app_id + " where dt between '" + eventParams.startDateNew + "' AND '" + eventParams.endDateNew + "' LIMIT 20000";
        // }
        // else {
        //     var Journeyquery = "select * FROM journey11_" + params.qstring.app_id + " where platform = "+ Platformvalue +" and dt between '" + eventParams.startDateNew + "' AND '" + eventParams.endDateNew + "' LIMIT 20000";
        // }
        // var AppEventsquery = "select distinct id,name from app_events_" + params.qstring.app_id + " where name NOT IN('App_Background','App_Foreground','Session_End','Session_Start','Campaign_Received','Campaign_Deleted','Campaign_Clicked','nan','Campaign_Viewed','_app_crash')";
        // var appEventsDataSets;
        // var resultlinks;
         
        // pgsql.executeQuery(Journeyquery)
        // .then((result) => {
        //     resultlinks = result[0];
        //     pgsql.executeQuery(AppEventsquery)
        //         .then((resultDataSets) => {
        //             appEventsDataSets = resultDataSets[0];
        //             var responseData = {
        //                 links: resultlinks,
        //                 nodes: appEventsDataSets
        //             };
                    
        //             var resData = processJourneyData(responseData);
        //             //send all the data in the form of links and Nodes to Client
        //             var resultData = {
        //                 links: resData,
        //                 nodes: appEventsDataSets
        //             };
        //             params.res.writeHead(200, {
        //                 'Content-Type': 'application/json; charset=utf-8'
        //             });
        //             var finalData = '{"result":'+JSON.stringify(resultData)+'}';
        //             params.res.write(finalData);
        //             params.res.end();
        //         })
        //         .catch((error) => {
         
        //             common.returnMessage(params, 200, "Failed");
        //         })
        // })
        // .catch((error) => {
         
        //     common.returnMessage(params, 200, "Failed");
        // })            }
    // Handle predefined filter
   else  {
        // Handle predefined filter
        
        var tableName = "journeyobject_" + params.qstring.app_id;
        const dtfilterValues = ['lastmonth', 'thismonth', 'last7days','last30days','yesterday'];
        if( params.qstring.args.def == true){
            var JourneyParameterizedquery = {
                text: `select journey from `+tableName+` where pfilter = ? AND dtfilter IN (?,?,?,?,?)`,
                values: [params.qstring.args.platform, dtfilterValues[0],dtfilterValues[1],dtfilterValues[2],dtfilterValues[3],dtfilterValues[4] ],
              };
      
        }else{
        var JourneyParameterizedquery = {
          text: 'select journey from ' + tableName + ' where pfilter = ? and dtfilter = ?',
          values: [params.qstring.args.platform, params.qstring.args.journeyRange]
        };
       }

      pgsql.executeParameterizedQuery(JourneyParameterizedquery)
      .then((result) => {
        logger.info(`Journey Query result => ${JSON.stringify(result)}`);
        if (params.qstring.args.def == true) {
          let links = [];
          let nodes = [];
          result.forEach((journey) => {
            if (journey.journey.links) {
              for (const element of journey.journey.links) {
                const nameExists = links.some( (obj) => obj.name === element.name);
                if (!nameExists) {
                  links.push(element);
                }
              }
            }
            if (journey.journey.nodes) {
              for (const element of journey.journey.nodes) {
                const nameExists = nodes.some( (obj) => obj.name === element.name );
                if (!nameExists) {
                  nodes.push(element);
                }
              }
            }
          });

          let retObj = {
            links: links,
            nodes: nodes,
          };

          common.returnMessage(params, 200, retObj);
        } else {
          var final = result[0];
          common.returnMessage(params, 200, final.journey);
        }
      })
      .catch((error) => {
        logger.error(`Journeyquery error => ${error}`);
        common.returnMessage(params, 200, "Failed");
      });
    }
  };

        journey.getjourneyData_old = function (params) {
            //Get Data from arguments 
            var argProps = {
                    'startDateNew': {
                        'required': true,
                        'type': 'String'
                    },
                    'endDateNew': {
                        'required': true,
                        'type': 'String'
                    },
                    // 'eventList': {
                    //     'required': true,
                    //     'type': 'Array'
                    // }
                },
                eventParams = {};
             
            // Don't have args
            if (!(eventParams = common.validateArgs(params.qstring.args, argProps))) {
                common.returnMessage(params, 400, 'Not enough args');
                return false;
            }
            logger.info(`platform => ${params.qstring.args.platform}`);
            var Platformvalue = -1
            if(params.qstring.args.platform=="all"){
                Platformvalue = -1
            }
            else if(params.qstring.args.platform=="android"){
                Platformvalue  = 0
            }
            else if(params.qstring.args.platform=="ios"){
                Platformvalue = 1
            }
            else if(params.qstring.args.platform=="web"){
                Platformvalue = 2
            }
            
            //Run query for Default Statements
            if(Platformvalue == -1){
                var Journeyquery = "select * FROM journey11_" + params.qstring.app_id + " where dt between '" + eventParams.startDateNew + "' AND '" + eventParams.endDateNew + "' LIMIT 20000";
            }
            else {
                var Journeyquery = "select * FROM journey11_" + params.qstring.app_id + " where platform = "+ Platformvalue +" and dt between '" + eventParams.startDateNew + "' AND '" + eventParams.endDateNew + "' LIMIT 20000";
            }
            var AppEventsquery = "select distinct id,name from app_events_" + params.qstring.app_id + " where name NOT IN('App_Background','App_Foreground','Session_End','Session_Start','Campaign_Received','Campaign_Deleted','Campaign_Clicked','nan','Campaign_Viewed','_app_crash')";
            var appEventsDataSets;
            var resultlinks;
            logger.info(`Journeyquery dd => ${Jneouryquery}`);
            pgsql.executeQuery(Journeyquery)
                .then((result) => {
                     
                    resultlinks = result[0];
                    pgsql.executeQuery(AppEventsquery)
                        .then((resultDataSets) => {
                            logger.info(`responseData then`);
                            appEventsDataSets = resultDataSets[0];
                            var responseData = {
                                links: resultlinks,
                                nodes: appEventsDataSets
                            };
                            
                            var resData = processJourneyData(responseData);
                            //send all the data in the form of links and Nodes to Client
                            var resultData = {
                                links: resData,
                                nodes: appEventsDataSets
                            };
                            params.res.writeHead(200, {
                                'Content-Type': 'application/json; charset=utf-8'
                            });
                            params.res.write(JSON.stringify(resultData));
                            params.res.end();
                        })
                        .catch((error) => {
                            logger.error(`error => ${error}`);
                            common.returnMessage(params, 200, "Failed");
                        })
                })
                .catch((error) => {
                    logger.error(`error => ${error}`);
                    common.returnMessage(params, 200, "Failed");
                })

            //send Response to Client

        };

        function processJourneyData(responseData) {
            var initialData = responseData.links; //links from the journey table
            var nodes = responseData.nodes; //Name of nodes from app_events table
            var preprocessedData = [] //Data after preprocessing
            var allevents = [] //all events of all the steps
            var max_step = 0 // Max Steps in the incoming data
            //Preprocessing
            var uniqueDate = new Set() //Set is used to remove duplicate date of same event in final data              
            for (var i = 0; i < initialData.length; i++) {
                let item = initialData[i]; //for every entry of journey
                item_name = item.appfunnel.split(','); //spliting appfunnel
                item_value = item.appfunnelcount.split(','); //spliting appfunnelcount
                let step = 0 //count steps of journey
                //for every event of single journey
                for (var j = 0; j < item_name.length; j++) {
                    var eventObject = {} //event Object
                    var eventSliceOnlyParent = item_name.slice(0, j) //Event slice excluding the current event
                    var eventSliceOnlyParentString = eventSliceOnlyParent.join(',') //Event slice excluding the current event String 
                    var eventSlice = item_name.slice(0, j + 1) //Event slice including the current event
                    var eventSliceString = eventSlice.join(',') //Event slice including the current event String
                    node_name = '' //name of node
                    //map node name to id from the data
                    for (var n = 0; n < 6; n++) {
                        if (item_name[j] == nodes[n].id) {
                            node_name = nodes[n].name
                        }
                    }
                    let check_flag = 0; // check flag for unique entry, if new entry,push to allevents else update count
                    var eventLength = 5;
                    if(allevents.length < 6){ eventLength = allevents.length; }
                    for (var k = 0; k < eventLength; k++) {
                        //if first event name is same , parent is same, date is not same, update sum of firsteventcount
                        if (j == 0 && allevents[k].name == node_name && allevents[k].parent == -1) {
                            let uniqueDateString = allevents[k].name + allevents[k].parent + item.dt + item.platform
                            if (!uniqueDate.has(uniqueDateString)) {
                                uniqueDate.add(uniqueDateString)
                                allevents[k].value = allevents[k].value + parseInt(item_value[j])
                                allevents[k].firsteventcount = allevents[k].firsteventcount + parseInt(item.firsteventcount)
                            }
                            check_flag = 1
                            break
                        }
                        //all events except first event of journey having same parent and different date, update count
                        else if (allevents[k].match_name == eventSliceString && allevents[k].parent == eventSliceOnlyParentString) {
                            let uniqueDateString = allevents[k].name + allevents[k].parent + item.dt + item.platform
                            if (!uniqueDate.has(uniqueDateString)) {
                                uniqueDate.add(uniqueDateString)
                                allevents[k].value = allevents[k].value + parseInt(item_value[j])
                            }
                            check_flag = 1
                            break
                        }

                    }
                    if (check_flag == 0) {
                        let initialDateString = ''
                        if (j == 0) {
                            eventObject = {
                                name: node_name,
                                date: item.dt,
                                firsteventcount: item.firsteventcount,
                                match_name: item_name[j],
                                value: parseInt(item_value[j]),
                                parent: -1,
                                step: step,
                                children: []
                            }
                            initialDateString = node_name + "-1" + item.dt
                        } else {
                            eventObject = {
                                name: node_name,
                                date: item.dt,
                                match_name: eventSliceString,
                                value: parseInt(item_value[j]),
                                parent: eventSliceOnlyParentString,
                                step: step,
                                children: []
                            }
                            initialDateString = node_name + eventSliceOnlyParentString + item.dt
                        }
                        //if value of event is less than 10, ignore the event
                        if (parseInt(item_value[j]) > 10) {
                            uniqueDate.add(initialDateString)
                            allevents.push(eventObject);
                        }
                    }


                    step = step + 1
                }
                //checking for max steps in all journeys
                if (step > max_step) {
                    max_step = step - 1
                }
            }
            //If max step is greater than 7 then we will show 7 (Discussed)
            if(max_step>7){
              max_step = 7;
            }

            var uniqueParent = new Set() //Set is used to remove duplicate parent in final data
            //Bottom up approach to fill children in parent
            for (var i = max_step - 1; i > -1; i--) {
                let current_step = [] // all events of current step
                //pushing all events of current step
                for (var j = 0; j < allevents.length; j++) {
                    if (allevents[j].step == i) {
                        current_step.push(allevents[j])
                    }
                }

                for (var k = 0; k < current_step.length; k++) {
                    var uniqueChildren = new Set() //Set is used to remove duplicate children of same parent
                    for (var l = 0; l < allevents.length; l++) {
                        //if parent same and step of child is one more than parent, then add child
                        if (allevents[l].parent == current_step[k].match_name && allevents[l].step == i + 1) {
                            //if child already exist, dont push to same parent
                            if (!uniqueChildren.has(allevents[l].name)) {
                                uniqueChildren.add(allevents[l].name)
                                current_step[k].children.push(allevents[l])
                            }
                        }
                    }
                    //if parent already exist, dont push to preprocessedData
                    if (i == 0) {
                        if (!uniqueParent.has(current_step[k].name)) {
                            uniqueParent.add(current_step[k].name)
                            preprocessedData.push(current_step[k])
                        }
                    }
                }
            }
            var finalData = [] //final data to display in chart
            //taking top 10 relevant journeys
            preprocessedData.sort((a, b) => (a.firsteventcount > b.firsteventcount) ? 1 : ((b.firsteventcount > a.firsteventcount) ? -1 : 0));
            for (var i = preprocessedData.length - 1; i > preprocessedData.length - 11; i--) {
                finalData.push(preprocessedData[i])
            }
            return finalData;
        }

        function getUnique(arr, comp) {
            return arr
                .map(e => e[comp])
                .map((e, i, final) => final.indexOf(e) === i && i)
                .filter(e => arr[e])
                .map(e => arr[e]);
        }

    }(journey))
module.exports = journey;