# By: Riasat Ullah
# This class represents a conditional routing object. It contains all the rules that must be met
# for a certain routing and what actions to perform as the routing.

from objects.routing_rule import RoutingRule
from utils import constants, times, var_names


class ConditionalRoute(object):

    def __init__(self, routing_id, rule_name, rule_description, routing_rules, rule_application_count,
                 valid_start, valid_end, rule_start_time, rule_end_time, all_days, repeat_on,
                 actions, is_enabled, routing_timezone, reference_id=None, allow_multiple=False):
        self.routing_id = routing_id
        self.rule_name = rule_name
        self.rule_description = rule_description
        self.routing_rules = routing_rules
        self.rule_application_count = rule_application_count
        self.valid_start = valid_start
        self.valid_end = valid_end
        self.rule_start_time = rule_start_time
        self.rule_end_time = rule_end_time
        self.all_days = all_days
        self.repeat_on = repeat_on
        self.actions = actions
        self.is_enabled = is_enabled
        self.routing_timezone = routing_timezone
        self.reference_id = reference_id
        self.allow_multiple = allow_multiple

    @staticmethod
    def create_conditional_route(details, externalize=False):
        '''
        Creates a ConditionalRoute object from a dict of details.
        :param details: (dict) conditional routing retails
        :param externalize: (boolean) when set to True service_id field name in rules is changed to service_ref_id
        :return: ConditionalRoute object
        '''
        rout_id = details[var_names.routing_id]
        rout_rules = ConditionalRoute.create_routing_rules(details[var_names.routing_rules], externalize=externalize)
        return ConditionalRoute(
            rout_id, details[var_names.rule_name], details[var_names.rule_description], rout_rules,
            details[var_names.rule_application_count],
            times.get_date_from_string(details[var_names.valid_start]),
            times.get_date_from_string(details[var_names.valid_end]),
            times.get_time_from_string(details[var_names.rule_start_time]),
            times.get_time_from_string(details[var_names.rule_end_time]),
            details[var_names.all_days], details[var_names.repeat], details[var_names.routing_actions],
            details[var_names.is_enabled], details[var_names.timezone],
            reference_id=details[var_names.reference_id] if var_names.reference_id in details else None,
            allow_multiple=details[var_names.allow_multiple] if var_names.allow_multiple in details else False
        )

    @staticmethod
    def create_routing_rules(rules: list, externalize=False):
        '''
        Creates list of RoutingRule objects given a routing id and list of routing rules info dict.
        :param rules: (dict) of rules info
        :param externalize: (boolean) when set to True service_id field name is changed to service_ref_id
        :return: (list) of RoutingRule objects
        '''
        new_list = []
        for item in rules:
            field_name = item[var_names.field_name]
            if externalize and var_names.rule_type == var_names.service and field_name == var_names.service_id:
                field_name = var_names.service_ref_id

            new_rule = RoutingRule(item[var_names.rule_type], field_name,
                                   item[var_names.comparator], item[var_names.field_value])
            new_list.append(new_rule)
        return new_list

    @staticmethod
    def standardize_routing_rules_info(rules: list):
        '''
        Replace field name values in routing rules info dict to the prescribed values.
        :param rules: (dict) of routing rules info
        :return: (dict) of updated routing rules info
        '''
        rule_type_mappings = {
            var_names.email_from: '.'.join([var_names.source_payload, var_names.email_from]),
            var_names.email_to: '.'.join([var_names.source_payload, var_names.email_to]),
            var_names.email_subject: '.'.join([var_names.source_payload, var_names.email_subject]),
            var_names.service: var_names.service_id,
            var_names.urgency_level: var_names.urgency_level
        }
        for item in rules:
            if item[var_names.rule_type] != var_names.payload:
                item[var_names.field_name] = rule_type_mappings[item[var_names.rule_type]]
        return rules

    def get_re_routing_service_id(self):
        '''
        Get the ID of the service that the alert needs to re-routed to.
        :return: (int) Service ID (or None)
        '''
        if self.actions[var_names.alert_handling] == constants.re_route_service and\
                self.actions[var_names.route_to_service] is not None:
            return self.actions[var_names.route_to_service]
        return None

    def to_dict(self):
        '''
        Gets the dict of the ConditionRoute object.
        :return: dict of ConditionalRoute
        '''
        rules = []
        for item in self.routing_rules:
            rules.append(item.to_dict())
        data = {
            var_names.routing_id: self.routing_id,
            var_names.routing_ref_id: self.reference_id,
            var_names.rule_name: self.rule_name,
            var_names.rule_description: self.rule_description,
            var_names.routing_rules: rules,
            var_names.rule_application_count: self.rule_application_count,
            var_names.valid_start: self.valid_start,
            var_names.valid_end: self.valid_end,
            var_names.rule_start_time: self.rule_start_time,
            var_names.rule_end_time: self.rule_end_time,
            var_names.all_days: self.all_days,
            var_names.repeat: self.repeat_on,
            var_names.routing_actions: self.actions,
            var_names.is_enabled: self.is_enabled,
            var_names.timezone: self.routing_timezone,
            var_names.allow_multiple: self.allow_multiple
        }

        return data
