class SmocaBuildController < ApplicationController
  before_action :logged_in_user, only: [:new, :dashboard]

  require 'httparty'

  def index
    @params = params.slice(:developer, :result) # Trusted Parameters. When merging params, refer to this variable

    # Time filters.
    @start_date = filter_time_for(:start_date, 1.month)
    @end_date = filter_time_for(:end_date)

    # Builds holds all the records.
    # It's useful to refer to for the dropdown filters to always display all options.
    # Note: Automatically filters by time range
    @builds = SmocaBuild.all.where(initiated_at: @start_date..@end_date)

    # For pagination and further filtering.
    @paginated_builds = @builds.paginate(page: params[:page]).order('initiated_at DESC').filter(@params)
  end

  def new
    @browsers = ['Firefox', 'Chrome']
    @operating_system = ['Windows 10']
    @environments = environments('web/web')
  end

  def dashboard
    @builds = SmocaBuild.all.where(developer: current_user.uid)
    @paginated_builds = @builds.paginate(page: params[:page]).order('initiated_at DESC').where(pending: false)
    @in_progress_builds = @builds.where(pending: true)
  end

  def trigger_job
    if params[:environment].blank?
      flash[:danger] = 'Must provide an environment'
      return redirect_to new_smoca_build_path
    end

    build_params = params.permit(:browser, :os, :environment, :uid)

    # TODO: Remove hardcoded qa-smoca value, when we support additional jobs.
    @record = SmocaBuild.new(developer: build_params[:uid], initiated_at: Time.now,
                             job_name: 'qa-smoca', environment: build_params[:environment], pending: true)

    if @record.valid?
      @record.save
      logger.debug "Saved new SmocaBuild record: #{@record.id}"
    else
      logger.error "Encountered issue creating new SmocaBuild record. #{@record.errors.messages}"
      flash[:danger] = 'Error saving build. Please contact #qe-automation.'
      return redirect_to root_path # Abort early
    end

    # Storing params that will be sent to Jenkins
    jenkins_params = {}
    jenkins_params['ENVIRONMENT'] = build_params[:environment]
    jenkins_params['GITHUB_CREATOR'] = build_params[:uid]
    jenkins_params['BROWSER'] = build_params[:browser]
    jenkins_params.merge!(os_parser(build_params[:os]))
    jenkins_params.merge!(browser_version(build_params[:browser]))
    jenkins_params['GRID'] = 'true'
    jenkins_params['GNOSIS_ID'] = @record.id
    jenkins_params['GRID_HOST'] = 'prod'

    #####################
    # Trigger the Build #
    #####################
    triggered_build = initiate_jenkins_build(jenkins_params)

    if triggered_build
      queue_url = triggered_build['location']
      logger.info "Build triggered. Queue URL: #{queue_url}"

      # Pull out the Queue ID to store, looking for the digits. Example format: jenkins.internal...    /queue /item /7014/
      queue_id = queue_url.match(/\/queue\/item\/(\d+)/)[1]

      @record.update_attributes!(queue_id: queue_id) # Add Queue ID to the record
      QueueMonitorJob.perform_async(queue_id)

      flash[:success] = 'Build Successfully Triggered'
      redirect_to @record
    else
      logger.error "Encountered issue initiating Jenkins Build. Triggered Build: #{triggered_build}"
      flash[:danger]  = 'Encountered an error connecting to Jenkins.'
      @record.delete # Delete the record, it failed to trigger.
      redirect_to root_path
    end
  end

  # GET /smoca_build/:id
  # GET /job/:job_name/:build_id
  def show
    if params.has_key?(:job_name) && params.has_key?(:build_id)
      # If someone is trying to access via the job_name/build_id route, redirect them to the Gnosis route
      # It's convenient to have that URL, but for now we want to redirect to the proper place
      # Only relying on that route will come across issues for pending builds with no ID yet
      build = SmocaBuild.find_by!(job_name: params[:job_name], build_id: params[:build_id])
      redirect_to build
    else
      @build = SmocaBuild.find(params[:id])
    end
  end

  def generate_job_data
    # Deprecate - Being called from the manage page
    if params.has_key?(:manage) && params[:manage][:qa_smoca] == '1'

      begin
        # TODO: Remove hardcoded qa-smoca value, when we support additional jobs.
        ScrapeSmocaDataJob.perform_async('qa-smoca')
        flash[:success] = 'Generating Job Data. Builds will be updated shortly. Refresh soon.'
      rescue => e
        flash[:danger] = "Encountered an error: #{e.message}"
      end
    end

    redirect_to smoca_build_index_path
  end

  private

    # Method to determine the time to filter by. Uses either user input, or a default time.
    # @param type Symbol Used to determine what portion of the range. Use either :start_date or :end_date
    # @param offset ActiveSupport::Duration The amount you want to offset the DEFAULT date by. Default 0.
    # @return Time The time to filter by
    def filter_time_for(type, offset=0.month)
      # If user inputted a date, use that. Else, use a default time (which can be offset).
      date = params.dig(:date, type) ? params[:date][type] : (Time.now.utc.to_date - offset)
      return filter_date_to_time(type, date)
    end

    # Converts a date to a filterable time
    # Database should filter from the beginning of the Start Date to the end of End Date
    # This helper method makes sure that happens.
    # @param type Symbol Used to determine what portion of the range. Use either :start_date or :end_date
    # @param date Date The date to be converted to a database filter time
    # @return Time The time for a database to filter by
    def filter_date_to_time(type, date)
      type == :end_date ? Time.parse("#{date} 23:59:59 UTC") : Time.parse("#{date} 00:00:00 UTC")
    end

    # @param params Hash Expects environment and uid keys for passing to Jenkins
    # @return HTTParty::Response The response of the post request, or false if unsuccessful
    def initiate_jenkins_build(jenkins_params)
      auth = {username: Rails.application.secrets.jenkins_username,
              password: Rails.application.secrets.jenkins_token}
      # TODO: Remove hardcoded qa-smoca value, when we support additional jobs.
      build_url = 'https://jenkins.internal.justin.tv/job/qa-smoca/buildWithParameters'

      begin
        response = HTTParty.post(build_url, :basic_auth => auth, query: jenkins_params)
      rescue SocketError
        return false
      end

      response.code == 201 ? (return response) : (return false)
    end

    # @param repo String The Org and Repo to list environments for. In format "org/repo", such as "web/web-client"
    # @return Array Environments within the given org/repo
    def environments(repo)
      begin
        response = HTTParty.get("http://clean-deploy.internal.justin.tv/v1/repos/#{repo}/settings")
      rescue SocketError
        return nil
      end

      if response.code == 200
        body = JSON.parse(response.body)
        return body['deploy']['environments'].keys
      else
        return nil
      end
    end

  # Parses an Operating System between its Operating System and Version
  # Only support Windows 10 at the moment
  # @param [String] os The operating system to parse
  # @return [Hash] A hash containing the OS_PLATFORM and OS_VERSION
  def os_parser(os)
    if os == 'Windows 10'
      return {'OS_PLATFORM' => 'Windows', 'OS_VERSION' => '10'}
    else
      return {'OS_PLATFORM' => os, 'OS_VERSION' => ''}
    end
  end

  # Pass the Browser Version recognized Prod
  # @param [String] browser The Browser to return the version of
  # @return [Hash] Hash containing the BROWSER_VERSION
  def browser_version(browser)
    if browser == 'Firefox'
      return {'BROWSER_VERSION' => '45'}
    else
      return {'BROWSER_VERSION' => ''}
    end
  end
end
