# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true

require 'contrast/agent/assess/events/event_factory'
require 'contrast/agent/assess/events/source_event'

module Contrast
  module Agent
    module Assess
      module Property
        # This module serves to hold the functionality required for the
        # management of our dataflow events.
        #
        # @attr_reader event [Contrast::Agent::Assess::ContrastEvent] the
        #   latest event to track
        module Evented
          attr_accessor :event

          # Create a new event and add it to the event set.
          #
          # @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
          #   the node that governs this event.
          # @param tagged [Object] the Target to which this event pertains.
          # @param object [Object] the Object on which the method was invoked
          # @param ret [Object] the Return of the invoked method
          # @param args [Array<Object>] the Arguments with which the method
          #   was invoked
          # @param source_type [String] the type of this source, from the
          #   source_node, or a KEY_TYPE if invoked for a map
          # @param source_name [String, nil] the name of this source, i.e.
          #   the key used to accessed if from a map or nil if a type like
          #   BODY
          def build_event policy_node, tagged, object, ret, args, source_type = nil, source_name = nil
            @event = Contrast::Agent::Assess::Events::EventFactory.build(policy_node, tagged, object, ret, args, source_type, source_name)
            report_sources(tagged, event)
          end

          private

          # Append the sources of the given event to the current request
          # context's observed route
          #
          # @param tagged [Object] The Target of the Event
          # @param event [Contrast::Agent::Assess::Events::ContrastEvent]
          def report_sources tagged, event
            return unless tagged && !tagged.to_s.empty?
            return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
            return unless event.source_type

            current_request = Contrast::Agent::REQUEST_TRACKER.current
            return unless current_request
            if current_request.observed_route.sources.any? { |source| source.type == event.forced_source_type && source.name == event.forced_source_name }
              return
            end

            event_source_dtm = event.build_event_source_dtm
            return unless event_source_dtm

            current_request.observed_route.sources << event_source_dtm
          end
        end
      end
    end
  end
end