class Monitoring
  include Mongoid::Document
  include RedisWrapper
  extend RedisWrapper
  field :nas_id, type: String
  has_many :monitoring_children
  index({"nas_id" => 1}, { background: true })

  def self.monitoring_id(nas_id)
    Monitoring.where(nas_id: nas_id).last
  end

  def self.monitoring(data)
    data = JSON.parse(data); m_id=""
    m_id = self.monitoring_id(data["INFO"]["NASID"].try(:upcase))
    m_id = Monitoring.create({nas_id: data["INFO"]["NASID"].try(:upcase)}) if m_id.blank?
    commands = data["COMMAND_RESULTS"]
    unless commands.blank?
      commands.each do |k|
        cmd = Command.find_by_id(k["CMD_ID"])
        cmd.update({:status=>"success", :result=>k["CMD_OUTPUT"]}) unless cmd.blank?
        ri = RouterInventory.find_by_mac_id(data["INFO"]["NASID"].try(:upcase))
        ri.update_redis(false) unless ri.blank?
      end
    end
    data["present_date"] = Time.now.to_i
    data["INFO"]["NASID"] = data["INFO"]["NASID"].try(:upcase)
    m_id.monitoring_children.create({monitoring_data: data, created_at: Time.zone.now.utc})
    # m_id.monitoring_children.create({monitoring_data: data.to_json})
  end

  def self.monitoring_data_update(message_data)
    p "Message subscribe:", message_data
    unless message_data.blank?
      message_data = JSON.parse(message_data)
      message_data.each do |data_for, data|
        if data_for == 'commands'
          data.each do |k,v|
            p "Data inspect:",k,v,v.class

            v.each do |x|
              p "CMD:",x
              cmd = Command.find_by_id(x.to_i)
              cmd.update({:status=>"waiting for response"}) unless cmd.blank?
              redis_del "CMD_#{k}"
              ri = RouterInventory.find_by_mac_id(k)
              ri.update_redis(false) unless ri.blank?
            end
            #remove this command from redis of that inventory
          end
        elsif data_for == 'upgrade'
          unless data["mac_id"].blank?
            p "UPGRADE:#{data["mac_id"]}"
            ri = RouterInventory.find_by(mac_id: data["mac_id"])
            redis_del "UPGRADE_#{data["mac_id"]}"
            unless ri.blank?
              unless ri.waiting_upgrade.blank?
                ri.waiting_upgrade.update_column(:status ,"sent")
                redis_hset "AP:#{data['mac_id']}",'upgrade', ri.waiting_upgrade.id.to_s
              end
            end
          end
        elsif data_for == 'ALERT'
          #Event Logging Code Starts
          #NOTE: {'ALERT' => { "NASID": "${NASID}", "CID": "${CATEGORY_ID}", "AID": "${ALERT_ID}", “DATA”:{“UID”:"12”, “STATUS” :”1”}}}
          unless data["NASID"].blank?
            ri = RouterInventory.find_by(mac_id: data["NASID"].upcase)
            unless ri.blank?
              profile = $redis.hgetall "AP:#{ri.mac_id}"
              EventLogging.create(mac_id: data['NASID'],category_id: data['CID'],type_id: data['AID'],description: data['DESC'],extra_data: data['DATA'],location_network_id: ri.location_network_id,timestamp: Time.at(data['TS'].to_i), client_mac: (data['DATA']||{})['CLI_MAC'])  if profile['EVENT_LOG'] && profile['EVENT_LOG'] == '1'
              ln = ri.location_network
              type = nil
              type = 'login' if data["AID"].to_s == "38"
              type = 'logout' if data["AID"].to_s == "39"

              if !ln.blank? && data["CID"] == "3" && data['AID'] == "1" && !data["DATA"]["STATUS"].blank?
                condition = data["DATA"]["STATUS"] == "1" ? "up" : "down"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'network',:alert_rules => {:alert_on => 'Network uplink',:condition => condition})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              if !ln.blank? && data["CID"] == "2"
                condition = 'associated' if data["AID"] == "35"
                condition = 'disassociated' if data["AID"] == "36"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'client',:alert_rules => {:alert_on => 'Client',:condition => condition})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              if !ln.blank? && data["CID"] == "3" && data['AID'] == "2"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'network',:alert_rules => {:alert_on => 'Network uplink',:condition => "uplink_switch_over"})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              unless ln.blank? && type.blank?
                alerts = ln.alerts.includes(:alert_rules).where(:alert_rules => {:alert_on => "Captive portal", :condition => type})
                  alerts.each do |alert|
                    alert.notify?(data, Time.now.utc.to_i)
                  end
              end
            end
          end
        end
      end
    end
  end

  def self.save_commands_result(message_data)
    #p "Message subscribe:", JSON.parse(message_data)
    unless message_data.blank?
     # message_data = JSON.parse(message_data)
      message_data.each do |data_for, data|
        if data_for == 'commands'
          data.each do |k,v|
            p "Data inspect:",k,v,v.class

            v.each do |x|
              p "CMD:",x
              cmd = Command.find_by_id(x.to_i)
              cmd.update({:status=>"waiting for response"}) unless cmd.blank?
              # redis_del "CMD_#{k}"
              ri = RouterInventory.find_by_mac_id(k)
              ri.update_redis(false) unless ri.blank?
            end
            #remove this command from redis of that inventory
          end
        elsif data_for == 'upgrade'
          unless data["mac_id"].blank?
            p "UPGRADE:#{data["mac_id"]}"
            ri = RouterInventory.find_by(mac_id: data["mac_id"])
            # redis_del "UPGRADE_#{data["mac_id"]}"
            unless ri.blank?
              unless ri.waiting_upgrade.blank?
                ri.waiting_upgrade.update_column(:status ,"sent")
                redis_hset "AP:#{data['mac_id']}",'upgrade', ri.waiting_upgrade.id.to_s
              end
            end
          end
        elsif data_for == 'ALERT'
          #Event Logging Code Starts
          #NOTE: {'ALERT' => { "NASID": "${NASID}", "CID": "${CATEGORY_ID}", "AID": "${ALERT_ID}", “DATA”:{“UID”:"12”, “STATUS” :”1”}}}
          unless data["NASID"].blank?
            ri = RouterInventory.find_by(mac_id: data["NASID"].upcase)
            unless ri.blank?
            profile = $redis.hgetall "AP:#{ri.mac_id}"
            EventLogging.create(mac_id: data['NASID'],category_id: data['CID'],type_id: data['AID'],description: data['DESC'],extra_data: data['DATA'],location_network_id: ri.location_network_id,timestamp: Time.at(data['TS'].to_i), client_mac: data['DATA']['CLI_MAC'])  if profile['EVENT_LOG'] && profile['EVENT_LOG'] == '1'
              ln = ri.location_network
              type = nil
              type = 'login' if data["AID"].to_s == "38"
              type = 'logout' if data["AID"].to_s == "39"

              if !ln.blank? && data["CID"] == "3" && data['AID'] == "1" && !data["DATA"]["STATUS"].blank?
                condition = data["DATA"]["STATUS"] == "1" ? "up" : "down"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'network',:alert_rules => {:alert_on => 'Network uplink',:condition => condition})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              if !ln.blank? && data["CID"] == "2"
                condition = 'associated' if data["AID"] == "35"
                condition = 'disassociated' if data["AID"] == "36"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'client',:alert_rules => {:alert_on => 'Client',:condition => condition})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              if !ln.blank? && data["CID"] == "3" && data['AID'] == "2"
                alerts = ln.alerts.includes(:alert_rules).where(:category => 'network',:alert_rules => {:alert_on => 'Network uplink',:condition => "uplink_switch_over"})
                alerts.each do |alert|
                  alert.notify?(data, Time.now.utc.to_i)
                end
              end
              unless ln.blank? && type.blank?
                alerts = ln.alerts.includes(:alert_rules).where(:alert_rules => {:alert_on => "Captive portal", :condition => type})
                  alerts.each do |alert|
                    alert.notify?(data, Time.now.utc.to_i)
                  end
              end
            end
          end
        end
      end
    end
  end

  def self.get_status(mac_id)
    result = {}
    record = self.where(nas_id: mac_id).last.monitoring_children.last rescue ""
    unless record.blank?
      record = record.monitoring_data
      result = if record["SYSTEM_INFO"].present?
        {"INFO"=>{"PIAP_VERSION"=>record["INFO"]["PIAP_VERSION"]},
       "SYSTEM_INFO"=>{"KERNEL_VERSION"=>record["SYSTEM_INFO"]["KERNEL_VERSION"],"PUBLIC_IP"=>record["SYSTEM_INFO"]["PUBLIC_IP"],"UPTIME"=>record["SYSTEM_INFO"]["UPTIME"],"UPTIME_REAL"=>record["SYSTEM_INFO"]["UPTIME_REAL"],"CPUIDLE_TIME"=>record["SYSTEM_INFO"]["CPUIDLE_TIME"],"LOAD_AVG"=>record["SYSTEM_INFO"]["LOAD_AVG"]},
       "MEMINFO"=>{"TOTAL"=>record["MEMINFO"]["TOTAL"],"FREE"=>record["MEMINFO"]["FREE"]}}
     else 
       {"INFO"=>{"PIAP_VERSION"=>record["INFO"]["PIAP_VERSION"]}}
     end
    end
    return result
  end

  def self.get_client(nas_id,mac_id)
    result = {}
    x = MonitoringChild.collection.aggregate({"$match" => {"monitoring_data.INFO.NASID" => nas_id, "monitoring_data.WLAN_CLIENTS.MAC" => mac_id}}, {"$sort" => {"monitoring_data.present_date" => -1}}, {"$limit" => 1}, {"$unwind" => "$monitoring_data.WLAN_CLIENTS"}, {"$match" => {"monitoring_data.WLAN_CLIENTS.MAC" => mac_id}}).first

    #MonitoringChild.collection.aggregate({"$match" => {"monitoring_data.INFO.NASID" => nas_id}}, {"$unwind" => "$monitoring_data.WLAN_CLIENTS"}, {"$match" => {"monitoring_data.WLAN_CLIENTS.MAC" => mac_id}}, {"$sort" => {"monitoring_data.present_date" => -1}}, {"$limit" => 1}).first
    unless x.blank?
      x = x["monitoring_data"]
      result = 
        if x["WLAN_CLIENTS"].present?
          {"SSID" => x["WLAN_CLIENTS"]["SSID"], "SIGNAL" => x["WLAN_CLIENTS"]["SIGNAL"], "MACID" => x["WLAN_CLIENTS"]["MAC"], "IPADDR" => x["WLAN_CLIENTS"]["IPADDR"], "HOSTNAME" => x["WLAN_CLIENTS"]["HOSTNAME"], "DEVICE" => x["WLAN_CLIENTS"]["DEVICE"], "AUTHORIZED" => x["WLAN_CLIENTS"]["AUTHORIZED"], "AUTHENTICATED" => x["WLAN_CLIENTS"]["AUTHENTICATED"], "status" => ((Time.zone.now.to_i - x["present_date"].to_i) <= 60)}
        else
          {}
        end
    end

    result
  end

  def self.get_clients_upload_download(ris)
    result = {}
    (ris || []).each do |x|
      record = MonitoringChild.where('info.NASID' => x).order_by([["created_at", "desc"]]).limit(1).to_a.last
      next if record.blank?
      result[x] = record.clients if((Time.zone.now - record.created_at) <= APPLICATION['defaults']['on_or_off'])
    end
    return result
  end

  def self.get_last_details(mac_id)
    result = {}
    record = MonitoringDataCapped.where("info.NASID" => mac_id, "created_at" => {"$lte" => Time.zone.now.utc}).desc("created_at").first rescue ""
    radio_rd = []
    ris = RouterInventory.find_by(mac_id:mac_id)
    if ris.get_bands.present?
      radio_channels_2 = ris.get_bands.radio_settings.where(band: "2.4").first
      if !radio_channels_2.is_disable
        radio_rd << ({BD: '1',CH_U: "-",TXP: "#{radio_channels_2.power == 0 ? "Auto": "#{radio_channels_2.power}"}",CH: "#{radio_channels_2.channel == 0 ? "Auto": "#{radio_channels_2.channel}"}",CH_UA: "-"})
      end
    else
      ris = RouterInventory.default_radio
      radio_rd << ({BD: ris["RADIO_SETTINGS"][0]["BAND"], 
                    CH_U: "-",TXP:  ris["RADIO_SETTINGS"][0]["TXPOWER"] == "0" ? "Auto": ris["RADIO_SETTINGS"][0]["TXPOWER"],
                    CH: ris["RADIO_SETTINGS"][0]["CHANNEL"] == "0" ? "Auto": ris["RADIO_SETTINGS"][0]["CHANNEL"],
                    CH_UA: "-"})
    end  
    ris = RouterInventory.find_by(mac_id:mac_id)
    if ris.get_bands.present?
      radio_channels_5 = ris.get_bands.radio_settings.where(band: "5").first
      if !radio_channels_5.is_disable
        radio_rd << {BD: '2',CH_U: "-",TXP: "#{radio_channels_5.power == 0 ? "Auto": "#{radio_channels_5.power}"}",CH: "#{radio_channels_5.channel == 0 ? "Auto": "#{radio_channels_5.channel}"}",CH_UA: "-"}
      end
    else 
      ris = RouterInventory.default_radio
      radio_rd << ({BD: ris["RADIO_SETTINGS"][1]["BAND"], 
                    CH_U: "-",TXP:  ris["RADIO_SETTINGS"][1]["TXPOWER"] == "0" ? "Auto": ris["RADIO_SETTINGS"][1]["TXPOWER"],
                    CH: ris["RADIO_SETTINGS"][1]["CHANNEL"] == "0" ? "Auto": ris["RADIO_SETTINGS"][1]["CHANNEL"],
                    CH_UA: "-"})
    end 


    unless record.blank?

      result = if record.s_info.present?
        {"INFO"=>{"PIAP_VERSION" => record.info["PIAP_VERSION"], "BN" => record.info["BN"] || $redis.hget("AP:#{mac_id}", "BN")},
                "SYSTEM_INFO"=>{"KERNEL_VERSION" => record.s_info["KERNEL_VERSION"],"PUBLIC_IP" => record.s_info["PUBLIC_IP"],
                                "UPTIME_REAL" => record.s_info["UPTIME_REAL"],
                                "CPU_IDLE_TIME"=>record.s_info["CPU_IDLE_TIME"],"LOAD_AVG"=>record.s_info["LOAD_AVG"],
                                "HW_PART_NO" => record.s_info["HW_PART_NO"]},
                "MEMINFO"=>{"TOTAL"=>record.m_info["TOTAL"],"CACHED"=>record.m_info["CACHED"],"BUFFERS"=>record.m_info["BUFFERS"],"FREE"=>record.m_info["FREE"]},
                "RD"=> radio_rd
              }
            else
              {"INFO"=>{"PIAP_VERSION" => record.info["PIAP_VERSION"], "BN" => $redis.hget("AP:#{mac_id}", "BN")},"RD" => radio_rd}
            end
    else
     result = {"RD" => radio_rd}    
     ri_details = $redis.hgetall("AP:#{mac_id}") || {}
     result = {"INFO"=>{"PIAP_VERSION" => ri_details['version'], "BN" => ri_details["BN"]},"RD" => radio_rd}
    end            
    return result
  end

  # def self.get_client_last_details(nas_id, mac_id)
  #   result = {}
  #   hb = MonitoringDataCapped.collection.aggregate({"$match" => {"info.NASID" => nas_id, "clients.MAC" => mac_id}}, {"$sort" => {"created_at" => -1}}, {"$limit" => 1}, {"$unwind" => "$clients"}, {"$match" => {"clients.MAC" => mac_id}}).first

  #   unless hb.blank?
  #     x = hb["clients"]
  #      result = {"SSID" => x["SSID"], "SIGNAL" => x["SIGNAL"], "MAC" => x["MAC"], "IPADDR" => x["IPADDR"], "HOSTNAME" => x["HOSTNAME"], "DEVICE" => x["DEVICE"], "AUTHORIZED" => x["AUTHORIZED"], "AUTHENTICATED" => x["AUTHENTICATED"], "status" => ((Time.zone.now.to_i - hb["created_at"].to_i) <= 60), "access_point" => nas_id, "BAND" => x['BAND'] || x['BD']}
  #   end
    
  #   result
  # end

  # def self.get_client_last_details(nas_id, mac_id, network_id)
  #   result = {}
  #   c = ClientAggregateData.find_recent mac_id, network_id
  #   nas_id = nas_id.present? ? nas_id : c.try(:ap)
  #   return result if nas_id.blank?
  #   hb = MonitoringDataCapped.collection.aggregate({"$match" => {"info.NASID" => nas_id, "clients.MAC" => mac_id}}, {"$sort" => {"created_at" => -1}}, {"$limit" => 1}, {"$unwind" => "$clients"}, {"$match" => {"clients.MAC" => mac_id}}).first

  #   if hb.present?
  #     x = hb["clients"]
  #      result = {"SSID" => x["SSID"], "SIGNAL" => x["SIGNAL"], "MAC" => x["MAC"], "IPADDR" => x["IPADDR"], "HOSTNAME" => x["HOSTNAME"], "DEVICE" => x["DEVICE"], "AUTHORIZED" => x["AUTHORIZED"], "AUTHENTICATED" => x["AUTHENTICATED"], "status" => ((Time.zone.now.to_i - hb["created_at"].to_i) <= 60), "access_point" => nas_id, "BAND" => x['BAND'] || x['BD']}
  #     val = ClientDevice.where(:mac => x["MAC"])
  #     if val.present?
  #       result["HOSTNAME"] = val.last.original_name.to_s 
  #       result["NICKNAME"] = val.last.nick_name.to_s
  #     else
  #     end
  #   else
  #     return result unless c.present?
  #     result = {"SSID" => c.ssid.last["n"], "MAC" => c.mac, "HOSTNAME" => c.hostname, "DEVICE" => c.device, "access_point" => c.ap, "BAND" => c.band, "IP" => c.ip, "lst" => c.l_time }
  #     val = ClientDevice.where(:mac => c.mac)
  #     if val.present?
  #       result["HOSTNAME"] = val.last.original_name.to_s
  #       result["NICKNAME"] = val.last.nick_name.to_s
  #     else
  #     end
  #   end

  #   result
  # end
  

  def self.get_client_last_details(nas_id, mac_id, network_id)
    result = {}
    ln = LocationNetwork.where(:id => network_id).first
    c = ClientAggregateData.find_recent mac_id, network_id
    nas_id = nas_id.present? ? nas_id : c.try(:ap)
    return result if nas_id.blank?
    hb = MonitoringDataCapped.collection.aggregate({"$match" => {"info.NASID" => nas_id, "created_at" => { "$gte" => Time.now - 60.minutes}, "clients.MAC" => mac_id}}, {"$sort" => {"created_at" => -1}}, {"$limit" => 1}, {"$unwind" => "$clients"}, {"$match" => {"clients.MAC" => mac_id}}).first
    #hb = MonitoringChild.collection.aggregate({"$match" => {"info.NASID" => nas_id, "clients.MAC" => mac_id}}, {"$sort" => {"created_at" => -1}}, {"$limit" => 1}, {"$unwind" => "$clients"}, {"$match" => {"clients.MAC" => mac_id}}).first unless hb.present?
    if hb.present?
      x = hb["clients"]
       result = {"SSID" => x["SSID"], "SIGNAL" => x["SIGNAL"], "MAC" => x["MAC"], "IPADDR" => x["IPADDR"], "HOSTNAME" => x["HOSTNAME"], "DEVICE" => x["DEVICE"], "AUTHORIZED" => x["AUTHORIZED"], "AUTHENTICATED" => x["AUTHENTICATED"], "status" => ((Time.zone.now.to_i - hb["created_at"].to_i) <= 60), "access_point" => nas_id, "BAND" => x['BAND'] || x['BD'],"lst" => hb["created_at"]}
      if ln.present?
        org_id = ln.organisation.id 
        val = ClientDevice.where(:mac => x["MAC"], :org_id => org_id)
        if val.present?
          result["HOSTNAME"] = val.last.original_name.to_s 
          result["NICKNAME"] = val.last.nick_name.to_s
          result["MONITORING"] = val.last.monitoring
          result["ALERT"] = val.last.critical.to_s
        else
        end
      end
    else
      return result unless c.present?
      result = {"SSID" => c.ssid.last["n"], "MAC" => c.mac, "HOSTNAME" => c.hostname, "DEVICE" => c.device, "access_point" => c.ap, "BAND" => c.band, "IPADDR" => c.ip, "lst" => c.l_time }
      if ln.present?
        org_id = ln.organisation.id       
        val = ClientDevice.where(:mac => c.mac, :org_id => org_id)
        if val.present?
          result["HOSTNAME"] = val.last.original_name.to_s
          result["NICKNAME"] = val.last.nick_name.to_s
          result["MONITORING"] = val.last.monitoring
          result["ALERT"] = val.last.critical.to_s
        else
        end
      end
    end
    result
  end

end
