from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.core.logging import get_logger
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import remove_dict_equal_values, safe_format
from parallels.plesk.source.web import messages
from parallels.plesk.source.web.actions.base.application import ApplicationAction

logger = get_logger(__name__)


class AdjustApplicationDatabaseName(ApplicationAction):
    """Adjust database name if it was renamed during migration due to conflict with existing database
    """

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

        :rtype: str | unicode
        """
        return messages.ACTION_ADJUST_DATABASE_NAME_DESCRIPTION

    def get_failure_message(self, global_context):
        """Get message for situation when action failed

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.ACTION_ADJUST_DATABASE_NAME_FAILURE

    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 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 filter_for_application(self, global_context, application):
        """Check whether we should run this action for application or not. By default True - action should be executed.

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: None
        """
        return len(self._get_database_name_mapping(application)) > 0

    def get_failure_message_for_application(self, global_context, application):
        """Get message for situation when action failed for specific application

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: str | unicode | None
        """
        return safe_format(
            messages.ACTION_ADJUST_DATABASE_NAME_FAILURE_FOR_APP,
            application_type=application.application_model.name,
            path=application.target_path
        )

    def get_failure_severity_for_application(self):
        """Get issue severity for application in case if that action failed

        :rtype: str | unicode
        """
        return Issue.SEVERITY_WARNING

    def run_for_application(self, global_context, application):
        """Run action

        :type global_context: parallels.plesk.source.web.global_context.WebGlobalMigrationContext
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: list[parallels.core.reports.model.issue.Issue] | None
        """
        return application.target_instance.fix_database_name(self._get_database_name_mapping(application))

    @staticmethod
    def _get_database_name_mapping(application):
        """
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: dict[str | unicode, str | unicode]
        """
        database_name_mapping = {}

        for database in application.databases:
            if database.target_name is not None:
                database_name_mapping[database.source_name] = database.target_name

        return remove_dict_equal_values(database_name_mapping)
