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

require 'contrast/agent/reporting/reporting_events/architecture_component'
require 'contrast/agent/reporting/reporting_events/library_discovery'
require 'contrast/agent/reporting/reporting_events/reporting_event'
require 'contrast/agent/reporting/reporting_events/route_discovery'
require 'contrast/api/dtm.pb'
require 'contrast/components/logger'
require 'json'

module Contrast
  module Agent
    module Reporting
      # This is the new Application Update class which will include all the needed information for the new reporting
      # system. Contains data used by TeamServer to render the Flow Map and SCA features.
      #
      # @attr_reader components [Array<Contrast::Agent::Reporting::ArchitectureComponent>]
      # @attr_reader libraries [Array<Contrast::Agent::Reporting::LibraryDiscovery>]
      class ApplicationUpdate < Contrast::Agent::Reporting::ReportingEvent
        attr_reader :components, :libraries

        class << self
          # @param app_update_dtm [Contrast::Api::Dtm::ApplicationUpdate]
          # @return [Contrast::Agent::Reporting::ApplicationUpdate]
          def convert app_update_dtm
            report = new
            report.attach_data(app_update_dtm)
            report
          end
        end

        def initialize
          @event_method = :PUT
          @event_endpoint = "#{ Contrast::API.api_url }/api/ng/update/application"
          super
        end

        # Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly.
        #
        # @param app_update_dtm [Contrast::Api::Dtm::ApplicationUpdate]
        def attach_data app_update_dtm
          @components = app_update_dtm.components.map do |component|
            Contrast::Agent::Reporting::ArchitectureComponent.convert(component)
          end
          @libraries = app_update_dtm.libraries.values.map do |library|
            Contrast::Agent::Reporting::LibraryDiscovery.convert(library)
          end
        end

        # Convert the instance variables on the class, and other information, into the identifiers required for
        # TeamServer to process the JSON form of this message.
        #
        # @return [Hash]
        # @raise [ArgumentError]
        def to_controlled_hash
          validate
          {
              components: components.map(&:to_controlled_hash),
              libraries: libraries.map(&:to_controlled_hash),
              timestamp: timestamp
          }
        end

        # Ensure the required fields are present.
        #
        # @raise [ArgumentError]
        def validate; end

        private

        # The timestamp field is a bit of a misnomer. It's really the time, in ms, since the settings for this
        # application have been updated.
        #
        # @return [Integer]
        def timestamp
          Contrast::Utils::Timer.now_ms - (Contrast::Agent.reporter&.client&.response_handler&.last_app_update_ms || 0)
        end
      end
    end
  end
end