# -*- coding: utf-8 -*-
import itertools
import os

from planta_logging.logging import *
from ppms import ppms
from ppms.constants import *
from ppms.migration import ChangeDTPPacket, MinVersionDependency, MaxVersionDependency, PacketCategory, BasePacket, PacketState
from ppms.period import aggregate_periods_from_start_to_end
from ppms.ressource import get_all_ressources_of_department


class UpdatePeriodAggregationQuery(ChangeDTPPacket):
    """Update the period aggregation query

    The 5 factors were not correctly aggregated to the parent across multiple
    levels. This migration packet fixes the queries and aggregates the period in the system.
    """
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 15815

    new_packet_path = 'migration.server.S_39_5_24.WI21117_fix_period_aggregation.FixPeriodAggregationQuery'

    NEW_FILENAMES = {DBMS_ORACLE: ('summarize_oracle_new.sql', 'aggregation_oracle_new.sql'),
                     DBMS_MSSQL: ('summarize_mssql_new.sql', 'aggregation_mssql_new.sql')}

    OLD_FILENAMES = {DBMS_ORACLE: ('summarize_oracle_old.sql', 'aggregation_oracle_old.sql'),
                     DBMS_MSSQL: ('summarize_mssql_old.sql', 'aggregation_mssql_old.sql')}

    def get_dependencies(self):
        return (MinVersionDependency(version='39.5.6'),
                MaxVersionDependency(version='39.5.6'))

    def newer_packet_already_run(self):
        new_packet = BasePacket.from_packet_path(self.new_packet_path)
        if new_packet and new_packet.state == PacketState.INSTALLED:
            return True
        return False

    def fix(self, runner):
        dbms = ppms.db_get_dbms_name()

        # 000682 is might be already updated by a server packet so skip it if the other packet is already installed
        if self.newer_packet_already_run():
            queries = ['000691', '000682']
        else:
            queries = ['000691']

        old_filenames = self.OLD_FILENAMES.get(dbms, None)
        new_filenames = self.NEW_FILENAMES.get(dbms, None)

        if old_filenames is None or new_filenames is None:
            return self.fail('Unknown dbms!!')

        for old_filename, new_filename, query in zip(old_filenames, new_filenames, queries):
            old_file_path = os.path.join(os.path.dirname(__file__), old_filename)
            new_file_path = os.path.join(os.path.dirname(__file__), new_filename)

            self.log('Updating period query from file: "%s"' % new_file_path)
            with open(new_file_path, 'r') as f:
                new_statement = f.read()

            with open(old_file_path, 'r') as f:
                old_statement = f.read()

            record = self.get_record(343, [dbms, query], ['source_text_clob'])
            if not self.change_value(record, 'source_text_clob', old_statement, new_statement):
                return self.fail('Changing the update query failed')

        self.fix_period_aggregation()

        return self.success()

    def fix_period_aggregation(self):
        all_resources = list(itertools.chain(*ppms.db_select("SELECT DI001218 FROM DT467")))
        resources_to_aggregate = all_resources[:]

        # Only call the period aggregation for the lowest level children
        # as those will aggregate to the top anyway
        for resource_id in all_resources:
            child_resources = get_all_ressources_of_department(resource_id, skip_departments=False)

            for child_resource in child_resources:
                if child_resource in resources_to_aggregate:
                    resources_to_aggregate.remove(resource_id)
                    break

        apology = 'Now running the period aggregation for all resources in the system. This could take a while!'
        self.log(apology)

        log_write(LogLevel.INFO, ComponentID.PY_PLANTA_DE, "UpdatePeriodAggregationQuery", -1, 'operative', '',
                  apology)

        for index, resource_id in enumerate(resources_to_aggregate):
            status_update = 'Working on resource %d of %d' % (index + 1, len(resources_to_aggregate))
            log_write(LogLevel.INFO, ComponentID.PY_PLANTA_DE, "UpdatePeriodAggregationQuery", -1, 'operative', '',
                      status_update)

            aggregate_periods_from_start_to_end(resource_id)
