# frozen_string_literal: true

module Members
  class InviteEmailExperiment < ApplicationExperiment
    exclude { context.actor.created_by.blank? }
    exclude { context.actor.created_by.avatar_url.nil? }

    INVITE_TYPE = 'initial_email'

    def resolve_variant_name
      RoundRobin.new(feature_flag_name, %i[avatar permission_info control]).execute
    end
  end

  class RoundRobin
    CacheError = Class.new(StandardError)

    COUNTER_EXPIRE_TIME = 86400 # one day

    def initialize(key, variants)
      @key = key
      @variants = variants
    end

    def execute
      increment_counter
      resolve_variant_name
    end

    # When the counter would expire
    #
    # @api private Used internally by SRE and debugging purpose
    # @return [Integer] Number in seconds until expiration or false if never
    def counter_expires_in
      Gitlab::Redis::SharedState.with do |redis|
        redis.ttl(key)
      end
    end

    # Return the actual counter value
    #
    # @return [Integer] value
    def counter_value
      Gitlab::Redis::SharedState.with do |redis|
        (redis.get(key) || 0).to_i
      end
    end

    # Reset the counter
    #
    # @private Used internally by SRE and debugging purpose
    # @return [Boolean] whether reset was a success
    def reset!
      redis_cmd do |redis|
        redis.del(key)
      end
    end

    private

    attr_reader :key, :variants

    # Increase the counter
    #
    # @return [Boolean] whether operation was a success
    def increment_counter
      redis_cmd do |redis|
        redis.incr(key)
        redis.expire(key, COUNTER_EXPIRE_TIME)
      end
    end

    def resolve_variant_name
      remainder = counter_value % variants.size

      variants[remainder]
    end

    def redis_cmd
      Gitlab::Redis::SharedState.with { |redis| yield(redis) }

      true
    rescue CacheError => e
      Gitlab::AppLogger.warn("GitLab: An unexpected error occurred in writing to Redis: #{e}")

      false
    end
  end
end
