# This file is distributed under New Relic's license terms.
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
# frozen_string_literal: true

require_relative '../../test_helper'
require_relative '../data_container_tests'
require_relative '../common_aggregator_tests'
require 'new_relic/agent/custom_event_aggregator'

module NewRelic::Agent
  class CustomEventAggregatorTest < Minitest::Test
    def setup
      nr_freeze_process_time
      events = NewRelic::Agent.instance.events
      @aggregator = NewRelic::Agent::CustomEventAggregator.new(events)
    end

    # Helpers for DataContainerTests

    def create_container
      @aggregator
    end

    def populate_container(container, n)
      n.times do |i|
        container.record(:atype, {:number => i})
      end
    end

    include NewRelic::DataContainerTests

    # Helpers for CommonAggregatorTests

    def generate_event(name = 'Controller/blogs/index', options = {})
      generate_request(name, options)
    end

    def generate_request(name = 'Controller/whatever', options = {})
      payload = options.merge(:name => name)

      @aggregator.record(:custom, payload)
    end

    def last_events
      aggregator.harvest![1]
    end

    def aggregator
      @aggregator
    end

    def name_for(event)
      event[1]['name']
    end

    include NewRelic::CommonAggregatorTests

    def test_record_by_default_limit
      max_samples = NewRelic::Agent.config[:'custom_insights_events.max_samples_stored']
      n = max_samples + 1
      n.times do |i|
        @aggregator.record(:footype, :number => i)
      end

      metadata, results = @aggregator.harvest!

      assert_equal(max_samples, metadata[:reservoir_size])
      assert_equal(n, metadata[:events_seen])
      assert_equal(max_samples, results.size)
    end

    def test_max_attribute_count
      attributes = {}
      70.times do |i|
        attributes["key#{i}"] = "value#{i}"
      end
      @aggregator.record(:footype, attributes)

      event = @aggregator.harvest![1].first

      assert_equal(64, event[1].size)
    end

    def test_truncates_attributes
      params = {
        "#{'b' * 300}" => 'a' * 5000
      }

      expected = {
        "#{'b' * 255}" => 'a' * 4095
      }

      @aggregator.record(:footype, params)

      actual = @aggregator.harvest![1].first[1]

      assert_equal(expected, actual)
    end

    def test_does_not_truncate_llm_embedding_input_attribute
      with_config(:'ai_monitoring.enabled' => true) do
        params = {'input' => 'a' * 5000}
        expected = {'input' => 'a' * 5000}

        @aggregator.record(:LlmEmbedding, params)
        actual = @aggregator.harvest![1].first[1]

        assert_equal(expected, actual)
      end
    end

    def test_does_not_truncate_llm_chat_message_content_attribute
      with_config(:'ai_monitoring.enabled' => true) do
        params = {'content' => 'a' * 5000}
        expected = {'content' => 'a' * 5000}

        @aggregator.record(:LlmChatCompletionMessage, params)
        actual = @aggregator.harvest![1].first[1]

        assert_equal(expected, actual)
      end
    end

    def test_lowering_limit_truncates_buffer
      orig_max_samples = NewRelic::Agent.config[:'custom_insights_events.max_samples_stored']

      orig_max_samples.times do |i|
        @aggregator.record(:footype, :number => i)
      end

      new_max_samples = orig_max_samples - 10
      with_config(:'custom_insights_events.max_samples_stored' => new_max_samples) do
        metadata, results = @aggregator.harvest!

        assert_equal(new_max_samples, metadata[:reservoir_size])
        assert_equal(orig_max_samples, metadata[:events_seen])
        assert_equal(new_max_samples, results.size)
      end
    end

    def test_merge_respects_event_limits_by_type
      with_config(:'custom_insights_events.max_samples_stored' => 10) do
        11.times do |i|
          @aggregator.record(:t, :foo => :bar)
        end
        old_events = @aggregator.harvest!

        3.times do |i|
          @aggregator.record(:t, :foo => :bar)
        end

        @aggregator.merge!(old_events)

        _, events = @aggregator.harvest!

        assert_equal(10, events.size)
      end
    end

    def test_record_adds_type_and_timestamp
      t0 = Process.clock_gettime(Process::CLOCK_REALTIME)
      @aggregator.record(:type_a, :foo => :bar, :baz => :qux)

      _, events = @aggregator.harvest!

      assert_equal(1, events.size)
      event = events.first

      event[0].delete('priority')

      assert_equal({'type' => 'type_a', 'timestamp' => t0.to_i}, event[0])
      assert_equal({'foo' => 'bar', 'baz' => 'qux'}, event[1])
    end

    def test_records_supportability_metrics_after_harvest
      with_config(:'custom_insights_events.max_samples_stored' => 5) do
        engine = NewRelic::Agent.instance.stats_engine
        engine.expects(:tl_record_supportability_metric_count).with('Events/Customer/Seen', 9)
        engine.expects(:tl_record_supportability_metric_count).with('Events/Customer/Sent', 5)
        engine.expects(:tl_record_supportability_metric_count).with('Events/Customer/Dropped', 4)

        9.times { @aggregator.record(:t, :foo => :bar) }
        @aggregator.harvest!
      end
    end

    def test_aggregator_defers_custom_event_creation
      with_config(aggregator.class.capacity_key => 5) do
        5.times { generate_event }
        aggregator.expects(:create_event).never
        aggregator.record('ImpossibleEvent', {priority: -999.0})
      end
    end
  end
end
