# frozen_string_literal: true

require_relative '../../metadata/ext'
require_relative '../analytics'
require_relative 'ext'
require_relative '../utils/quantization/hash'

module Datadog
  module Tracing
    module Contrib
      module Rake
        # Instrumentation for Rake tasks
        module Instrumentation
          def self.included(base)
            base.prepend(InstanceMethods)
          end

          # Instance methods for Rake instrumentation
          module InstanceMethods
            def invoke(*args)
              return super if !enabled? || !instrumented_task?

              Tracing.trace(Ext::SPAN_INVOKE, **span_options) do |span|
                annotate_invoke!(span, args)
                super
              end
            ensure
              shutdown_tracer!
            end

            def execute(args = nil)
              return super if !enabled? || !instrumented_task?

              Tracing.trace(Ext::SPAN_EXECUTE, **span_options) do |span|
                annotate_execute!(span, args)
                super
              end
            ensure
              shutdown_tracer!
            end

            private

            # Task names are verified dynamically, in order to be agnostic of
            # when tracing is configured in relation to Rake task declaration.
            def instrumented_task?
              configuration[:tasks].include?(name)
            end

            def shutdown_tracer!
              Tracing.shutdown! if Tracing.active_span.nil? && ::Rake.application.top_level_tasks.include?(name)
            end

            def annotate_invoke!(span, args)
              span.resource = name
              # Set analytics sample rate
              if Contrib::Analytics.enabled?(configuration[:analytics_enabled])
                Contrib::Analytics.set_sample_rate(span, configuration[:analytics_sample_rate])
              end

              # Measure service stats
              Contrib::Analytics.set_measured(span)

              span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
              span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_INVOKE)
              span.set_tag(Ext::TAG_TASK_ARG_NAMES, arg_names)
              span.set_tag(Ext::TAG_INVOKE_ARGS, quantize_args(args)) unless args.nil?
            rescue => e
              Datadog.logger.debug("Error while tracing Rake invoke: #{e.class.name} #{e.message}")
            end

            def annotate_execute!(span, args)
              span.resource = name
              span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
              span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_EXECUTE)
              span.set_tag(Ext::TAG_EXECUTE_ARGS, quantize_args(args.to_hash)) unless args.nil?
            rescue => e
              Datadog.logger.debug("Error while tracing Rake execute: #{e.class.name} #{e.message}")
            end

            def quantize_args(args)
              quantize_options = configuration[:quantize][:args]
              Contrib::Utils::Quantization::Hash.format(args, quantize_options)
            end

            def enabled?
              Datadog.configuration.tracing.enabled &&
                configuration[:enabled] == true
            end

            def span_options
              {service: configuration[:service_name]}
            end

            def configuration
              Datadog.configuration.tracing[:rake]
            end
          end
        end
      end
    end
  end
end
