# frozen_string_literal: true

module Matterhorn
  module Models
    class Job < Matterhorn::Model
      attr_reader :id, :item
      alias_method :jid, :id

      attr_writer :status, :completed_at

      def initialize(jid, item, queue = nil)
        @id = jid
        @item = item
        @queue = queue
      end

      def repository
        item['args'][0]
      end

      def pull_request_number
        item['args'][1]
      end

      def pull_request
        @pull_request ||= Matterhorn::GitHub.pull_request(repository, pull_request_number)
      end

      def pull_request_commits
        @pull_request_commits ||= Matterhorn::GitHub.pull_request_commits(repository, pull_request_number)
      end

      def author
        @author ||= Matterhorn::Models::User.new(pull_request['user']['login'], pull_request['user']['ldap_dn'])
      end

      def last_commit
        @last_commit ||= begin
          last_commit = nil
          pull_request_commits.each do |commit|
            next if commit['author'].nil? || commit['author']['login'] == GITHUB_USERNAME
            last_commit = commit
            break
          end
          last_commit
        end
      end

      def last_committer
        @last_committer ||= Matterhorn::Models::User.new(last_commit['author']['login'], last_commit['author']['ldap_dn']) unless last_commit.nil?
      end

      def merger
        @merger ||= item['args'][-1]['merger']
      end

      def priority?
        item['queue'].include? ':priority'
      end

      def admin?
        return !!item['args'][2]['admin'] if item['args'][2]
        false
      end

      def active?
        @queue&.active_job&.id == @id
      end

      def teamcity_build
        return {} if PROJECTS[:projects][@queue.id][:teamcity].nil?

        @teamcity_build ||= (active? ? Matterhorn::TeamCity.current_run(repository, pull_request_number, pull_request['head']['sha']) : {})
      end

      def teamcity_link
        @teamcity_link ||= teamcity_build['webUrl']
      end

      def percentage_complete
        # since this is just an approximation from TeamCity, assume it's ~5% short of actual progress
        @percentage_complete ||= teamcity_build['running-info']['percentageComplete'].to_i * 0.95 if in_progress?
      end

      def estimated_duration
        @estimated_duration ||= teamcity_build['running-info']['estimatedTotalSeconds'].to_i if in_progress?
      end

      def duration
        @duration ||= teamcity_build['running-info']['elapsedSeconds'].to_i if in_progress?
      end

      def in_progress?
        active? && !teamcity_build['running-info'].empty?
      end

      def status
        @status || 'queued'
      end

      def teamcity_status
        return nil if teamcity_build.nil?
        return teamcity_build['state'] unless teamcity_build['state'] == 'finished'
        return 'failed' if teamcity_build['state'] == 'finished' && teamcity_build['status'].downcase == 'failure'
        teamcity_build['status'].downcase
      end

      def to_json(options = nil)
        {
          id: id,
          author: author,
          prNumber: pull_request_number,
          prLink: "#{GITHUB_URL.sub(/\/api\/v3$/,"")}/#{repository}/pull/#{pull_request_number}",
          title: pull_request['title'],
          teamcityLink: teamcity_link,
          percentageComplete: percentage_complete,
          estimatedDuration: estimated_duration,
          duration: duration,
          status: status,
          teamcity_status: teamcity_status,
          timeQueued: item['enqueued_at'],
          timeCompleted: @completed_at,
          isAdminMerge: admin?,
          isPriorityMerge: priority?,
          lastCommitter: last_committer,
          merger: merger
        }.to_json(options)
      end

      class << self
        def all
          @all ||= begin
            jobs = []
            Sidekiq::JobSet.new do |job|
              jobs << Matterhorn::Models::Job.new(job.jid, job)
            end
            jobs
          end
        end
      end
    end
  end
end
