# typed: true
module PerformJobHelpers
  extend T::Sig
  extend T::Helpers
  abstract!

  # TODO - migrate all the calls to perform_now to use this
  sig do
    params(
      params: T::Hash[Symbol, T.untyped],
      should_raise: T.any(T::Boolean, T.class_of(Exception), String, Regexp),
      skip_enqueue_found_links: T::Boolean,
    ).returns(T.untyped)
  end
  def perform_now(params, should_raise: false, skip_enqueue_found_links: true)
    ret =
      described_class.perform_now({ skip_enqueue_found_links: }.merge(params))

    bt_printer =
      Kernel.proc do
        bt = ret.backtrace.reject { |l| l =~ %r{/gems/} }[0..10]
        "!> " + ret.message[0..100] + "\n" + bt.join("\n")
      end

    case should_raise
    when false
      expect(ret).to_not be_a(Exception), bt_printer
    when Class
      expect(ret).to be_a(should_raise), bt_printer
    when String, Regexp
      expect(ret.message).to match(should_raise), bt_printer
    else
      expect(ret).to be_a(Exception), ret.nil? ? "no exception" : bt_printer
    end

    ret
  end

  def set_up_gallery_dl_mock(mock, sequence)
    sequence.each do |seq|
      expected = receive(seq[:receive])

      if seq[:with].respond_to?(:call)
        expected = expected.with(*seq[:with].call(sequence))
      else
        expected = expected.with(*seq[:with])
      end if seq[:with]

      expected = expected.and_return(seq[:return]) if seq[:return]

      expect(mock).to(expected)
    end

    allow(mock).to(receive(:next_message).and_raise(RuntimeError.new))
  end

  def gallery_dl_user_with_no_tweets_sequence(mock)
    set_up_gallery_dl_mock(
      mock,
      [
        {
          receive: :start_twitter_user,
          with: ["curtus", { caused_by_entry: nil }],
        },
        {
          receive: :next_message,
          with: [{ caused_by_entry: nil }],
          return:
            Scraper::GalleryDlClient::HttpRequestEvent.new(
              log_entry: instance_double("::HttpLogEntry"),
              response_code: 200,
              response_headers: {
                "content-type": "application/json",
              },
              body: {
                "data" => {
                  "user" => {
                    "result" => {
                      "__typename" => "User",
                      "rest_id" => "1234567",
                    },
                  },
                },
              }.to_json,
            ),
        },
        {
          receive: :next_message,
          with:
            Kernel.proc do |sequence|
              [{ caused_by_entry: sequence[1][:return].log_entry }]
            end,
          return: Scraper::GalleryDlClient::FinishEvent.new,
        },
      ],
    )
  end

  sig { abstract.returns(T.class_of(ApplicationJob)) }
  def described_class
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def expect(args)
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def be_a(args)
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def match(args)
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def receive(args)
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def allow(args)
  end

  sig { abstract.params(args: T.untyped).returns(T.untyped) }
  def instance_double(args)
  end
end
