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

require 'contrast/components/interface'
require 'contrast/agent/worker_thread'

module Contrast
  module Api
    module Communication
      # Top level gateway to messaging with speedracer
      class MessagingQueue < Contrast::Agent::WorkerThread
        include Contrast::Components::Interface
        access_component :agent, :analysis, :logging, :settings

        attr_reader :queue, :speedracer

        def initialize
          @queue = Queue.new
          @speedracer = Contrast::Api::Communication::Speedracer.new
          super
        end

        # Use this to bypass the messaging queue and leave response processing to the caller
        def send_event_immediately event
          if AGENT.disabled?
            logger.warn('Attempted to send event immediately with Agent disabled', caller: caller, event: event)
            return
          end
          speedracer.return_response(event)
        end

        # Use this to add a message to the queue and process the response internally
        def send_event_eventually event
          if AGENT.disabled?
            logger.warn('Attempted to queue event with Agent disabled', caller: caller, event: event)
            return
          end
          logger.debug('Enqueued event for sending', event_type: event.cs__class)
          queue << event if event
        end

        def start_thread!
          speedracer.ensure_startup!
          return if running?

          @queue ||= Queue.new
          @_thread = Contrast::Agent::Thread.new do
            loop do
              event = queue.pop

              begin
                logger.debug('Dequeued event for sending', event_type: event.cs__class)
                speedracer.process_internally(event)
              rescue StandardError => e
                logger.error('Could not send message to service from messaging queue thread.', e)
              end
            end
          end
          logger.debug('Started background sending thread.')
        end

        def stop!
          return unless running?

          super
          @queue&.clear
          @queue&.close
          @queue = nil
        end
      end
    end
  end
end