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

import hql
from ppms import ppms
from ppms.migration import BasePacket, PacketCategory, MinVersionDependency, MaxVersionDependency, \
    VersionType, PacketDependency, PacketState
from ppms.sql import sanitize_value
try:
    from ppms.interface import StaticConfig, get_module_subclass, get_mapping_instance_from_uuid, ModuleType
except:
    StaticConfig = None


def get_module_subclass_path(mod_id):
    """Get the subclass path of a module"""
    rec = ppms.search_record(405, [mod_id], ['python_module_subclass'])
    if rec is None:
        return ''

    return rec.python_module_subclass.get_value()


class B_MigrateInterfacePositionData(BasePacket):
    """Migrate the position data for the PLANTA Link"""
    done_after_success = True
    run_on_startup = True
    category = PacketCategory.CATEGORY_MANDATORY
    wi_number = 17344

    PACKET_PATH = 'migration.customizing.DB_39_5_8.wi17344_add_position.A_AddInterfacePositionField'

    def get_dependencies(self):
        return (MinVersionDependency(version='39.5.7', version_type=VersionType.CUSTOMIZING),
                MaxVersionDependency(version='39.5.7', version_type=VersionType.CUSTOMIZING),
                PacketDependency(packet_path=self.PACKET_PATH, expected_state=PacketState.INSTALLED))

    def migrate_config(self, config):
        self.log('Migrating configuration "%s"' % config.description)

        if not self.migrate_config_parameters(config=config):
            return False

        if not self.migrate_mapping_parameters(config=config):
            return False

        return True

    def migrate_mapping_parameters(self, config):
        query = """select INTERFACE_MAPPING.UUID from INTERFACE_MAPPING
                   where
                     INTERFACE_MAPPING.CONFIG_ID = '{config_id}'
                     and INTERFACE_MAPPING.UUID in (select MAPPING_ID from MAPPING_PARAMETER)"""
        formatted_query = query.format(config_id=sanitize_value(config.config_id))

        # self.log(formatted_query)

        self.log('Migrating all mappings in this config')

        for mapping_id in itertools.chain(*ppms.db_select(formatted_query)):
            mapping = get_mapping_instance_from_uuid(mapping_id)

            default_parameters = mapping.get_default_parameters()
            for name, parameter in default_parameters.items():
                position = parameter.position

                self.update_mapping_parameter_position(mapping=mapping, name=name, position=position)

        return True

    def update_mapping_parameter_position(self, mapping, name, position):
        query = """update MappingParameters mp
                   set
                     mp.position = {position}
                   where
                     mp.mapping_id = '{mapping_id}'
                     and mp.name = '{name}'"""

        formatted_query = query.format(position=position, name=name, mapping_id=mapping.uuid)
        # self.log(formatted_query)

        return hql.modify(formatted_query) == 1

    def migrate_config_parameters(self, config):
        errors = 0

        self.log('Migrating all module parameters')

        for module, module_type in ((config.source_module, ModuleType.SOURCE),
                                    (config.pool_module, ModuleType.POOL),
                                    (config.target_module, ModuleType.TARGET)):
            if not module:
                continue

            try:
                subclass = get_module_subclass(module)
                if subclass is None:
                    raise ValueError('%s could not be imported' % module)
            except BaseException as err:
                self.log('Could not fetch module subclass for %s (%s)' % (module, get_module_subclass_path(module)))
                self.log(err)

                errors += 1
                continue

            default_parameters = subclass.get_default_parameters(module_type=module_type)
            for name, parameter in default_parameters.items():
                position = parameter.position

                self.update_config_parameter_position(config=config, module=module, name=name,
                                                      position=position)

        if errors > 0:
            self.log('Migrating the module parameters failed')
            return False

        return True

    def update_config_parameter_position(self, config, module, name, position):
        query = """update ConfigurationParameters cp
                   set
                     cp.position = {position}
                   where
                     cp.config_id = '{config_id}'
                     and cp.source = '{module}'
                     and cp.name = '{name}'"""

        formatted_query = query.format(position=position, name=name, module=module, config_id=config.config_id)
        # self.log(formatted_query)

        return hql.modify(formatted_query) == 1

    def fix(self, packet_runner):
        if StaticConfig is None:
            self.fail('Interface files don\'t have the correct version')

        query = "select UUID from INTERFACE_CONFIG"

        failed_migrations = 0
        for config_id in itertools.chain(*ppms.db_select(query)):
            config = StaticConfig(config_id)

            if not self.migrate_config(config=config):
                failed_migrations += 1

        if failed_migrations:
            return self.fail('%d configs could not be migrated!' % failed_migrations)

        self.log('All migrations successful')
        return self.success()
