class LiveAggregateDataQuery
  attr_accessor :query_for, :filter_params, :user
  DEVICE_TYPE_MAP = { 
    0 => "Unidentified",
    1 => "Windows (Desktop & Laptops)",
    2 => "Mac OS",
    3 => "VOIP Phone",
    4 => "Linux",
    5 => "Android",
    6 => "ChromeOS",
    7 => "ios (iPhone, iPad, iPod)",
    8 => "Blackberry",
    9 => "SymbianOS",
    10 => "Windows Mobile",
    11 => "Mobile"
  }

  #Initilize Query object with query params.
  # query - [<start-date>, <end-date>] OR Any one of ["1d", "3d", "1w", "1m", "3m", "6m"]
  def initialize query, filter_params, user
    #Set all query params
    @query_for = query
    @filter_params = filter_params
    @user = user
  end

  def search_clients
    begin
      start_time = Time.at(@filter_params['start_time']).utc
      end_time = Time.at(@filter_params['end_time']).utc
    rescue ArgumentError
      return {message: "Invalid time. Please check start & end timestamp."}
    end

    aggregate_pipeline = []
    match_criteria = {}

    #Match criteria
    if @filter_params['device_mac'].present?
      device_mac = @filter_params['device_mac'].is_a?(Array) ? @filter_params['device_mac'].map(&:upcase) : @filter_params['device_mac'].upcase
      ris = @user.router_inventories.where(mac_id: @filter_params['device_mac'].upcase).pluck :mac_id
      match_criteria['info.NASID'] = {"$in" => ris}
    else
      if @filter_params['location_network_id'].present?
        ln_macs = @user.router_inventories.where(location_network_id: @filter_params['location_network_id']).pluck(:mac_id)
        match_criteria['info.NASID'] = {"$in" => ln_macs}
      else
        match_criteria['info.NASID'] = {"$in" => @user.router_inventories.pluck(:mac_id)}
      end
    end
    
    match_criteria["created_at"] = {"$gte" => start_time, "$lte" => end_time}
    aggregate_pipeline << {"$match" => match_criteria}

    #project
    aggregate_pipeline << {"$project" => {"info.NASID" => 1, "clients" => 1, "created_at" => 1}}
    #unwind clients array
    aggregate_pipeline << {"$unwind" => "$clients"}

    #client criteria
    client_match_criteria = {}
    if @filter_params['client_mac'].present?
      if @filter_params['client_mac'].is_a?(String)
        client_match_criteria['clients.MAC'] = @filter_params['client_mac'].downcase
      elsif @filter_params['client_mac'].is_a?(Array)
        client_match_criteria['clients.MAC'] = {"$in" => @filter_params['client_mac'].map(&:downcase)}
      end
    end
    
    if @filter_params['ssid'].present?
      if @filter_params['ssid'].is_a?(String)
        client_match_criteria['clients.SSID'] = @filter_params['ssid']
      elsif @filter_params['ssid'].is_a?(Array)
        client_match_criteria['clients.SSID'] = {"$in" => @filter_params['ssid']}
      end
    end

    if @filter_params['client_ip'].present?
      client_match_criteria['clients.IPADDR'] = @filter_params['client_ip']
    end

    if @filter_params['username'].present?
      client_match_criteria['clients.USERNAME'] = @filter_params['username']
    end

    if @filter_params['hostname'].present?
      client_match_criteria['clients.HOSTNAME'] = @filter_params['hostname']
    end

    aggregate_pipeline << {"$match" => client_match_criteria} unless client_match_criteria.blank?

    #group criteria
    group_criteria = {"_id" => {"client_mac" => "$clients.MAC", "device_mac" => "$info.NASID"}}
    prop_name_map = {"BD" => 'band', "MAC" => "client_mac", "IPADDR" => "ip_address", "WIRED_UNIQ_ID" => 'vlan'}
    project_fields = {"_id" => 0, "last_seen_at" => 1, "device_mac" => 1}
    
    ["SSID", "BD", "SIGNAL_AVG", "RX_BITRATE", "TX_BIT", "SIGNAL", "MAC", "IPADDR", "HOSTNAME", "RX_BYTES", "RX_PACKETS", "RX_BYTES_INT", "RX_PACKETS_INT", "TX_BYTES", "TX_PACKETS", "TX_BYTES_INT", "TX_PACKETS_INT", "TX_RATE", "RX_RATE", "DEVICE_TYPE", "WIRED_UNIQ_ID", "USERNAME"].each do |prop|
      group_criteria[prop_name_map[prop] || prop.downcase] = {"$last" => "$clients.#{prop}"}
      project_fields[prop_name_map[prop] || prop.downcase] = 1
    end
    
    group_criteria['last_seen_at'] = {"$last" => "$created_at"}
    group_criteria['device_mac'] = {"$last" => "$info.NASID"}
    aggregate_pipeline << {"$group" => group_criteria}

    aggregate_pipeline << {"$project" => project_fields}
    p aggregate_pipeline

    clients = MonitoringChild.collection.aggregate(aggregate_pipeline)

    clients.map do |cli|
      cli['device_type'] = DEVICE_TYPE_MAP[cli['device_type'] || 0]
      cli['vlan'] = VLan.where(id: cli['vlan'].gsub('VL','')).last.try(:v_lan_id).try(:to_i) unless cli['vlan'].blank?
      cli['device_name'] = $redis.hget("AP:#{cli['device_mac']}", 'AP')
      cli['network_name'] = $redis.hget("AP:#{cli['device_mac']}", 'Network')
      cli['last_seen_at'] = cli['last_seen_at'].to_i
      
      cli
    end

    return {data: {clients: clients}}
  end
end

#LiveAggregateDataQuery.new('live', {'device_mac' => "00:0C:66:13:31:8B", 'start_time' => (Time.now-100.minutes).to_s, 'end_time' => Time.now.to_s}).search_clients