import ntpath
import posixpath

from parallels.core import MigrationError
from parallels.core.logging import get_logger
from parallels.core.utils.database_server_type import DatabaseServerType
from parallels.plesk.source.custom import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.database_utils import restore_db_from_dump_linux
from parallels.core.utils.database_utils import restore_db_from_dump_windows
from parallels.core.utils.database_utils import set_mssql_dumps_dir_permissions

logger = get_logger(__name__)


class RestoreDBDumps(SubscriptionAction):
    """Restore databases from dump files specified in hosting description file"""

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

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

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

        :type global_context: parallels.common.global_context.GlobalMigrationContext
        :type subscription: parallels.common.migrated_subscription.MigratedSubscription
        :rtype: str | unicode
        """
        return messages.ACTION_RESTORE_DATABASES_FROM_DUMPS_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 filter_subscription(self, global_context, subscription):
        """Check if we should run this action on given subscription or not

        :type global_context: parallels.common.global_context.GlobalMigrationContext
        :type subscription: parallels.custom_panel_migrator.migrated_subscription.CustomPanelMigratedSubscription
        """
        return subscription.hosting_description is not None

    def run(self, global_context, subscription):
        """Run action on given subscription

        :type global_context: parallels.custom_panel_migrator.global_context.CustomPanelGlobalMigrationContext
        :type subscription: parallels.custom_panel_migrator.migrated_subscription.CustomPanelMigratedSubscription
        """
        databases_with_dumps = [db for db in subscription.hosting_description.iter_databases() if db.dump is not None]
        for db in databases_with_dumps:
            logger.info(messages.LOG_RESTORE_DB_DUMP.format(
                db_type=db.db_type, db_name=db.name, dump=db.dump
            ))
            target_db_server = subscription.db_target_servers.get(db.db_type)
            if target_db_server is None:
                raise MigrationError(
                    messages.DB_WILL_NOT_BE_RESTORED_NO_DB_SERVER.format(
                        db_type=db.db_type, db_name=db.name,
                    )
                )

            target_dumps_dir = target_db_server.panel_server.get_session_file_path('db-dumps')
            target_dump_filename = (ntpath if target_db_server.utilities_server.is_windows() else posixpath).join(
                target_dumps_dir, 'db_backup_%s_%s' % (subscription.name, db.name)
            )
            with target_db_server.runner() as runner:
                runner.mkdir(target_dumps_dir)
                runner.upload_file(db.dump, target_dump_filename)
                if target_db_server.utilities_server.is_windows():
                    if db.db_type == DatabaseServerType.MSSQL:
                        set_mssql_dumps_dir_permissions(target_db_server, target_dumps_dir)
                    restore_db_from_dump_windows(target_db_server, db.name, target_dump_filename)
                else:
                    restore_db_from_dump_linux(target_db_server, db.name, target_dump_filename)
                runner.remove_file(target_dump_filename)
