class Api::BrowserstackController < ApplicationController
  def show
    platforms = retrieve_platforms
    filtered_platforms = filter_platforms(platforms)

    render json: filtered_platforms
  end

  # Retrieves all BrowserStack Platforms in a re-arranged, flat style
  # @return Hash BrowserStack configurations including Platforms, Operating Systems, Browsers and Browser Versions
  private def retrieve_platforms
    bs_platforms = browserstack_platforms
    return parse_platforms(bs_platforms)
  end

  # Filters the platform configuration by user provided parameters
  # User can filter by ?platform, ?os and ?browser
  # Example: ?platform=Windows&os=7&browser=firefox - This will return all browser versions of that configuration
  # Example: ?platform=Windows&os=7 - This will return all supported browsers and their versions
  # @param original_params ActionController::Parameters Parameters provided by the user
  # @param original_platforms Hash The platforms, unfiltered
  # @return Hash The filtered platforms
  private def filter_platforms(original_platforms)
    platforms = original_platforms # The platforms to filter through
    filter_params = params.permit('platform', 'os', 'browser') # The params a user provided
    filter_param_order = %w(platform os browser) # The filter order. Traverse hash starting with Platform, ending Browser

    # Go through each param and traverse through the platforms
    filter_param_order.each do |param|
      if filter_params.has_key?(param)
        # User supplied that filter, so grab those results.
        platforms = platforms[filter_params[param]]
      else
        # The user didn't supply all three filters.
        break
      end
    end

    return platforms
  end

  # Connect to BrowserStack Browsers API and return its result
  # @return Hash Browserstack's raw API results
  def browserstack_platforms
    require 'json'

    endpoint = 'https://api.browserstack.com/4/browsers'

    auth = {:username => Rails.application.secrets.browserstack_user,
            :password => Rails.application.secrets.browserstack_key}

    response = HTTParty.get(endpoint, basic_auth: auth)

    case response.code
      when 200
        body = JSON.parse(response.body)
        return body
      when 401
        # See secrets.yml for authentication keys
        raise 'Authentication error! There was a problem authenticating with the BrowserStack API'
      else
        raise "Error! Browser returned unexpected response code #{response.code}"
    end
  end

  # Filter the BrowserStack API into a flatter hash
  # Each Operating System should have a flat list of its supported browsers and browser versions
  # @params raw_bs_platforms Hash BrowserStack's response from their /browsers endpoint
  # @return Hash A full hash of each Platform's Operating Systems, Supported Browsers and an array of their browser versions
  private def parse_platforms(raw_bs_platforms)
    begin
      platforms = {}

      # Flatten its hash
      raw_bs_platforms.each do |key, value|
        browsers = browsers_for value
        platforms[key] = browsers
      end

      return platforms
    end
  end

  # Method to loop through the browsers of a major platform and return their supported browsers and browser versions for each OS
  # @param platform Hash BrowserStack's value for a major platform
  # @return Hash The Supported Browsers and Browser Version of each Operating System under that Platform
  # Example Response: {'XP' => {'Firefox' => ['32', '33'], 'Chrome => '42', '43'}, '7' => 'Firefox' => ['47', '48']}
  private def browsers_for(platform)
    configuration = {}

    # Loop through Each Operating System within the Platform
    platform.each do |os, browser_data|
      # Establish a key of that OS
      configuration[os] = {}

      browser_data.each do |info|
        # Loop through the array of browser entries, and compile each version number
        if configuration[os][info['browser']] # If an entry exists for that browser, add it's version
          configuration[os][info['browser']] << info['browser_version']
        else
          # If it doesn't exist, add that browser under the OS and create an array with that version
          configuration[os][info['browser']] = [info['browser_version']]
        end
      end
    end

    return configuration
  end
end
