# By: Riasat Ullah
# This file contains methods for handling incident related analysis and metrics.

from analytics import analytics_tools
from analytics.instance_analyzer import InstanceAnalyzer
from dbqueries import db_analytics, db_policies, db_services, db_teams
from utils import var_names


class IncidentAnalytics(object):

    def __init__(self, conn, timestamp, organization_id, start_date, end_date, timezone, urgency_levels=None,
                 policy_refs=None, service_refs=None, team_refs=None, tags=None, user_id=None):
        self.conn = conn
        self.organization_id = organization_id
        self.start_date = start_date
        self.end_date = end_date
        self.timezone = timezone
        self.urgency_levels = urgency_levels
        self.policy_refs = policy_refs
        self.service_refs = service_refs
        self.team_refs = team_refs
        self.tags = tags
        self.user_id = user_id

        self.policy_ids = None
        self.service_ids = None

        if policy_refs is not None:
            self.policy_ids = db_policies.list_policy_ids_from_ref_ids(conn, timestamp, organization_id, policy_refs)

        if service_refs is not None:
            self.service_ids = db_services.list_service_ids_from_ref_ids(conn, timestamp, organization_id, service_refs)

        if team_refs is not None:
            all_team_components = db_teams.get_organization_team_components_for_analytics(
                self.conn, self.start_date, self.end_date, self.organization_id
            )
            tm_policies = []
            tm_services = []
            for tm_ref in team_refs:
                if tm_ref in all_team_components:
                    tm_policies += [x[0] for x in all_team_components[tm_ref][var_names.policies]]
                    tm_services += [x[0] for x in all_team_components[tm_ref][var_names.services]]

            if len(tm_policies) > 0:
                if self.policy_ids is None:
                    self.policy_ids = tm_policies
                elif self.policy_ids is not None and isinstance(self.policy_ids, list) and len(self.policy_ids) > 0:
                    self.policy_ids = list(set(self.policy_ids).intersection(set(tm_policies)))

            if len(tm_services) > 0:
                if self.service_ids is None:
                    self.service_ids = tm_services
                elif self.service_ids is not None and isinstance(self.service_ids, list) and len(self.service_ids) > 0:
                    self.service_ids = list(set(self.service_ids).intersection(set(tm_services)))

        self.last_two_periods = analytics_tools.get_previous_periods(start_date, end_date, 2)
        self.instances = db_analytics.get_instances_for_analysis(conn, self.last_two_periods[0][0], self.end_date,
                                                                 organization_id,
                                                                 urgencies=self.urgency_levels,
                                                                 esc_pol_ids=self.policy_ids,
                                                                 service_ids=self.service_ids,
                                                                 tags=self.tags,
                                                                 user_id=self.user_id)

    def get_metrics(self):
        '''
        Get the metrics for incident analytics.
        :return: (dict) of metrics
        '''
        # first calculate the metrics for the current period
        analyzer = InstanceAnalyzer(self.timezone, self.instances)
        analyzer.filter_by_period(self.start_date, self.end_date)
        analyzer.create_acknowledgement_time_columns()
        analyzer.create_escalation_count_column()
        analyzer.create_resolved_by_column(with_display_name=True)

        daily_labels_n_inst_count = analytics_tools.get_period_labels_and_values(
            self.start_date, self.end_date, analyzer.get_daily_instance_count())
        daily_labels_n_mean_ack = analytics_tools.get_period_labels_and_values(
            self.start_date, self.end_date, analyzer.get_daily_mean_acknowledgement_time(), round_dp=2)
        daily_labels_n_mean_res = analytics_tools.get_period_labels_and_values(
            self.start_date, self.end_date, analyzer.get_daily_mean_resolution_time(), round_dp=2)

        period_inst_count = analyzer.get_aggregate_instance_count()
        period_mean_ack_time = analytics_tools.convert_nan_to_number(analyzer.get_average_acknowledgement_time())
        period_mean_res_time = analytics_tools.convert_nan_to_number(analyzer.get_average_response_effort())
        period_esc_count = analyzer.get_aggregate_count_of_escalated_instances()

        # next go through the previous period's metrics to calculate the percentage change
        old_analyzer = InstanceAnalyzer(self.timezone, self.instances)
        old_analyzer.filter_by_period(self.last_two_periods[0][0], self.last_two_periods[0][1])
        old_analyzer.create_acknowledgement_time_columns()
        old_analyzer.create_escalation_count_column()

        old_inst_count = old_analyzer.get_aggregate_instance_count()
        old_mean_ack_time = old_analyzer.get_average_acknowledgement_time()
        old_mean_res_time = old_analyzer.get_average_response_effort()
        old_esc_count = old_analyzer.get_aggregate_count_of_escalated_instances()

        inst_count_perc_delta = analytics_tools.get_percentage_change(period_inst_count, old_inst_count)
        mean_ack_time_perc_delta = analytics_tools.get_percentage_change(period_mean_ack_time, old_mean_ack_time)
        mean_res_time_perc_delta = analytics_tools.get_percentage_change(period_mean_res_time, old_mean_res_time)
        esc_count_perc_delta = analytics_tools.get_percentage_change(period_esc_count, old_esc_count)

        return {
            var_names.period: daily_labels_n_inst_count[0],
            var_names.incident_count: daily_labels_n_inst_count[1],
            var_names.acknowledgement_time: daily_labels_n_mean_ack[1],
            var_names.resolution_time: daily_labels_n_mean_res[1],
            var_names.total_incident_count: (period_inst_count, inst_count_perc_delta),
            var_names.mean_acknowledgement_time: (period_mean_ack_time, mean_ack_time_perc_delta),
            var_names.mean_resolution_time: (period_mean_res_time, mean_res_time_perc_delta),
            var_names.escalation_count: (period_esc_count, esc_count_perc_delta),
            var_names.incidents: analyzer.get_all_major_instances()
        }
