# typed: strict

START_PROMETHEUS_EXPORTER =
  T.let(
    # never start in test mode
    !Rails.env.test? &&
      (
        (
          # and do not start in console mode
          !Rails.env.test? && !Rails.const_defined?("Console") &&
            Rails.const_defined?("Server")
        ) ||
          # always start in sever mode
          Rails.const_defined?("Server") ||
          # always start in worker mode
          (Rails.env == "worker") ||
          # ran with args when in server mode, but no top level task
          (ARGV.any? && Rake.application.top_level_tasks.empty?)
      ),
    T::Boolean,
  )

if START_PROMETHEUS_EXPORTER
  require "prometheus_exporter"
  require "prometheus_exporter/client"
  require "prometheus_exporter/metric"
  require "prometheus_exporter/metric/counter"
  require "prometheus_exporter/instrumentation"
  require "prometheus_exporter/middleware"

  # This reports stats per request like HTTP status and timings
  Rails.application.middleware.unshift PrometheusExporter::Middleware
  PrometheusExporter::Client.default.logger.level = Logger::ERROR
  PrometheusExporter::Instrumentation::ActiveRecord.start(
    custom_labels: {
      type: "puma_single_mode",
    }, #optional params
    config_labels: %i[database host], #optional params
  )
else
  # this mocks out the PrometheusExporter::Client for testing
  #
  # this is a bit of a hack, but it's a way to get around the fact that
  # PrometheusExporter::Client is a singleton and we can't easily mock it out
  # in a test environment, and simply constructing a new instance attempts to
  # connect to a Prometheus server, which we can't rely on in a test environment.
  $stderr.puts "PrometheusExporter is disabled in test, console, and rake task environments"
  module PrometheusExporter
    module Instrumentation
      class PeriodicStats
        class << self
          extend T::Sig
          sig do
            params(
              args: T.untyped,
              frequency: T.untyped,
              client: T.untyped,
              kwargs: T.untyped,
            ).void
          end
          def start(*args, frequency:, client: T.unsafe(nil), **kwargs)
          end

          sig { params(blk: T.proc.void).void }
          def worker_loop(&blk)
          end
        end
      end
    end

    class Client
      class RemoteMetric
      end

      extend T::Sig

      class NullClient < PrometheusExporter::Client
        extend T::Sig

        sig { void }
        def initialize
        end

        sig { params(args: T.untyped).returns(NullMetric) }
        def register(*args)
          NullMetric.new
        end
      end

      @default = T.let(NullClient.new, NullClient)

      sig { returns(NullClient) }
      def self.default
        @default
      end

      class NullMetric < PrometheusExporter::Client::RemoteMetric
        extend T::Sig

        sig { void }
        def initialize
        end

        sig { params(args: T.untyped).void }
        def increment(*args)
        end

        sig { params(args: T.untyped).void }
        def decrement(*args)
        end

        sig { params(args: T.untyped).void }
        def observe(*args)
        end
      end
    end
  end
end
