require 'net/http'
require 'net/https'
require 'uri'
require 'json'
require 'date'

class JenkinsJobScraper
  def initialize(job_name, jenkins_user, jenkins_token)
    @jenkins_username = jenkins_user
    @jenkins_token = jenkins_token
    @jenkins_job = job_name
    @jenkins_job_url = "https://jenkins.internal.justin.tv/job/#{job_name}"
    @jenkins_job_api_url = "#{@jenkins_job_url}/api/json"
    @auth = {:username => @jenkins_username, :password => @jenkins_token}
  end

  def last_build_number
    response = rest_get(@jenkins_job_api_url)

    if response.code.to_i == 200
      body = JSON.parse(response.body)

      return body['lastBuild']['number']
    else
      raise "Error retrieving last build number. Response returned code #{response.code}"
    end
  end

  def get_build_info(build_number)
    build_url = "#{@jenkins_job_url}/#{build_number}"
    api_url = "#{build_url}/api/json"
    timestamp_url = "#{build_url}/buildTimestamp"

    response = rest_get(api_url)
    timestamp = rest_get(timestamp_url)

    # Variables to get pulled out of the Jenkins hash. Initialize outside of block for scope purposes.
    ldap = nil
    initiator = nil
    environment = nil
    trigger_smoca = nil
    upstream_build = nil
    upstream_project = nil

    if response.code.to_i == 200 && timestamp.code.to_i == 200
      body = JSON.parse(response.body)

      # Jenkins returns a hash with nested hashes and arrays. The order varies per project
      # Need to loop through all nests until we find the right thing
      body.each_key do |key|
        if key == 'actions'
          body[key].each do |actions|
            if actions.kind_of?(Hash)

              # Analyze Parameters
              if actions.has_key?'parameters'
                actions['parameters'].each do |params|

                  # Environment
                  if params['name'] == 'ENVIRONMENT'
                    environment = params['value']
                  end

                  # GITHUB_CREATOR / LDAP Username (available if deploy tool initated it)
                  if params['name'] == 'GITHUB_CREATOR'
                    ldap = params['value'] unless params['value'].empty?
                  end

                  if params['name'] == 'TRIGGER_SMOCA'
                    trigger_smoca = params['value']
                  end
                end
              end

              # Get initator name (available if manually initiated through Jenkins)
              if actions.has_key?('causes')
                actions['causes'].each do |causes|
                  if causes.has_key?('userName')
                    initiator = causes['userName']
                  end

                  if causes.has_key?('upstreamBuild')
                    upstream_build = causes['upstreamBuild']
                  end

                  if causes.has_key?('upstreamProject')
                    upstream_project = causes['upstreamProject']
                  end
                end
              end
            end
          end
        end
      end

      # If it is a deploy job with GITHUB_CREATOR, use that. If not, it'll use who manually triggered the job.
      if ldap
        initiated_by = ldap
        ldap = true
      elsif initiator
        initiated_by = initiator
        ldap = false
      else
        initiated_by = nil
        ldap = false
      end

      return {
          'number' => build_number,
          'displayName' => body['fullDisplayName'],
          'result' => body['result'],
          'url' => build_url,
          'timestamp' => body['timestamp'].to_s,
          'initiatedBy' => initiated_by,
          'environment' => environment,
          'smoca_triggered' => trigger_smoca,
          'ldap' => ldap,
          'building' => body['building'],
          'queueId' => body['queueId'],
          'duration' => body['duration'],
          'jobName' => @jenkins_job,
          'upstreamBuild' => upstream_build,
          'upstreamProject' => upstream_project
      }

    elsif response.code.to_i == 403 # Forbidden
      regex = /<title>.*<\/title>/
      error = response.body.to_s.match regex
      puts error
      raise Exception.new("Invalid token for Jenkins. Jenkins returned #{response.code.to_i}")
    elsif response.code.to_i == 404 # Not Found
      return nil
    else
      raise Exception.new("Unknown Error. Jenkins returned invalid response." \
                          "\n\t#{response.code}: #{api_url}\n\t#{timestamp.code}: #{timestamp_url}")
    end
  end


  private

    def rest_get(url)
      uri = URI.parse(url)

      Net::HTTP.start(uri.host, uri.port,
          :use_ssl => uri.scheme == 'https') do |http|
        request = Net::HTTP::Get.new uri
        request.basic_auth @auth[:username], @auth[:password]

        return http.request request
      end
    end
end
