module Vanity
  module Experiment
    # One of several alternatives in an A/B test (see AbTest#alternatives).
    class Alternative
      def initialize(experiment, id, value) # , participants, converted, conversions)
        @experiment = experiment
        @id = id
        @name = I18n.t('vanity.option_number', char: (@id + 65).chr.upcase)
        @value = value
      end

      # Alternative id, only unique for this experiment.
      attr_reader :id

      # Alternative name (option A, option B, etc).
      attr_reader :name

      # Alternative value.
      attr_reader :value

      # Experiment this alternative belongs to.
      attr_reader :experiment

      # Number of participants who viewed this alternative.
      def participants
        load_counts unless defined?(@participants)
        @participants
      end

      # Number of participants who converted on this alternative (a
      # participant is counted only once).
      def converted
        load_counts unless defined?(@converted)
        @converted
      end

      # Number of conversions for this alternative (same participant may be
      # counted more than once).
      def conversions
        load_counts unless defined?(@conversions)
        @conversions
      end

      # Z-score for this alternative, related to 2nd-best performing
      # alternative. Populated by AbTest#score if #score_method is :z_score.
      attr_accessor :z_score

      # Probability alternative is best. Populated by AbTest#score.
      attr_accessor :probability

      # Difference from least performing alternative. Populated by
      # AbTest#score.
      attr_accessor :difference

      # Conversion rate calculated as converted/participants
      def conversion_rate
        @conversion_rate ||= (participants > 0 ? converted.to_f / participants : 0.0)
      end

      # The measure we use to order (sort) alternatives and decide which one
      # is better (by calculating z-score). Defaults to conversion rate.
      def measure
        conversion_rate
      end

      def <=>(other)
        measure <=> other.measure
      end

      def ==(other)
        other && id == other.id && experiment == other.experiment
      end

      def to_s
        name
      end

      def inspect
        "#{name}: #{value} #{converted}/#{participants}"
      end

      def load_counts
        if @experiment.playground.collecting?
          @participants, @converted, @conversions = @experiment.playground.connection.ab_counts(@experiment.id, id).values_at(:participants, :converted, :conversions)
        else
          @participants = @converted = @conversions = 0
        end
      end

      def default?
        @experiment.default == self
      end
    end
  end
end
