#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import logging


from utils.input_output import get_yamls_in_path
from utils.databases.superclasses.database_superclasses import DbYamlInteractor
from utils.db_handling.maintenance.migrators import \
    (MigrateV00toV01,
     MigrateV01toV02,
     MigrateV02toV03,
     MigrateV03toV04,
     MigrateV04toV05,
     MigrateV05toV06
    )
from utils.vars import REQUIRED_DB_SCHEMA_VERSION

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())

MIGRATION_OBJ_DICT = {
    0: MigrateV00toV01,
    1: MigrateV01toV02,
    2: MigrateV02toV03,
    3: MigrateV03toV04,
    4: MigrateV04toV05,
    5: MigrateV05toV06
}


def migrate_dbs_style_if_necessary(db_base_dir):
    yamls = get_yamls_in_path(db_base_dir)
    if not yamls:
        raise ValueError(f'No yaml files were found in provided database directory \n\t{db_base_dir}')
    yaml_objs = [DbYamlInteractor(yaml) for yaml in yamls]
    is_any_db_outdated = any([yaml_o.is_db_schema_version_outdated() for yaml_o in yaml_objs])
    if is_any_db_outdated:
        logger.warning(
            "Databases will be migrated:\n" +
            "\n".join([y.get_yaml() for y in yaml_objs])
        )
        _ = migrate_db_style(yaml_objs)


def migrate_db_style(yaml_objs_to_migrate):
    lowest_db_version = get_lowest_schema_version(yaml_objs_to_migrate)
    for old_version in range(lowest_db_version, REQUIRED_DB_SCHEMA_VERSION):
        processed_yaml_objs = migrate_yaml_objs_to_next_version(yaml_objs_to_migrate, old_version)
        yaml_objs_to_migrate = processed_yaml_objs
    return yaml_objs_to_migrate


def get_lowest_schema_version(yaml_objs):
    lowest_version = None
    for yaml_o in yaml_objs:
        v = yaml_o.get_db_schema_version()
        if lowest_version is None:
            lowest_version = v
        elif v < lowest_version:
            lowest_version = v
        else:
            pass
    return lowest_version


def migrate_yaml_objs_to_next_version(yaml_objs, from_version):
    try:
        migrator_class = MIGRATION_OBJ_DICT[from_version]
    except KeyError:
        raise KeyError(f'No Database Migrator defined for version: {from_version}')
    migrator = migrator_class(yaml_objs)
    migrated_yaml_objs = migrator.migrate()
    for y in migrated_yaml_objs:
        assert_yaml_obj_has_target_version(y, expected_version=from_version + 1)
    return migrated_yaml_objs


def assert_yaml_obj_has_target_version(yaml_obj, expected_version):
    db_schema_version = yaml_obj.get_db_schema_version()
    if not db_schema_version == expected_version:
        raise ValueError(
            f"Expected database version: {expected_version}\n" +
            f"Database version is: {db_schema_version}\n" +
            f"Database: {yaml_obj.get_yaml()}"
        )
