module JamRuby
  class MusicianFilter
    
    LATENCY_SCORES = {
      good: { label: 'GOOD', min: 0, max: 40 },
      fair: { label: 'FAIR', min: 40, max: 60 },
      high: { label: 'HIGH', min: 60, max: 10000000 },
      me: { label: 'ME', min: -1, max: -1 },
      unknown: { label: 'UNKNOWN', min: -2, max: -2 }
    };

    def self.filter(user, remote_ip, params)
      #debugger
      latency_good  = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
      latency_fair  = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
      latency_high  = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
      offset        = [params[:offset].to_i, 0].max
      limit         = [params[:limit].to_i, 20].max
      filter_params = {}

      if params[:from_location].present? && params[:from_location].to_s == 'true'
        filter_params.merge!(from_location: "1")
      else
        filter_params.merge!(from_location: "0")
      end
      
      genres = params[:genres]
      filter_params.merge!(genres: genres) if genres
      
      beginner      = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_beginner])
      intermediate  = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_intermediate])
      expert        = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_expert])

      proficiency_levels = []
      proficiency_levels.push(1) if beginner
      proficiency_levels.push(2) if intermediate
      proficiency_levels.push(3) if expert
      
      instruments = params[:instruments]

      if instruments && instruments.any? && proficiency_levels.any?
        inst = []
        instruments.each do |ii|
          proficiency_levels.each do |pl|
            inst << { id: ii[:value], proficiency: pl}
          end
        end
        filter_params.merge!(instruments: inst) 
      end

      filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
      filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?

      begin  
        
        #bm = Benchmark.measure do
          result       = JamRuby::MusicianFilter.users_latency_data(user, remote_ip, latency_good, latency_fair, latency_high, filter_params, offset, limit)
          latency_data = result[:data]
          nextOffset   = result[:next]

          user_ids     = latency_data.map{ |l_data| l_data[:user_id] }   
        #end
      
        # Bugsnag.notify("search_users_benchmark") do |report|
        #   report.severity = "info"
        #   report.add_tab(:benchmark, benchmark: bm.to_s)
        # end if Rails.env.production?

        sobj = JamRuby::MusicianSearch.user_search_filter(user)
        search = sobj.user_search_results(user_ids)
        
        [search, latency_data, nextOffset]
        
      rescue => exception
        #logger.debug("Latency exception: #{exception.message}")
        Bugsnag.notify(exception) do |report|
          report.severity = "error"
          report.add_tab(:latency, {
            params: params,
            user_id: user.id,
            name: user.name,
            url: latency_url,
          })
        end
        raise exception 
      end
    end

    def self.users_latency_data(user_obj, remote_ip, latency_good, latency_fair, latency_high, filter_opts, offset, limit)
      uri = URI(latency_url)
      begin
        http = Net::HTTP.new(uri.host, uri.port)
        http.use_ssl = true if APP_CONFIG.latency_data_host.start_with?("https://")
        req = Net::HTTP::Post.new(uri)
        req["Authorization"] = "Basic #{APP_CONFIG.latency_data_host_auth_code}"
        req["Content-Type"] = "application/json"
  
        req_params = {
          my_user_id: user_obj.id,
          my_public_ip: remote_ip,
          my_device_id: nil,
          my_client_id: nil,
          from_location: filter_opts[:from_location] || "0",
          offset: offset,
          limit: limit
        }
  
        req_params.merge!(instruments: filter_opts[:instruments]) if filter_opts[:instruments]
        req_params.merge!(genres: filter_opts[:genres]) if filter_opts[:genres]
        req_params.merge!(joined_within_days: filter_opts[:joined_within_days]) if filter_opts[:joined_within_days]
        req_params.merge!(active_within_days: filter_opts[:active_within_days]) if filter_opts[:active_within_days]
  
        req.body = req_params.to_json
  
        response = http.request(req)
        
        if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
          json_body = JSON.parse(response.body)
          graph_db_users = json_body['users']
          nextOffset     = json_body['next']
  
          if latency_good || latency_fair || latency_high
            #fiter by latency params
            graph_db_users.select! do |user|
              total_latency = user["ars"]["total_latency"].to_f
              (total_latency >= LATENCY_SCORES[:good][:min] && total_latency <= LATENCY_SCORES[:good][:max] && latency_good) ||
              (total_latency > LATENCY_SCORES[:fair][:min] && total_latency <= LATENCY_SCORES[:fair][:max] && latency_fair) ||
              (total_latency > LATENCY_SCORES[:high][:min] && latency_high)
              end
          end
  
          latency_data = graph_db_users.map { | user |
            { 
              user_id: user["user_id"],
              audio_latency: user["audio_latency"].to_f,
              ars_total_latency: user["ars"]["total_latency"].to_f,
              ars_internet_latency: user["ars"]["internet_latency"].to_f
            }
          }.uniq
          
          return { data: latency_data, next: nextOffset } 
        else
          Bugsnag.notify("LatencyResponseFailed") do |report|
            report.severity = "faliure"
            report.add_tab(:latency, {
              user_id: user_obj.id,
              name: user_obj.name,
              params: req_params,
              url: latency_url,
              code: response.code,
              body: response.body,
            })
          end
          Rails.logger.debug("Latency response failed: #{response.code} #{response.body}")
          raise Exception.new("#{response.code}: #{response.body}")
        end
      rescue => exception
        raise exception
      end
    end

    private

    def self.latency_url
      "#{APP_CONFIG.latency_data_host}/search_users"
    end
  end
end