# frozen_string_literal: true

# HubLoad - Calculates dynamic event sampling rate based on system load
#
# This service monitors SolidQueue depth and adjusts sampling rates to prevent
# the Hub from being overwhelmed while ensuring critical events are always captured.
class HubLoad
  # Queue depth thresholds
  THRESHOLDS = {
    normal: 0..1_000,       # 100% sampling
    moderate: 1_001..5_000, # 50% sampling
    high: 5_001..10_000,    # 20% sampling
    critical: 10_001..Float::INFINITY  # 5% sampling
  }.freeze

  SAMPLING_RATES = {
    normal: { allowed: 1.0, blocked: 1.0, rate_limited: 1.0 },
    moderate: { allowed: 0.5, blocked: 1.0, rate_limited: 1.0 },
    high: { allowed: 0.2, blocked: 1.0, rate_limited: 1.0 },
    critical: { allowed: 0.05, blocked: 1.0, rate_limited: 1.0 }
  }.freeze

  # Get current sampling configuration based on load
  def self.current_sampling
    load_level = calculate_load_level
    rates = SAMPLING_RATES[load_level]

    {
      allowed_requests: rates[:allowed],
      blocked_requests: rates[:blocked],
      rate_limited_requests: rates[:rate_limited],
      effective_until: next_sync_time,
      load_level: load_level,
      queue_depth: queue_depth
    }
  end

  # Test method for different load levels
  def self.test_sampling(load_level)
    rates = SAMPLING_RATES[load_level] || SAMPLING_RATES[:normal]

    {
      allowed_requests: rates[:allowed],
      blocked_requests: rates[:blocked],
      rate_limited_requests: rates[:rate_limited],
      effective_until: next_sync_time,
      load_level: load_level,
      queue_depth: THRESHOLDS[load_level].first + 100
    }
  end

  # Calculate when sampling should be rechecked (next agent sync)
  def self.next_sync_time
    10.seconds.from_now.iso8601(3)
  end

  # Get current queue depth
  def self.queue_depth
    # SolidQueue stores jobs in the jobs table
    # Count pending/running jobs only
    SolidQueue::Job.where(finished_at: nil).count
  rescue StandardError => e
    Rails.logger.error "Failed to get queue depth: #{e.message}"
    0
  end

  # Determine load level based on queue depth
  def self.calculate_load_level
    depth = queue_depth

    THRESHOLDS.each do |level, range|
      return level if range.cover?(depth)
    end

    :critical # Fallback
  end

  # Check if hub is under heavy load
  def self.overloaded?
    calculate_load_level.in?([:high, :critical])
  end

  # Get load statistics for monitoring
  def self.stats
    {
      queue_depth: queue_depth,
      load_level: calculate_load_level,
      sampling_rates: SAMPLING_RATES[calculate_load_level],
      overloaded: overloaded?
    }
  end
end
