# typed: strict
module Tasks
  class InterruptableTask
    extend T::Sig
    extend T::Helpers
    abstract!
    PB_FORMAT = T.let("%B %c/%C (%r/sec) %J%% %a %E", String)

    sig { params(log_sink: T.any(IO, StringIO)).void }
    def initialize(log_sink: $stderr)
      @interrupt_monitor =
        T.let(
          Tasks::UserInterruptMonitor.new(log_sink:),
          Tasks::UserInterruptMonitor,
        )
      @log_sink = log_sink
      log("Press Ctrl+C to cleanly interrupt and save progress")
    end

    sig { abstract.returns(String) }
    def progress_key
    end

    sig { params(start_at: T.nilable(String)).returns(T.nilable(String)) }
    def get_progress(start_at)
      value =
        if start_at == "last"
          value = GlobalState.get(progress_key)
        else
          start_at
        end

      if value
        log(
          "[progress key: #{progress_key.bold}] [resuming from: #{value.to_s.bold}]",
        )
      else
        log("[progress key: #{progress_key.bold}] [no saved progress]")
      end

      value
    end

    sig { params(value: String).void }
    def save_progress(value)
      GlobalState.set(progress_key, value)
    end

    sig { params(message: String).void }
    def log(message)
      @log_sink.puts(message)
    end

    sig { returns(T::Boolean) }
    def interrupted?
      @interrupt_monitor.interrupted?
    end

    sig { params(total: T.nilable(Integer)).returns(ProgressBar::Base) }
    def create_progress_bar(total)
      ProgressBar.create(
        total: total,
        progress_mark: " ",
        remainder_mark: " ",
        format: PB_FORMAT,
      )
    end
  end
end
