require 'httparty'
require 'json'
require 'smoca_common/utils/twitch_utils'

class BmpConfig
  # BrowserMob-Proxy captures performance data from browsers
  # This class is a wrapper of the rest API of our Browsermob Proxy server
  # Full API endpoints are documented at https://github.com/lightbody/browsermob-proxy/

  attr_reader :proxy_full_address

  def initialize
    # Browsermob Server Configuration
    @bmp_ip = 'bmp.us-west2.justin.tv'
    @bmp_port = 9090
    @bmp_url = "http://#{@bmp_ip}:#{@bmp_port}/proxy"

    # Proxy Configuration
    @proxy_port = TwitchUtils.nil_or_empty?(ENV['BMP_PORT']) ? create_proxy : ENV['BMP_PORT'].to_i
    @proxy_full_address = "#{@bmp_ip}:#{@proxy_port}"

    if open_proxies.include?(@proxy_port)
      puts "[INFO] Connected to Proxy: #{@proxy_full_address}"
    else
      raise 'Encountered an error creating the proxy'
    end

    blacklist_requests
  end

  # Generates a new HAR for the proxy
  # Any preceding data prior to calling this method will be erased.
  # Set 'captureContent=true' captures POST data
  def new_har
    endpoint = "#{@bmp_url}/#{@proxy_port}/har?captureContent=true"
    response = HTTParty.put(endpoint)

    if response.code == 204 || response.code == 200
      return true
    else
      raise "Error creating new HAR. Response code: #{response.code}. Endpoint: #{endpoint}."
    end

  end

  def get_har_path
    return @@file_path
  end

  # Returns the HAR data generated
  def get_har_data
    @@file_path = "#{@bmp_url}/#{@proxy_port}/har"
    response = HTTParty.get(@@file_path)

    if response.code == 200
      return response.body
    else
      raise "Error getting HAR data. Response code: #{response.code}. Endpoint: #{@@file_path}. Body: #{response.body}"
    end
  end

  # Saves the HAR data to a file
  # @return String Filepath of where the HAR was saved
  def save_har(filename)
    data = get_har_data

    current_date = Time.now.strftime('%m_%d_%Y') # mm_dd_yyyy
    directory_path = "./resources/hars/#{current_date}" # Make a file path so that we can group HARs by the date (easy deletion)

    Dir.mkdir(directory_path) unless Dir.exists?(directory_path) # Create the date folder unless it already exists
    filepath = "#{directory_path}/#{filename}"

    File.new(filepath, 'w+') # Create file
    open(filepath, 'w') do |f| # Write to file
      f.puts data
    end

    return filepath
  end

  # Used to define a list of requests to block
  def blacklist_requests
    add_blacklist_request('http://www.twitch.tv/experiments.json', 403) if SpecData.test_suite == 'player_ui'
    add_blacklist_request('https://www.twitch.tv/experiments.json', 403) if SpecData.test_suite == 'player_ui'
  end

  # Adds a URL Regex to blacklist through BMP
  # @param request_regex String Regular Expression of the URL to block
  # @param status Int HTTP status code to return for URLs that are blacklisted
  def add_blacklist_request(request_regex, status)
    HTTParty.put("#{@bmp_url}/#{@proxy_port}/blacklist", :query => {:regex => request_regex, :status => status})

    puts "DEBUG: Added \"#{request_regex}\" to the blacklist"
  end

  # @return String Blacklisted Items
  def get_blacklist
    response = HTTParty.get("#{@bmp_url}/#{@proxy_port}/blacklist")

    return response.body if response.code == 200
  end

  # Shut down the proxy and close the port
  def close_proxy
    puts "Closing proxy: #{@bmp_url}:#{@proxy_port}"
    response = HTTParty.delete("#{@bmp_url}/#{@proxy_port}")

    return response.code == 200
  end

  # PUT /proxy/[port]/limit - Limit the bandwidth through the proxy.
  def limit_proxy_bandwidth(latency, downstream_kbps, upstream_kbps)
    response = HTTParty.put("#{@bmp_url}/#{@proxy_port}/limit?latency=#{latency}&downstreamKbps=#{downstream_kbps}&upstreamKbps=#{upstream_kbps}")
  end

  # BMP does not currently support.
  # https://github.com/lightbody/browsermob-proxy/issues/510
  # def disable_bandwidth_cap
  #   response = HTTParty.put("#{@bmp_url}/#{@proxy_port}/limit?enable=false")
  # end

  # Displays the amount of data remaining to be uploaded/downloaded until the limit is reached.
  def get_proxy_bandwidth
    response = HTTParty.get("#{@bmp_url}/#{@proxy_port}/limit")
    puts "Amount of data remaining: #{response}"
  end

  private

  # @return Array Available open proxy ports
  def open_proxies
    response = HTTParty.get(@bmp_url)

    if response.code != 200
      # There were cases where the proxy was returning a 500 on this call
      # I suspect when running in Parallel, BMP is getting hit with way too many requests
      # If a 500 error gets returned, try one more time after 5 seconds.

      puts "WARNING: Checking for open proxies resulted in unexpected Response Code: #{response.code}. Trying again..."
      sleep(5)
      response = HTTParty.get(@bmp_url)
    end

    # Raise the error if it is still not a 200
    raise "Encountered a problem searching for open proxy ports. "\
      "Response Code: #{response.code}\n\nBody:\n#{response.body}" unless response.code == 200

    data = JSON.parse(response.body)

    ports = Array.new
    data['proxyList'].each do |x|
      ports.push(x['port'])
    end

    return ports
  end

  # Creates a new proxy to record data
  # @return Fixnum Proxy port number that was created
  def create_proxy
    response = HTTParty.post(@bmp_url)

    if response.code == 200
      data = JSON.parse(response.body)
      return data['port']
    else
      raise "Error creating proxy. Response code: #{response.code}. Body: #{response.body}"
    end
  end
end
