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

require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions'
require 'contrast/agent/telemetry/events/exceptions/obfuscate'

module Contrast
  module Logger
    # Our decorator for the Ougai logger allowing for the catching, creating and saving Telemetry exceptions
    module AliasedLogging
      ALIASED_WARN = 'warn'.cs__freeze
      ALIASED_ERROR = 'error'.cs__freeze
      ALIASED_FATAL = 'fatal'.cs__freeze

      # @param message [String] The message to log. Use default_message if not specified.
      # @param exception [Exception] The exception or the error
      # @param data [Object] Any structured data
      def warn message = nil, exception = nil, data = nil, &block
        # build Telemetry Exclusion
        build_exclusion(ALIASED_WARN, message, exception, data)
        super(message, exception, data, &block)
      end

      # @param message [String] The message to log. Use default_message if not specified.
      # @param exception [Exception] The exception or the error
      # @param data [Object] Any structured data
      def error message = nil, exception = nil, data = nil, &block
        # build Telemetry Exclusion
        build_exclusion(ALIASED_ERROR, message, exception, data)
        super(message, exception, data, &block)
      end

      # @param message [String] The message to log. Use default_message if not specified.
      # @param exception [Exception] The exception or the error
      # @param data [Object] Any structured data
      def fatal message = nil, exception = nil, data = nil, &block
        # build Telemetry Exclusion
        build_exclusion(ALIASED_FATAL, message, exception, data)
        super(message, exception, data, &block)
      end

      private

      def build_exclusion _type, _message = nil, _exception = nil, _data = nil
        # TODO: RUBY-1698
        nil
        #   start = caller_locations&.find_index { |stack| stack.to_s.include?(type) }
        #   stack_trace = start ? caller_locations(start + 1, 20) : caller_locations(20, 20)
        #   stack_frame_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_type(
        #       stack_trace[1].path.delete_prefix(Dir.pwd))
        #   message_exception_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_exception_type(
        #       exception ? exception.cs__class.to_s : stack_frame_type.split('/').last)
        #   stack_frame_function = stack_trace[1].label
        #   key = "#{ stack_frame_type }|#{ stack_frame_function }|#{ message }"
        #   if TELEMETRY_EXCEPTIONS[key]
        #     TELEMETRY_EXCEPTIONS.increment(key)
        #     return
        #   end
        #
        #   event_message = create_message(stack_frame_function,
        #                                  stack_frame_type, message_exception_type,
        #                                  data, exception,
        #                                  message)
        #   TELEMETRY_EXCEPTIONS[key] = event_message
        # rescue StandardError => e
        #   debug('Unable to report exception to telemetry', e)
      end

      def create_message stack_frame_function, stack_frame_type, message_exception_type, data, exception, message
        message_for_exception = if exception
                                  exception.cs__respond_to?(:message) ? exception.message : exception
                                else
                                  message
                                end
        module_name = message_exception_type ? message_exception_type.split('::')[0] : nil
        stack_frame = Contrast::Agent::Telemetry::TelemetryException::StackFrame.build(stack_frame_function,
                                                                                       stack_frame_type,
                                                                                       module_name)
        message_exception = Contrast::Agent::Telemetry::TelemetryException::MessageException.build(
            message_exception_type,
            message_for_exception,
            module_name,
            stack_frame)
        tags = if data
                 data
               else
                 exception.cs__is_a?(Hash) ? exception : {}
               end
        message = Contrast::Agent::Telemetry::TelemetryException::Message.build(tags, [message_exception])
        Contrast::Agent::Telemetry::TelemetryException::Event.new(message)
      end
    end
  end
end