require 'jenkins_job_scraper'

class ScrapeSmocaDataJob
  include Sidekiq::Worker

  def perform(job)
    jenkins_username = Rails.application.secrets.jenkins_username || ENV['JENKINS_USERNAME']
    jenkins_token    = Rails.application.secrets.jenkins_token    || ENV['JENKINS_TOKEN']
    @scraper = JenkinsJobScraper.new(job, jenkins_username, jenkins_token)
    number_of_builds_to_search = (ENV['JENKINS_SCRAPE_AMOUNT'] || 50).to_i

    logger.info 'Searching for Pending Builds to update.'
    update_pending_builds(job) # Updating any jobs in a pending state

    logger.info 'Searching for Existing Builds to import'
    import_builds_from_jenkins(job, number_of_builds_to_search)
  end

  private

  # Scans through any builds not yet imported into the database
  def import_builds_from_jenkins(job, total_builds_to_search = 50)
    last_jenkins_build = @scraper.last_build_number
    existing_builds = SmocaBuild.where(job_name: job).pluck(:build_id)

    for build in 0...(total_builds_to_search)
      build_number = last_jenkins_build - build
      break if build_number <= 0 # Can't have negative or a build id of 0

      if existing_builds.include?(build_number.to_s)
        # Data already exists in the database
        logger.debug "#{build_number} found already exists in the database"
        next
      else
        # Data doesn't exist in the database - grab it from Jenkins API
        logger.info "Adding #{build_number} to database"

        data = @scraper.get_build_info(build_number)
        next if data.nil? # Data was returned as nil, so move to the next one
        next if building?(data)

        build_timestamp = parse_timestamp(data['timestamp'])

        # Save the record into the Database
        record = SmocaBuild.new(build_id: data['number'], initiated_at: build_timestamp, result: data['result'],
          developer: data['initiatedBy'], environment: data['environment'], job_name: data['jobName'])

        if data['result'] == 'ABORTED'
          record[:cancelled] = true
        end

        record.save!
        logger.debug("Saved Build \##{build_number} to database. Record: #{record.inspect}")
        sleep(1) # Rate limiting
      end
    end
  end

  # Scans through any builds in a pending state, and checks Jenkins if it has a finished result
  def update_pending_builds(job)
    pending_builds = SmocaBuild.where(pending: true, job_name: job) # Pull jobs out in the pending state

    pending_builds.each do |build|
      logger.info "Checking Record ID #{build.id}"

      if build.build_id.nil?
        logger.info "Record ID \##{build.id} has a non assigned build id. Skipping"
        next
      end

      data = @scraper.get_build_info(build.build_id)

      # For some reason Jenkins doesn't have this record.
      # TODO: Figure out what we should do with these records. Mark them as cancelled? Delete? Ticketed - SMOC-630
      if data.nil?
        logger.warn "Could not retrieve data for Build ID \##{build.build_id}, Record ID \##{build.id}. Skipping"
        next
      end

      if building?(data)
        logger.info "Record ID #{build.id} is still building. Skipping"
        next
      end

      logger.info "Updating Record \##{build.id}"
      build_timestamp = parse_timestamp(data['timestamp'])
      attributes_to_update = { initiated_at: build_timestamp, result: data['result'],
                               environment: data['environment'], pending: false }

      build.update_attributes!(attributes_to_update)
    end
  end

  # @return Boolean If the build is still in a building status
  def building?(data)
    return data['building']
  end

  # Converts timestamp from string to DateTime for the database
  def parse_timestamp(timestamp)
    return DateTime.strptime(timestamp, '%Q')
  end
end
