# frozen_string_literal: true

module Gitlab
  class Experiment
    module Nestable
      extend ActiveSupport::Concern

      included do
        set_callback :run, :around, :manage_nested_stack
      end

      def nest_experiment(other)
        raise NestingError, "unable to nest the #{other.name} experiment within the #{name} experiment"
      end

      private

      def manage_nested_stack
        Stack.push(self)
        yield
      ensure
        Stack.pop
      end

      class Stack
        include Singleton

        @stack = []

        class << self
          delegate :pop, :length, :size, :[], to: :@stack

          def push(instance)
            @stack.last&.nest_experiment(instance)
            @stack.push(instance)
          end
        end
      end
    end
  end
end
