class AggregateSlotsData

  def self.sites_aggregate_data(org_id, interval, permitted_network_ids = nil)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)
    match_condition = { "org_id" => org_id }
    match_condition["ln"] = { "$in" => permitted_network_ids } if permitted_network_ids.present?

    model.collection.aggregate([
                                 {
                                   "$match" => match_condition
                                 },
                                 {
                                   "$group" => {
                                     "_id" => nil,
                                     "online" => { "$sum" => { "$cond" => [{ "$eq" => ["$status", "online"] }, 1, 0] } },
                                     "down" => { "$sum" => { "$cond" => [{ "$eq" => ["$status", "down"] }, 1, 0] } },
                                     "imp" => { "$sum" => { "$cond" => [{ "$eq" => ["$status", "impaired"] }, 1, 0] } },
                                     "dor" => { "$sum" => { "$cond" => [{ "$eq" => ["$status", "dormant"] }, 1, 0] } },
                                     "networks_affected" => { "$sum" => "$networks_affected" },
                                     "managed_clients_count" => { "$sum" => "$managed_clients_count" },
                                     "lan_count" => { "$sum" => "$lan_count" },
                                     "wireless_count" => { "$sum" => "$wireless_count" },
                                     "down_clients" => { "$sum" => "$down_clients" }
                                   }
                                 }
                               ])
  end

  def self.isp_outages_count(org_id, interval, permitted_network_ids = nil)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)
    match_condition = {
      "org_id" => org_id,
      "networks_affected" => { "$gt" => 0 },
      "isp" => { "$ne" => nil }
    }
    match_condition["ln"] = { "$in" => permitted_network_ids } if permitted_network_ids.present?
      
    result = model.collection.aggregate([
      { "$match" => match_condition },
      {
        "$group" => {
          "_id" => "$isp" # Group by ISP to get unique ISPs
        }
      },
      {
        "$group" => {
          "_id" => nil, 
          "unique_isp_count" => { "$sum" => 1 } # Count the unique ISPs
        }
      },
      {
        "$project" => {
          "unique_isp_count" => 1, # Return only the unique_isp_count field
          "_id" => 0 # Exclude _id from the result
        }
      }
    ])
  
    # If no result found, return 0
    result = result.to_a
    result.empty? ? 0 : result.first["unique_isp_count"]
  end

  
  def self.hardware_aggregate_data(org_id, interval, permitted_network_ids = nil)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)
    match_condition = { "org_id" => org_id }
    match_condition["ln"] = { "$in" => permitted_network_ids } if permitted_network_ids.present?

    results = model.collection.aggregate([
                                            {
                                              "$match" => match_condition
                                            },
                                           {
                                             "$group" => {
                                               "_id" => nil,
                                               "router_total_count" => { "$sum" => "$device_details.router.total" },
                                               "router_down_count" => { "$sum" => "$device_details.router.down" },
                                               "router_up_count" => { "$sum" => "$device_details.router.up" },
                                               "wired_total_count" => { "$sum" => "$uplink_total_count.wired" },
                                               "cellular_total_count" => { "$sum" => "$uplink_total_count.cellular" },
                                               "switch_total_count" => { "$sum" => "$device_details.switch.total" },
                                               "switch_down_count" => { "$sum" => "$device_details.switch.down" },
                                               "switch_up_count" => { "$sum" => "$device_details.switch.up" },
                                               "access_point_total_count" => { "$sum" => "$device_details.access_point.total" },
                                               "access_point_down_count" => { "$sum" => "$device_details.access_point.down" },
                                               "access_point_up_count" => { "$sum" => "$device_details.access_point.up" },
                                               "wan_cell_count" => { "$sum" => "$wan_cell_count" },
                                               "lan_unused" => { "$sum" => "$lan_unused" },
                                               "switch_models" => { "$push" => "$switch_model" },
                                               "ap_models" => { "$push" => "$ap_model" }
                                             }
                                           }
                                         ]).first

    return {} unless results                                    

    # Aggregate switch model details
    switch_model_totals = Hash.new { |hash, key| hash[key] = { "total" => 0, "down" => 0 } }

    if results["switch_models"]
      results["switch_models"].each do |model_data|
        model_data.each do |switch, data|
          switch_model_totals[switch]["total"] += data["up"].to_i + data["down"].to_i
          switch_model_totals[switch]["down"] += data["down"].to_i
        end
      end
    end
    
    switch_model_totals = switch_model_totals.map do |switch, counts|
      { switch => counts }
    end

    # Aggregate access point model details
    ap_model_totals = Hash.new { |hash, key| hash[key] = { "total" => 0, "down" => 0 } }

    if results && results["ap_models"]
      results["ap_models"].each do |model_data|
        model_data.each do |ap, data|
          ap_model_totals[ap]["total"] += data["up"].to_i + data["down"].to_i
          ap_model_totals[ap]["down"] += data["down"].to_i
        end
      end
    end

    ap_model_totals = ap_model_totals.map do |ap, counts|
      { ap => counts }
    end

    avg_clients_count = ((results.to_h["wired_total_count"] || 0).to_i + (results.to_h["cellular_total_count"] || 0).to_i) / 2.0

    {
      router_total_count: results["router_total_count"],
      router_down_count: results["router_down_count"],
      router_up_count: results["router_up_count"],
      wired_total_count: results["wired_total_count"],
      cellular_total_count: results["cellular_total_count"],
      switch_total_count: results["switch_total_count"],
      switch_down_count: results["switch_down_count"],
      switch_up_count: results["switch_up_count"],
      access_point_total_count: results["access_point_total_count"],
      access_point_down_count: results["access_point_down_count"],
      access_point_up_count: results["access_point_up_count"],
      switch_model_totals: switch_model_totals,
      ap_model_totals: ap_model_totals,
      avg_clients_count: avg_clients_count,
      wan_cell_count: results["wan_cell_count"]
    }
  end

  def self.combined_lns_slot_data(ln_ids, interval, limit=10, skip=0)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)

    data = model.collection.aggregate([
      {
        "$match" => {
          "ln" => { "$in" => ln_ids }
        }
      },
      {
        "$group" => {
          "_id" => "$ln",
          "c_count" => { "$sum" => "$clients.count" },
          "c_wired" => { "$sum" => "$clients.wired" },
          "c_wireless" => { "$sum" => "$clients.wireless" },
          "grouped_uplinks" => { "$first" => "$grouped_uplinks" }, # Push grouped_uplinks for post-processing
          "isp" => { "$first" => "$isp" },
          "network_name" => { "$first" => "$network_name" },
          "template_name" => { "$first" => "$template_name" },
          "switch_up" => { "$sum" => "$device_details.switch.up" },
          "switch_down" => { "$sum" => "$device_details.switch.down" },
          "switch_dor" => { "$sum" => "$device_details.switch.dor" },
          "access_point_up" => { "$sum" => "$device_details.access_point.up" },
          "access_point_down" => { "$sum" => "$device_details.access_point.down" },
          "access_point_dor" => { "$sum" => "$device_details.access_point.dor" },
          "router_up" => { "$sum" => "$device_details.router.up" },
          "router_down" => { "$sum" => "$device_details.router.down" },
          "router_dor" => { "$sum" => "$device_details.router.dor" },
          "overall_health_last24hr" => { "$first" => "$overall_health_last24hr" },
          "primary_uplink_status" => { "$first" => "$primary_uplink_status" }
        }
      },
      {
        "$project" => {
          "ln_id" => "$_id",
          "_id" => 0,
          "c_count" => 1,
          "c_wired" => 1,
          "c_wireless" => 1,
          "grouped_uplinks" => 1,
          "isp" => 1,
          "switch_up" => 1,
          "switch_down" => 1,
          "switch_dor" => 1,
          "access_point_up" => 1,
          "access_point_down" => 1,
          "access_point_dor" => 1,
          "router_up" => 1,
          "router_down" => 1,
          "router_dor" => 1
        }
      },
      {"$skip" => skip},
      {"$limit" => limit}
    ])
    data
  end

  def self.fetch_health_data(org_id, interval,  ln_ids = nil, permitted_network_ids = nil)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)
  
    match_condition = { "org_id" => org_id }
    if ln_ids.present?
      match_condition["ln"] = { "$in" => ln_ids }
    elsif permitted_network_ids.present?
      match_condition["ln"] = { "$in" => permitted_network_ids }
    end
    match_condition['status'] = { "$ne" => "dormant" }
  
    if ln_ids.present?
      pipeline = [
        { "$match" => match_condition },
        {
          "$project" => {
            "_id" => 0,
            "ln" => 1,
            "last_24_health" => 1,
            "networks_affected" => 1
          }
        },
        { "$unwind" => "$last_24_health" },  
        {
          "$project" => {
            "st" => "$last_24_health.time",  
            "health" => "$last_24_health.health"  
          }
        },
        { "$sort" => { "st" => 1 } }  # Sort by Unix timestamp in ascending order
      ]

      result = model.collection.aggregate(pipeline).map do |record|
        {
          st: record['st'], 
          health: record['health'].to_f.round(1)  
        }
      end

    else
      pipeline = [
            { "$match" => match_condition },
            { "$unwind" => "$last_24_health" },  # Unwind the health array
            {
              "$group" => {
                "_id" => "$_id",  # Group by document ID to maintain distinct entries per document
                "health_entries" => { "$push" => "$last_24_health.health" },  # Collect health values
                "timestamps" => { "$push" => "$last_24_health.time" }  # Collect corresponding timestamps
              }
            },
            {
              "$unwind" => {
                "path" => "$health_entries",
                "includeArrayIndex" => "index"  # Add an index to the array elements
              }
            },
            {
              "$group" => {
                "_id" => { "index" => "$index" },  # Group by the array index
                "avg_health" => { "$avg" => "$health_entries" }  # Compute average health values
              }
            },
            { "$sort" => { "_id.index" => 1 } }  # Sort by index
          ]

      result = model.collection.aggregate(pipeline).map do |record|
        {
          idx: record['_id']['index'],  
          avg: record['avg_health'].to_f.round(1)  #
        }
      end    

    end
    result
  end
  

  def self.compute_overall_health(org_id, interval, permitted_network_ids = nil)
    DynamicModelGenerator.create_model(interval)
    class_name = "Ln#{interval.capitalize}Data"
    model = Object.const_get(class_name)

    match_condition = { "org_id" => org_id }
    match_condition["ln"] = { "$in" => permitted_network_ids } if permitted_network_ids.present?

  
    # Aggregation pipeline to work with last_24_health
    pipeline = [
      { "$match" => match_condition },
      {
        "$project" => {
          "_id" => 0,
          "ln" => 1,  # Include the ln (Location Network) field
          "last_24_health" => 1,
          "status" => 1  # Include status for filtering
        }
      },
      # Filter out dormant entries
      { "$match" => { "status" => { "$ne" => "dormant" } } },
      { "$unwind" => "$last_24_health" },  # Unwind the last_24_health array
      {
        "$group" => {
          "_id" => "$ln",  # Group by ln (Location Network ID)
          "health_values" => { "$push" => "$last_24_health.health" }  # Push health values into an array
        }
      }
    ]
  
    # Perform aggregation
    result = model.collection.aggregate(pipeline).map do |record|
      {
        ln_id: record["_id"],  # Location Network ID
        health_values: record["health_values"]  # List of health values
      }
    end
  
    # Count networks where all health values are below 80
    reduced_qoe_count = result.count do |data|
      data[:health_values].all? { |h| h < 60 }  # Check if all health values are below 60
    end
  
    reduced_qoe_count
  end
  
  
end

