import logging
import ntpath
import posixpath

from parallels.core import MigrationError
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
from parallels.core.utils.unix_utils import get_safe_filename

logger = logging.getLogger(__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: basestring
		"""
		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: basestring
		"""
		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)
				if not target_db_server.utilities_server.is_windows():
					get_safe_filename(runner, target_dump_filename)
				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)
