# typed: strict
class EnqueueJobBase < Tasks::InterruptableTask
  include HasColorLogger
  abstract!

  class DateHelper
    extend ActionView::Helpers::DateHelper
  end

  sig do
    params(perform_max: T.nilable(Integer), log_sink: T.any(IO, StringIO)).void
  end
  def initialize(perform_max: nil, log_sink: $stderr)
    @total_performed = T.let(0, Integer)
    @perform_max = T.let(perform_max, T.nilable(Integer))
    @inferred_queue_size = T.let(0, Integer)
    super(log_sink:)
  end

  sig { returns(Integer) }
  def high_water_mark
    100
  end

  sig { returns(Integer) }
  def low_water_mark
    50
  end

  sig { returns(ActiveSupport::Duration) }
  def delay_time
    10.seconds
  end

  sig { void }
  def run
    @inferred_queue_size = queue_size
    logger.info(
      "initial queue size is #{@inferred_queue_size}, starting enqueuing",
    )
    start_enqueuing
  end

  sig { abstract.void }
  def start_enqueuing
  end

  sig { params(block: T.proc.void).void }
  def enqueue(&block)
    # if we're under the high water mark, we can just enqueue and return
    # so we get called again as soon as possible
    if @inferred_queue_size < high_water_mark
      # logger.info("queue is at #{@inferred_queue_size}, enqueuing")
    else
      # if we're over the high water mark, we need to wait for the queue to drop
      # so we don't enqueue too many jobs at once
      while @inferred_queue_size > low_water_mark
        logger.info(
          "waiting for queue to drop to #{low_water_mark} (currently #{@inferred_queue_size}, total performed #{@total_performed})",
        )
        sleep delay_time.in_seconds
        @inferred_queue_size = queue_size
      end
    end

    block.call
    @inferred_queue_size += 1
    @total_performed += 1
  end

  sig { abstract.returns(Integer) }
  def queue_size
  end

  sig do
    params(time: T.nilable(T.any(ActiveSupport::TimeWithZone, Time))).returns(
      String,
    )
  end
  def time_ago_in_words(time)
    return "never" if time.nil?
    "#{DateHelper.time_ago_in_words(time)} ago"
  end
end
