# frozen_string_literal: true

module Submissions
  module EnsureResultGenerated
    WAIT_FOR_RETRY = 2.seconds
    CHECK_EVENT_INTERVAL = 1.second
    CHECK_COMPLETE_TIMEOUT = 90.seconds

    WaitForCompleteTimeout = Class.new(StandardError)
    NotCompletedYet = Class.new(StandardError)

    module_function

    def call(submitter)
      return [] unless submitter

      raise NotCompletedYet unless submitter.completed_at?

      return submitter.documents if ApplicationRecord.uncached { submitter.document_generation_events.complete.exists? }

      events =
        ApplicationRecord.uncached do
          DocumentGenerationEvent.where(submitter:).order(:created_at).to_a
        end

      if events.present? && events.last.event_name.in?(%w[start retry])
        wait_for_complete_or_fail(submitter)
      else
        submitter.document_generation_events.create!(event_name: events.present? ? :retry : :start)

        documents = GenerateResultAttachments.call(submitter)

        submitter.document_generation_events.create!(event_name: :complete)

        documents
      end
    rescue ActiveRecord::RecordNotUnique
      sleep WAIT_FOR_RETRY

      retry
    rescue StandardError => e
      Rollbar.error(e) if defined?(Rollbar)
      Rails.logger.error(e)

      submitter.document_generation_events.create!(event_name: :fail)

      raise
    end

    def wait_for_complete_or_fail(submitter)
      total_wait_time = 0

      loop do
        sleep CHECK_EVENT_INTERVAL
        total_wait_time += CHECK_EVENT_INTERVAL

        last_event =
          ApplicationRecord.uncached do
            DocumentGenerationEvent.where(submitter:).order(:created_at).last
          end

        break submitter.documents.reload if last_event.event_name.in?(%w[complete fail])

        raise WaitForCompleteTimeout if total_wait_time > CHECK_COMPLETE_TIMEOUT
      end
    end
  end
end
