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

# require 'contrast/components/logger'
require 'contrast/utils/duck_utils'

module Contrast
  module Utils
    # This is the RoutesSent class, which determines whether observed routes can be sent to TeamServer.
    # Routes that have not been seen (according to the cache) can be sent, as well as any route that
    # # has been seen but not within the time limit.
    class RoutesSent
      # include Contrast::Components::Logger::InstanceMethods
      ROUTES_LIMIT = 500
      TIME_LIMIT_IN_SECONDS = 60

      attr_accessor :cache

      def initialize
        @cache = {}
      end

      # Determine whether the provided route can be sent to TeamServer.
      #
      # @param route [Contrast::Agent::Reporting::ObservedRoute] the route
      # @return [boolean]
      def sendable? route
        return false unless route
        return false unless route.signature && !route.signature.blank?
        return false unless route.url && !route.url.blank?

        route_hash = route.hash_id

        # If hash doesn't exist in @cache...
        #   - Add hash to @cache (with Time.now)
        #   - Clear oldest entries (if more than ROUTES_LIMIT)
        #   - Return *true*
        unless cache.key?(route_hash)
          cache[route_hash] = Time.now
          remove_oldest_entries!
          return true
        end

        # If hash exists in @cache...
        #   - Return *true* if more than a minute since time recorded for hash
        #   - Return *false* if not than a minute since time recorded for hash
        return false unless Time.now.to_i - cache.fetch(route_hash, 0).to_i > TIME_LIMIT_IN_SECONDS

        cache[route_hash] = Time.now
        true
      end

      private

      def remove_oldest_entries!
        return if cache.size < ROUTES_LIMIT

        route_hashes = cache.sort_by { |_, v| -v.tv_nsec }.
            to_h.keys.slice(0, ROUTES_LIMIT)
        @cache = cache.slice(*route_hashes)
      end
    end
  end
end