# typed: false
require "rails_helper"

describe Scraper::Metrics::JobBaseMetrics do
  # Create concrete test job classes
  class TargetJob < Scraper::JobBase
    def self.http_factory_method
      :get_fa_http_client
    end

    def perform(args)
      sleep 0.1
    end
  end

  class TestJob < Scraper::JobBase
    def self.http_factory_method
      :get_fa_http_client
    end

    def perform(args)
      # Simulate some work
      sleep 0.1
      # Enqueue another job
      defer_job(TargetJob, {}) if args[:enqueue_target]
    end
  end

  let(:test_job_class) { TestJob }
  let(:job_class_name) { test_job_class.name }

  describe "job execution metrics" do
    it "records metrics for successful job execution" do
      expect(described_class::JOB_START_COUNT).to receive(:increment).with(
        { job_class: job_class_name },
      )

      # The around_perform block in JobBase ensures these are called
      expect(described_class::JOB_FINISH_COUNT).to receive(:increment).with(
        { job_class: job_class_name, success: true },
      )
      expect(described_class::JOB_FINISH_TIME_HISTOGRAM).to receive(
        :observe,
      ).with(
        be_between(90, 200), # 0.1 seconds = ~100ms with some buffer
        { job_class: job_class_name, success: true },
      )
      expect(described_class::JOB_FINISH_TIME_SUMMARY).to receive(
        :observe,
      ).with(be_between(90, 200), { job_class: job_class_name, success: true })

      test_job_class.perform_now({})
    end

    it "records metrics for failed job execution" do
      error_job =
        Class.new(test_job_class) do
          def perform(args)
            raise "test error"
          end
        end

      expect(described_class::JOB_START_COUNT).to receive(:increment).with(
        { job_class: error_job.name },
      )
      expect(described_class::JOB_FINISH_COUNT).to receive(:increment).with(
        { job_class: error_job.name, success: false },
      )
      expect(described_class::JOB_FINISH_TIME_HISTOGRAM).to receive(
        :observe,
      ).with(
        be_between(0, 100), # Should be quick since it errors immediately
        { job_class: error_job.name, success: false },
      )
      expect(described_class::JOB_FINISH_TIME_SUMMARY).to receive(
        :observe,
      ).with(be_between(0, 100), { job_class: error_job.name, success: false })

      expect(error_job.perform_now({})).to be_a(RuntimeError)
    end

    it "records metrics when a job enqueues another job" do
      expect(described_class::JOB_START_COUNT).to receive(:increment).with(
        { job_class: job_class_name },
      )
      expect(described_class::JOB_FINISH_COUNT).to receive(:increment).with(
        { job_class: job_class_name, success: true },
      )
      expect(described_class::JOB_FINISH_TIME_HISTOGRAM).to receive(
        :observe,
      ).with(be_between(90, 200), { job_class: job_class_name, success: true })
      expect(described_class::JOB_FINISH_TIME_SUMMARY).to receive(
        :observe,
      ).with(be_between(90, 200), { job_class: job_class_name, success: true })

      # Expect the enqueued job metric to be recorded
      expect(described_class::JOB_ENQUEUED_COUNT).to receive(:increment).with(
        { source_class: job_class_name, enqueued_class: TargetJob.name },
      )

      test_job_class.perform_now({ enqueue_target: true })
    end
  end
end
