# frozen_string_literal: true

require 'singleton'
require 'logger'
require 'digest'

require 'active_support/deprecation'

module Gitlab
  class Experiment
    class Configuration
      include Singleton

      # Prefix all experiment names with a given value. Use `nil` for none.
      @name_prefix = nil

      # The logger is used to log various details of the experiments.
      @logger = Logger.new($stdout)

      # The base class that should be instantiated for basic experiments.
      @base_class = 'Gitlab::Experiment'

      # The caching layer is expected to respond to fetch, like Rails.cache.
      @cache = nil

      # The domain to use on cookies.
      @cookie_domain = :all

      # The default rollout strategy only works for single variant experiments.
      # It's expected that you use a more advanced rollout for multiple variant
      # experiments.
      @default_rollout = Rollout::Base.new

      # Secret seed used in generating context keys.
      @context_key_secret = nil

      # Bit length used by SHA2 in generating context keys - (256, 384 or 512.)
      @context_key_bit_length = 256

      # The default base path that the middleware (or rails engine) will be
      # mounted.
      @mount_at = nil

      # The middleware won't redirect to urls that aren't considered valid.
      # Expected to return a boolean value.
      @redirect_url_validator = ->(_redirect_url) { true }

      # Logic this project uses to determine inclusion in a given experiment.
      # Expected to return a boolean value.
      @inclusion_resolver = ->(_requested_variant) { false }

      # Tracking behavior can be implemented to link an event to an experiment.
      @tracking_behavior = lambda do |event, args|
        Configuration.logger.info("#{self.class.name}[#{name}] #{event}: #{args.merge(signature: signature)}")
      end

      # Called at the end of every experiment run, with the result.
      @publishing_behavior = lambda do |_result|
        track(:assignment)
      end

      class << self
        # TODO: Added deprecation in release 0.6.0
        def context_hash_strategy=(block)
          ActiveSupport::Deprecation.warn('context_hash_strategy has been deprecated, instead configure' \
            ' `context_key_secret` and `context_key_bit_length`.')
          @__context_hash_strategy = block
        end

        # TODO: Added deprecation in release 0.5.0
        def variant_resolver
          ActiveSupport::Deprecation.warn('variant_resolver is deprecated, instead use `inclusion_resolver` with a' \
            ' block that returns a boolean.')
          @inclusion_resolver
        end

        def variant_resolver=(block)
          ActiveSupport::Deprecation.warn('variant_resolver is deprecated, instead use `inclusion_resolver` with a' \
            ' block that returns a boolean.')
          @inclusion_resolver = block
        end

        attr_accessor(
          :name_prefix,
          :logger,
          :base_class,
          :cache,
          :cookie_domain,
          :context_key_secret,
          :context_key_bit_length,
          :mount_at,
          :default_rollout,
          :redirect_url_validator,
          :inclusion_resolver,
          :tracking_behavior,
          :publishing_behavior
        )
      end
    end
  end
end
