# typed: true # rubocop:todo Sorbet/StrictSigil
# frozen_string_literal: true

require "downloadable"
require "concurrent/promises"
require "concurrent/executors"

module Homebrew
  class DownloadQueue
    sig { returns(Concurrent::FixedThreadPool) }
    attr_reader :pool
    private :pool

    sig { params(size: Integer).void }
    def initialize(size = 1)
      @pool = Concurrent::FixedThreadPool.new(size)
    end

    sig { params(downloadable: Downloadable, force: T::Boolean).returns(Concurrent::Promises::Future) }
    def enqueue(downloadable, force: false)
      quiet = pool.max_length > 1
      # Passing in arguments from outside into the future is a common `concurrent-ruby` pattern.
      # rubocop:disable Lint/ShadowingOuterLocalVariable
      Concurrent::Promises.future_on(pool, downloadable, force, quiet) do |downloadable, force, quiet|
        downloadable.clear_cache if force
        downloadable.fetch(quiet:)
      end
      # rubocop:enable Lint/ShadowingOuterLocalVariable
    end

    sig { void }
    def cancel
      # FIXME: Implement graceful cancellaction of running downloads based on
      #        https://ruby-concurrency.github.io/concurrent-ruby/HEAD/Concurrent/Cancellation.html
      #        instead of killing the whole thread pool.
      pool.kill
    end

    sig { void }
    def shutdown
      pool.shutdown
      pool.wait_for_termination
    end
  end
end
