# By: Riasat Ullah

# This class represents a task that already exists.
# If a task needs to be created then it has to be done
# using the create_task method from db_tasks.

from objects.assignee import Assignee
from utils import var_names


class Task(object):

    def __init__(self, taskid, details, assignees, labels=None):
        self.taskid = taskid
        self.details = details
        self.assignees = assignees
        self.labels = labels

    @staticmethod
    def create_task(details):
        '''
        Creates a Task object from its details.
        :param details: (dict) of task details
        :return: Task object
        '''
        task_id = details.pop(var_names.task_id)
        labels = details.pop(var_names.labels) if var_names.labels in details else None
        assignees = details.pop(var_names.assignees) if var_names.assignees in details else None
        if assignees is not None:
            assignees = [Assignee.create_assignee(x) for x in assignees]
        return Task(task_id, details, assignees, labels)

    @staticmethod
    def create_assignees(service_policy_id, assignee_policy_ids):
        '''
        Creates assignee objects and puts them in a list given assignees info.
        :param service_policy_id: (int) policy id associated to the service of the task.
        :param assignee_policy_ids: (list) of policy ids
        :return: (list) of Assignee objects
        '''
        assignee_objects = []
        all_policy_ids = []
        if service_policy_id is not None:
            all_policy_ids.append(service_policy_id)
        if assignee_policy_ids is not None:
            all_policy_ids += assignee_policy_ids

        for policy_id in all_policy_ids:
            assignee_objects.append(Assignee(policy_id, policy_id, assignee_level=1))
        return assignee_objects

    @staticmethod
    def standardize_labels(labels):
        '''
        Get the standardized dict of labels.
        :param labels: (list) of dict -> [{'field_name': name, 'field_value': val}, ...]
        :return: (dict) -> {'tags': [tag 1, tag 2, ..], 'dedup_key': key}
        '''
        new_labels = dict()
        if labels is not None:
            for item in labels:
                if item[var_names.field_name] == var_names.tags:
                    if var_names.tags not in new_labels:
                        new_labels[var_names.tags] = []
                    new_labels[var_names.tags].append(item[var_names.field_value])
                else:
                    new_labels[item[var_names.field_name]] = item[var_names.field_value]
        if len(new_labels) > 0:
            return new_labels
        else:
            return None

    def get_level_assignees(self, check_level):
        '''
        Get all the assignees at a given level
        :param check_level: (int) the task level
        :return: (list) of Assignee objects
        '''
        level_assignees = []
        for assignee in self.assignees:
            if assignee.assignee_level == check_level:
                level_assignees.append(assignee)
        return level_assignees

    def urgency_level(self):
        '''
        Gets the urgency level of the task.
        :return: urgency level
        '''
        return int(self.details[var_names.urgency_level])

    def get_assignee_policy_ids(self):
        '''
        Get the policy ids of all the assignees.
        :return: (list) of policy ids
        '''
        policy_ids = []
        for assignee in self.assignees:
            policy_ids.append(assignee.for_policy_id)
        return policy_ids

    def service_id(self):
        '''
        Gets the service id of the task.
        :return: (int) service ID; None if task is not associated to a service
        '''
        if var_names.service_id in self.details:
            return self.details[var_names.service_id]
        return None

    def service_name(self):
        '''
        Gets the name of the service the task was created on.
        :return: (str) name of the service
        '''
        if var_names.service_name in self.details:
            return self.details[var_names.service_name]
        return None

    def title(self):
        '''
        Gets the title of the task.
        :return: (str) task title
        '''
        if var_names.task_title in self.details:
            return self.details[var_names.task_title]
        return None

    def text_msg(self):
        '''
        Gets the text message content of the task.
        :return: (str) details of the task
        '''
        if var_names.text_msg in self.details:
            return self.details[var_names.text_msg]
        return None

    def remove_policies(self, policy_ids: list):
        '''
        Removes a list of policies from a task's assignments and adjusts the levels accordingly.
        :param policy_ids: (int or list) of policy ids to remove
        '''
        if isinstance(policy_ids, int):
            policy_ids = [policy_ids]
        new_assignees = []
        new_levels = set()
        for assignee in self.assignees:
            if assignee.for_policy_id not in policy_ids:
                new_assignees.append(assignee)
                new_levels.add(assignee.assignee_level)
        self.assignees = new_assignees
        if len(self.assignees) > 0:
            new_levels = list(new_levels)
            new_levels.sort()
            new_levels_map = dict()
            for i in range(0, len(new_levels)):
                new_levels_map[new_levels[i]] = i + 1

            for assignee in self.assignees:
                old_level = assignee.assignee_level
                assignee.assignee_level = new_levels_map[old_level]

    def get_tags(self):
        '''
        Get the tags associated to a task; if there are any.
        :return: (list) of tags
        '''
        if self.labels is not None and var_names.tags in self.labels:
            return self.labels[var_names.tags]
        return []

    def get_snapshots(self):
        '''
        Get the snapshots associated with the task.
        :return: (list) of image urls
        '''
        if var_names.snapshots in self.details:
            return self.details[var_names.snapshots]
        return None

    def to_dict(self):
        '''
        Gets the serialized json of the Task object.
        :return: json of Task object
        '''
        data = {var_names.task_id: self.taskid, var_names.labels: self.labels}
        data = {**data, **self.details}
        assignee_list = []
        if self.assignees is not None:
            for assignee in self.assignees:
                assignee_list.append(assignee.to_dict())
        data = {**data, **{var_names.assignees: assignee_list}}
        return data
