# coding: utf-8

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from saas.library.python.common_functions import round_up

MINIMUM_REPLICA_SWITCH_TIME = 150


class AlemateRecipe(object):
    __slots__ = ('id', 'name', 'desc', 'context', 'labels')

    @staticmethod
    def dict_to_list(d):
        return [{'key': k, 'value': str(v)} for k, v in d.items()]

    @staticmethod
    def list_to_dict(l):
        return {e['key']: e['value'] for e in l}

    def __init__(self, id, name, desc, context=None, labels=None):
        self.id = id
        self.name = name
        self.desc = desc
        self.labels = labels if labels else []
        if isinstance(context, list):
            self.context = context
        elif isinstance(context, dict):
            self.context = self.dict_to_list(context)
        else:
            self.context = []

    def __repr__(self):
        return 'AlemateRecipe({}, {}, desc={}, context={})'.format(
            self.id, self.name, self.desc, self.context
        )

    def dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'desc': self.desc,
            'context': self.context,
            'labels': []
        }

    @property
    def context_dict(self):
        return {c['key']: c['value'] for c in self.context}

    @context_dict.setter
    def context_dict(self, value):
        self.context = [{'key': k, 'value': str(v)} for k, v in value.items()]

    @property
    def operating_degrade_level(self):
        return self.context_dict.get('stop_degrade_level', 0)

    @operating_degrade_level.setter
    def operating_degrade_level(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError('operating_degrade_level must be number')
        if value <= 0 or value > 1:
            raise ValueError('operating_degrade_level must be in [0, 1]')

        current_context = self.context
        current_context['operating_degrade_level'] = value
        self.context = current_context

    @property
    def stop_degrade_level(self):
        return self.context_dict.get('stop_degrade_level')

    @stop_degrade_level.setter
    def stop_degrade_level(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError('operating_degrade_level must be number')
        if value <= 0 or value > 1:
            raise ValueError('stop_degrade_level must be in [0, 1]')

        current_context = self.context
        current_context['stop_degrade_level'] = value
        self.context = current_context


def get_replica_share(replicas_count, n=1):
    return round_up(n / replicas_count, 3)


def get_sharded_activate_recipe(replicas_count, geo='sas,man,vla', wait_time=900,
                                manual_confirm=True, activate_first_location_without_confirm=True):
    recipe = AlemateRecipe(
        id='activate_sharded', name='activate_saas_sharded.yaml', desc='Activate sharded', context=[], labels=[]
    )
    recipe.context_dict = {
        'operating_degrade_level': get_replica_share(replicas_count, 2),
        'stop_degrade_level': get_replica_share(replicas_count, 1),
        'max_degrade_speed': round_up(1 / (MINIMUM_REPLICA_SWITCH_TIME * replicas_count), 5),
        'geo': geo,
        'manual_confirm': str(manual_confirm),
        'activate_first_location_without_confirm': str(activate_first_location_without_confirm),
        'wait_time': wait_time
    }
    return recipe


def get_prepare_recipe(replicas_count):
    recipe = AlemateRecipe(
        id='prepare', name='_prepare_service_configuration.yaml', desc='Prepare', context=[], labels=[]
    )
    recipe.context_dict = {
        'operating_degrade_level': 1,
        'stop_degrade_level': get_replica_share(replicas_count, 1),
        'instance_selector': 'sharded_instance_selector',
        'prepare_shards': True
    }
    return recipe
