from parallels.core.logging import get_logger
from parallels.core import messages
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import format_multiline_list
from parallels.core.utils.database_server_type import DatabaseServerType
from parallels.core.utils.database_utils import is_mysql_innodb_strict_mode
from collections import defaultdict

logger = get_logger(__name__)


class CheckInnodbStrictMode(CommonAction):
    """Pre-migration check if source mysql/mariadb has innodb_strict_mode set to OFF so it can fail
    the database transfer

    Briefly:
    In InnoDB 5.6 (both in MySQL 5.6 and MariaDB 10.0/10.1) innodb_strict_mode=0 by default,
    that's why the CREATE statement simply issued a warning and assumed COMPACT format instead.
    In InnoDB 5.7 (both in MySQL 5.7 and MariaDB 10.2) innodb_strict_mode=1 by default,
    so both of them fail to create a table with the wrong ROW_FORMAT.
    Thus, dumps, created in old versions will fail to restore in new ones.

    Refer to https://jira.mariadb.org/browse/MDEV-11305 for more information.
    """

    def get_description(self):
        """Get short description of action as string

        :rtype: str
        """
        return messages.ACTION_CHECK_INNODB_STRICT_MODE_DESCRIPTION

    def get_failure_message(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        return messages.ACTION_CHECK_INNODB_STRICT_MODE_FAILURE

    def is_critical(self):
        """If action is critical or not

        If action is critical and it failed for a subscription, migration tool
        won't run the next operations for the subscription.

        :rtype: bool
        """
        return False

    def get_logging_properties(self):
        """Get how action should be logged to migration tools end-user

        :rtype: parallels.core.actions.utils.logging_properties.LoggingProperties
        """
        return LoggingProperties(compound=False)

    def run(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        subscriptions = []
        subscriptions_by_servers = defaultdict(lambda: list())

        for db_info in global_context.migrator.databases_to_copy:
            subscriptions_by_servers[(db_info.source_database_server, db_info.target_database_server)].append(db_info.subscription_name)

        for (source_database_server, target_database_server), subscriptions_list in subscriptions_by_servers.items():
            if source_database_server.type() == DatabaseServerType.MYSQL:
                if not is_mysql_innodb_strict_mode(source_database_server):
                    if is_mysql_innodb_strict_mode(target_database_server):
                        subscriptions.extend(subscriptions_list)

        if len(subscriptions) == 0:
            return

        subscriptions = list(set(subscriptions))

        global_context.pre_check_report.add_issue(
            'mysql_innodb_strict_mode', Issue.SEVERITY_ERROR,
            messages.MYSQL_INNODB_STRICT_MODE_PROBLEM.format(
                subscriptions=format_multiline_list(subscriptions)
            )
        )
