class VisitorDetail
    
    include Mongoid::Document
    field :device_id, type: String
    field :visitor_data, type: Hash

    has_many :visitor_timings, :dependent => :destroy 
    has_and_belongs_to_many :router_locations
    has_many :user_stayed_times
    has_many :user_details

    def self.save_stayed_time(vd_id)
        VisitorTimeHopeWorker.perform_async(vd_id)
    end

    def self.uniqe_tot_return(rlids,start_date,end_date)
        vdids = self.get_vdids(rlids)
        return "" if vdids.blank?
        return UserStayedTime.uniqe_tot_return(vdids,start_date,end_date)
    end

    def self.storehouroptimization_v2(rlids,fm_date,to_date,offset)
      fm_date,to_date = self.time_zone_dates(fm_date,to_date,offset)
      return {"store_hour" => UserStayedTime.store_hour_v2(rlids,fm_date,to_date)}
    end

    def self.storehouroptimization(rlids,fm_date,to_date,offset)
        # vdids = self.get_vdids(rlids)
        fm_date,to_date = self.time_zone_dates(fm_date,to_date,offset)
        avg_ppl_in_store = UserStayedTime.avg_ppl_by_hr_in_store(rlids,fm_date,to_date,offset)
        avg_min_spent_in_store = UserStayedTime.avg_min_spent_in_store(rlids,fm_date,to_date,offset)
        return {"avg_min_spent_in_store" => avg_min_spent_in_store, "avg_ppl_in_store"=>avg_ppl_in_store}
    end

    def self.time_zone_dates(fm_date,to_date,offset)
        fm_date = Time.zone.parse(fm_date).utc - offset.to_i/1000
        to_date = Time.zone.parse(to_date).utc - offset.to_i/1000
        # fm_date = Time.zone.parse(fm_date).utc.beginning_of_day - offset.to_i/1000
        # to_date = Time.zone.parse(to_date).utc.end_of_day - offset.to_i/1000
        return fm_date,to_date
    end
    
    def self.ppl_bfr_afr_xmin_v2(rlids,start_date,end_date,offset)
        start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
        lists = UserStayedTime.ppl_bfr_afr_xmin_v2(rlids,start_date,end_date,offset)
        five_min = 0; fifteen_min =0;thirty_min=0;fortyfive_min=0;one_hour = 0;one_hourplus = 0;
        a=[]
        (lists || []).each do |x| 
            next if x["max_stm"].to_f == 0
            case x["max_stm"].to_f
                when 1..300; five_min += 1
                when 301..900; fifteen_min += 1
                when 901..1800; thirty_min += 1
                when 1801..2700; fortyfive_min += 1
                when 2701..3600; one_hour += 1
                else; 
                    one_hourplus += 1
                    a.push(x["_id"]["vd"])
            end
        end
        return {"ppl_bfr_afr_xmin" => {"1-5min"=>five_min,"6-15min"=>fifteen_min,"16-30min"=>thirty_min,"31-45min"=>fortyfive_min,"46-60min"=>one_hour,"1+hr"=>one_hourplus}}
    end

    def self.storefrontconversion_v2(rlids,start_date,end_date,offset)
      start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
      return {"store_front" => UserStayedTime.store_front_v2(rlids,start_date,end_date)}
    end

    def self.customer_recency_v2(rlids,start_date,end_date,offset)
      start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
      lists = UserStayedTime.customer_recency_v2(rlids,start_date,end_date,offset)
      return_vts = {}; return_mbs = {}; tot_vts = 0; tot_ret_vts = 0; unique_mbs_rtn=0
      (lists["return_vts"] || []).each do |x|
        week_year = x["_id"]["week"].to_s+","+x["_id"]["year"].to_s
        return_vts["week"+week_year] = 0 if return_vts["week"+week_year].blank?
        return_vts["week"+week_year] += x["rvv"].to_i
        tot_vts += (x["rvv"].to_i + x["nvv"].to_i)
        tot_ret_vts += x["rvv"].to_i
        return_mbs["week"+week_year] = 0
      end
      top_6,return_mbs = self.get_top_6_vtrs(lists["return_mbs"].first(6), return_mbs)
      unique_mbs_rtn = lists["return_mbs"].count unless lists["return_mbs"].blank?
      return {"top_6" => top_6,"crs_result" => return_vts, "store_result" => return_mbs, "visitors" => tot_vts, "returns" => tot_ret_vts, "members_returns" => unique_mbs_rtn}
    end

    def self.get_top_6_vtrs(top_visitors,return_mbs)
      top_6=[]
        (top_visitors || []).each do |x|
          week_year = x["_id"]["week"].to_s+","+x["_id"]["year"].to_s
          return_mbs["week"+week_year] += 1
          ud = UserDetail.where(:vd_mac_id=>x["_id"]["vd_mac_id"]).last
          next if ud.blank?
          name,image_path =  ud.social_network(ud)
          next if name.blank?
          top_6.push({"name"=>name, "count" => x["count"],"image"=>image_path})
      end
      return top_6,return_mbs
    end

    def self.customer_recency(rlids,start_date,end_date,offset)

        # this is for only return users
        crs_result={}; store_result= {}; i = 1; top_6 = [];status = false
        start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
        # end_date = (start_date.to_time + 6.day).utc
        

        first_week_cnt = UserStayedTime.customer_recency(rlids,start_date,end_date,offset) 
        first_week_members = UserStayedTime.members_customer_recency(rlids,start_date,end_date,offset)
        top_6_visits = UserStayedTime.top_6_visits(rlids,start_date,end_date,offset) 
        members = UserDetail.members(rlids,start_date,end_date,offset)

        start_date = (end_date.to_time + 1.second).utc

        return_cnt = UserStayedTime.customer_recency(rlids,start_date,Time.now.utc,offset)
        reurn_top_visits = UserStayedTime.top_6_visits(rlids,start_date,Time.now.utc,offset).first(6)
        return_members = UserDetail.members(rlids,start_date,Time.now.utc,offset)

        visitors = 0 ; returns = 0 ; members_returns = 0
        unless first_week_cnt.blank?
            visitors = first_week_cnt[0]["_id"]["visitors"].count
            returns =  (first_week_cnt[0]["_id"]["visitors"] & return_cnt[0]["_id"]["visitors"]).count rescue 0
            members_returns =  (members[0]["visitors"] & return_members[0]["visitors"]).count rescue 0
            crs = UserStayedTime.customer_recency_new(rlids,start_date,offset) 
            store_crs = UserStayedTime.members_customer_recency_new(rlids,start_date,offset)
            status = true

            unless first_week_cnt.blank?
                (crs || []).each do |x|
                    week_year = x["_id"]["week"].to_s+","+x["_id"]["year"].to_s
                    crs_result["week"+week_year] = (x["_id"]["visitors"] & first_week_cnt[0]["_id"]["visitors"]).count
                     store_result["week"+week_year] = 0
                end
            end
            unless first_week_members.blank?
                (store_crs || []).each do |x|
                    week_year = x["_id"]["week"].to_s+","+x["_id"]["year"].to_s
                    store_result["week"+week_year] = (x["_id"]["visitors"] & first_week_members[0]["_id"]["visitors"]).count
                end
            end

            top_visitors = []
            (top_6_visits || []).each {|x| top_visitors.push(x["_id"]["visitor_detail_id"])} 
            top_visitors = top_visitors.uniq
            unless top_visitors.blank?
                (reurn_top_visits || []).each do |x|
                    id = x["_id"]["visitor_detail_id"] 
                    if top_visitors.include?(id)
                        name,image_path = UserDetail.user_name(self.find(id))
                        next if name.blank?
                        top_6.push({"name"=>name, "count" => x["count"],"image"=>image_path})
                    end
                end
            end
        end
        return {"crs_result"=>crs_result,"top_6"=>top_6, "store_result"=>store_result,"visitors"=>visitors,"returns"=>returns, "members_returns"=>members_returns}
    end

    def self.avg_ppl_in_store(vdids,fm_date,to_date)
        ust = UserStayedTime.avg_ppl_by_hr_in_store(vdids,fm_date,to_date) 
        result_hash = {};
        timings = self.timings
        (ust || []).each do |x|
            _12_hr_format = Time.parse(x["_id"]["hour"].to_s+":00").strftime("%p %I:%M")
            timings[_12_hr_format] = x["count"]
        end

        result_hash.merge!(timings) {|key,val1,val2| val1+val2}
        return result_hash
    end

    def self.get_vdids(rlids)
        RouterLocation.includes(:visitor_details).where(:mac_id.in=>rlids).pluck(:visitor_detail_ids).flatten.uniq
    end

    def self.storefrontconversion(rlids = [],fm_date,to_date,offset)
        people = {}; total_traffic= {}; before_visited = {}; never_visited = {};
        # vdids = self.get_vdids(rlids)
        fm_date,to_date = self.time_zone_dates(fm_date,to_date,offset)
        total_traffic = UserStayedTime.total_traffic(rlids,fm_date,to_date,offset)
        before_visited = UserStayedTime.before_visited(rlids,fm_date,to_date,offset)
        never_visited = UserStayedTime.never_visited(rlids,fm_date,to_date,offset)

        presence_ppl = UserStayedTime.register_ppl(rlids,fm_date,to_date,offset)    
        # presence_ppl = UserDetail.get_mac_ids(rlids,fm_date,to_date,offset)

        people["total_ppl"] = self.count_ppl(presence_ppl[:total_visits])
        people["before_ppl"] = self.count_ppl(presence_ppl[:before_visited])
        people["never_ppl"] = self.count_ppl(presence_ppl[:never_visited])
        
        people["total_traffic"] = self.conversion_rates(total_traffic)
        people["before_visited"] = self.conversion_rates(before_visited)
        people["never_visited"] = self.conversion_rates(never_visited)
        return people
    end

    def self.count_ppl(people)
        ppl_ar=[0]
        (people || []).each {|x| ppl_ar.push(x["count"]) }
        return ppl_ar
    end

    def self.conversion_rates(people)
        out_store_hs={}; tot_ppl_ar=[]; in_store_ar=[]; tot_ppl_hs={}; in_store_hs={}; 
        tot_ppl_hs = self.convert_into_array(people["total_people"])
        in_store_hs = self.convert_into_array(people["in_store"])
        out_store_hs = tot_ppl_hs.merge(in_store_hs) {|key,val1,val2| val1 - val2}

        return {"out_store"=>[0].push(out_store_hs.values).flatten , "total_people"=>[0].push(tot_ppl_hs.values).flatten, "in_store"=>[0].push(in_store_hs.values).flatten}
    end

    def self.convert_into_array(people)
        hs = {}
        (people || []).each { |x| hs[x["_id"]] = x["count"] }
        return hs
    end

    def self.timings
        timings = {}
        (1..24).each { |x| timings[Time.parse(x.to_s+":00").strftime("%p %I:%M")] = 0 }
        return timings
    end

    def self.visitors_bar_chart(rlids,fm_date,to_date,offset)
        fm_date,to_date = self.time_zone_dates(fm_date,to_date,offset)
        fm_date = fm_date.beginning_of_day; to_date = to_date.end_of_day
        visitors = {};
        hs_limit = {"30"=>"5.year","15"=>"2.year","7"=>"8.month","5"=>"6.week","1"=>"3.week", "0"=>"7.day"}
        limit = self.return_limit(fm_date,to_date)
        (rlids || []).each do |x|
            result = self.hourly_aggrigate(x,fm_date,to_date,offset,"non_avg")
            fm_date = fm_date - eval(hs_limit[limit.to_s])
            avg_result = self.hourly_aggrigate(x,fm_date,to_date,offset,"avg")
            visitors[x] = result[0]
            visitors[x+"Min"] = result[1]
            visitors[x+"Max"] = result[2]
            visitors[x+"Avg"] = avg_result[0]
        end
        return {"result" => visitors, "avg" =>hs_limit[limit.to_s]}
    end

    def self.hourly_aggrigate(mac_id,fm_date,to_date,offset,avg)
        
        vt = UserStayedTime.avg_peple_by_hr(mac_id,fm_date,to_date,offset) 
        result_hash={}; min = {}; max = {}; timings={}
        (1..24).each do |x|
            t = Time.parse(x.to_s+":00").strftime("%p %I:%M ")
            timings[t] = 0;min[t] = 0;max[t] = 0
        end
        (vt || []).each do |x|
            _12_hr_format = Time.parse(x["_id"]["hour"].to_s+":00").strftime("%p %I:%M ")
            timings[_12_hr_format] = x["count"]
            if avg.eql?("non_avg")
                if min[_12_hr_format].blank?
                    min[_12_hr_format] = x["count"] 
                    max[_12_hr_format] = x["count"] 
                else
                    min[_12_hr_format] < x["count"] ? max[_12_hr_format] = x["count"] : min[_12_hr_format] = x["count"]
                end
            end
            result_hash.merge!(timings) {|key,val1,val2| val1+val2}
        end
        # hs={}; val=0; r=0
        # result_hash.each do |k,v|
        #     val += v;  r += 1
        #     if r==3
        #         hs[k]=val
        #         val = 0; r = 0
        #     end
        # end

        return result_hash, min, max
    end

    def self.visitors_unique_return(mac_ids,start_date,end_date,offset)
        start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
        start_date = start_date.beginning_of_day; end_date = end_date.end_of_day
        total = [];present=[];last=[]
        unless mac_ids.blank?
            match_cond = self.dates_range(mac_ids)
            total = self.return_ret_uniq_ses(match_cond)
            match_cond = self.dates_range(mac_ids,start_date,end_date)
            present = self.return_ret_uniq_ses(match_cond)
            diff_days = (end_date.to_date - start_date.to_date).to_i
            end_date = start_date - 1.day
            start_date = start_date - diff_days.day
            match_cond = self.dates_range(mac_ids,start_date,end_date)
            last = self.return_ret_uniq_ses(match_cond)
        end
        return {'present'=>present,'last'=>last,'total'=>total}
    end

    def self.dates_range(mac_ids,start_date="",end_date="")
        return {"rl_mac_id" => {"$in" => mac_ids},"starttime"=> { "$gte" => start_date.to_time.utc.beginning_of_day},"endtime" => {"$lte" => end_date.to_time.utc.end_of_day} }  unless(start_date.blank? && end_date.blank?)

        return {"rl_mac_id" => {"$in" => mac_ids} } if(start_date.blank? && end_date.blank?)
    end

    def self.return_user_stayed_times(match_cond)
        unique_cnt = 0; return_cnt = 0
        unless match_cond.blank?
            usts = UserStayedTime.collection.aggregate(
                {
                    "$match"=> match_cond
                }, 
                {
                    "$project"=>
                    {
                        "vd_mac_id"=>1,
                        "return_flag"=>1
                    }
                },
                {
                    "$group" => 
                    {
                        "_id"=>{}, 
                        "return_cnt"=>
                        {
                            "$addToSet"=>
                            {
                                "$cond"=> [{"$eq"=> ["$return_flag", 1]}, "$vd_mac_id", nil ]
                            }
                        },
                        "new_cnt"=>
                        {
                            "$addToSet"=>
                            {
                                "$cond"=> [{"$eq"=> ["$return_flag", 0]}, "$vd_mac_id", nil ]
                            }
                        }
                    }
                },
                {
                    "$project"=>
                    {
                        "r_cnt"=>{"$size"=>"$return_cnt"},
                        "n_cnt"=>{"$size"=>"$new_cnt"}
                    }
                }
            )
            unless usts.blank?
                return_cnt = (usts[0]["r_cnt"]  - 1)
                unique_cnt = (usts[0]["n_cnt"]  - 1)
            end
                
        end
        return {"session_cnt"=>(return_cnt + unique_cnt),"unique_cnt"=>unique_cnt, "return_cnt"=>return_cnt}
    end
    def self.return_ret_uniq_ses(match_cond)
        match_cond.merge!({"stayedtime"=>{"$lt"=>  APPLICATION['defaults']['footfall_passerby'] }})
        passerby = self.return_user_stayed_times(match_cond)
        match_cond.merge!({"stayedtime"=>{"$gte"=>  APPLICATION['defaults']['footfall_passerby'] }})
        footfall = self.return_user_stayed_times(match_cond)
        return {"passerby"=>passerby,"footfall"=>footfall}        
    end

    def self.avg_time_spend(mac_ids,start_date,end_date,offset)
        start_date,end_date = self.time_zone_dates(start_date,end_date,offset)
        start_date = start_date.beginning_of_day; end_date = end_date.end_of_day
        limit = self.return_limit_for_group(start_date,end_date)
        return self.sparklinecounts(start_date,end_date,limit,mac_ids)
    end

    def self.return_limit(start_date,end_date)
        a = (end_date - start_date).to_i / (24 * 60 * 60)
        case
          when a > 300;return 30
          when a > 150;return 15
          when a > 31;return 7
          when a > 15;return 5
          when a > 7 || a >= 1;return 1
          when a == 0;return 0
        end
    end

    def self.return_limit_for_group(start_date,end_date)
        a = (end_date - start_date).to_i / (24 * 60 * 60)
        case
          when a > 366;return "year"
          when a > 31;return "month"
          when a > 7;return "week"
          else; return "day"
        end
    end

    def self.router_location_ids(mac_id)
        RouterLocation.includes(:visitor_details).where(:mac_id.in=>mac_id).pluck(:visitor_detail_ids).flatten.uniq
        # RouterLocation.where(mac_id: mac_id.downcase).last.visitor_details.pluck(:id) rescue ""
    end

    def self.sparklinecounts(start_date,end_date,limit,mac_ids)
        s = {}
        case limit
        when "year";s = {"group"=>{"year"=>{"$year"=>"$starttime"}}} 
        when "month";s = {"group"=>{"year"=>{"$year"=>"$starttime"},"month"=>{"$month"=>"$starttime"}}}
        when "week";s = {"group"=>{"year"=>{"$year"=>"$starttime"},"week"=>{"$week"=>"$starttime"}}}
        when "day";s = {"group"=>{"year"=>{"$year"=>"$starttime"},"month"=>{"$month"=>"$starttime"},"day"=>{"$dayOfMonth"=>"$starttime"}}}
        end
        usts = [];
        unless mac_ids.blank?
            usts = UserStayedTime.collection.aggregate(
                {
                    "$match" => 
                    {
                        "rl_mac_id" => {"$in" => mac_ids},
                        "starttime"=> { "$gte" => start_date},
                        "endtime" => {"$lte" => end_date},
                        "stayedtime" => {"$gt"=>0} 
                    } 
                },
                {
                    "$project"=>
                    {
                        "vd_mac_id"=>1,
                        "stayedtime"=>1, 
                        "starttime"=>1
                    }
                },
                {
                    "$group" => 
                    {
                        "_id"=>{"vd"=>"$vd_mac_id"}.merge!(s),
                        "max_time" => {"$max"=>"$stayedtime"}
                    }
                },
                {
                    "$group" => 
                    {
                        "_id"=>{"group"=>"$_id.group"},
                        "0-5"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 0]},{"$lte"=> ["$max_time", 300]}]}, 1, 0 ]
                            }
                        }, 
                        "6-10"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 300]},{"$lte"=> ["$max_time", 600]}]}, 1, 0 ]
                            }
                        },
                        "11-15"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 600]},{"$lte"=> ["$max_time", 900]}]}, 1, 0 ]
                            }
                        },
                        "16-30"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 900]},{"$lte"=> ["$max_time", 1800]}]}, 1, 0 ]
                            }
                        },
                        "31-45"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 900]},{"$lte"=> ["$max_time", 1800]}]}, 1, 0 ]
                            }
                        },
                        "46-1hr"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$and"=>[{"$gt"=> ["$max_time", 1800]},{"$lte"=> ["$max_time", 3600]}]}, 1, 0 ]
                            }
                        },
                        "1hr+"=>
                        {
                            "$sum"=>
                            {
                                "$cond"=> [ {"$gt"=> ["$max_time", 3600]}, 1, 0 ]
                            }
                        }
                    }
                }
            )
        end
        return {"results"=>usts, "limit"=>limit }
    end
    def self.to_csv(options = {})
        column_names = ["device_id","protype"]
        CSV.generate(options) do |csv|
            csv << column_names
            all.each do |product|
                csv << product.attributes.values_at(*column_names)
            end
        end
    end
end
