import random


def epsilon_greedy(variant_vals, eps=0.1):
    """Epsilon-greedy algorithm implementation 
    on Variant model values.

    Parameters
    ----------
    variant_vals : list
        A list of dictionary mappings of Variant field values for
        a given Campaign object. Required ``Variant`` fields are
        ``code`` ``impressions`` ``conversions`` ``conversion_rate`` 
        ``html_template``. For example: ::

            Campaign.objects.get(code='xxx').values(
                'code',
                'impressions',
                'conversions',
                'conversion_rate',
                'html_template'
            )    

    eps : float
        Exploration parameter. Values between 0.0 and 1.0.
        Defaults to 0.1

    Returns
    -------
    selected_variant : dict
        The selected dictionary mapping of Variant fields
        from ``variant_vals`` list, as chosen by the epsilon_greedy
        algorithm

    """

    if random.random() < eps: 
        # If random number < eps, exploration is chosen over 
        # exploitation
        selected_variant = random.sample(list(variant_vals), 1)[0]

    else:
        # If random number >= eps, exploitation is chosen over
        # exploration
        best_conversion_rate = 0.0
        selected_variant = None
        for var in variant_vals:
            if var['conversion_rate'] > best_conversion_rate:
                best_conversion_rate = var['conversion_rate']
                selected_variant = var
            if var['conversion_rate'] == best_conversion_rate:
                # Break tie - randomly choose between current and best
                selected_variant = random.sample([var, selected_variant], 1)[0]

    return selected_variant