from parallels.core import messages
from parallels.core.actions.base.subscription_backup_action import SubscriptionBackupAction
from parallels.core.actions.utils.logging_properties \
	import LoggingProperties
from parallels.core.checking import Problem
from parallels.core.utils.plesk_utils import get_database_subscription, get_database_user_subscription


class CheckDatabaseConflicts(SubscriptionBackupAction):
	def get_description(self):
		return messages.ACTION_CHECK_DATABASE_CONFLICTS_DESCRIPTION

	def get_failure_message(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return messages.ACTION_CHECK_DATABASE_CONFLICTS_FAILURE % subscription.name

	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):
		return LoggingProperties(info_log=False)

	def _run_subscription_backup(
		self, global_context, subscription, subscription_backup
	):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		:type subscription_backup: parallels.core.plesk_backup.data_model.Subscription
		"""
		for backup_db in subscription_backup.all_databases:
			target_db_server = subscription.db_target_servers.get(backup_db.dbtype)

			if target_db_server is None:
				continue

			has_issues = self.has_database_issues(
				global_context, subscription, subscription_backup, backup_db, target_db_server
			)
			if has_issues:
				subscription_backup.remove_database(backup_db)

	@classmethod
	def has_database_issues(
		cls, global_context, subscription, subscription_backup, backup_db, target_db_server, add_report_issues=True
	):
		has_issues = cls._check_database_owner(
			global_context, subscription, backup_db, target_db_server, add_report_issues
		)
		has_issues |= cls._check_database_user_owner(
			global_context, subscription, subscription_backup, backup_db, target_db_server, add_report_issues
		)
		return has_issues

	@staticmethod
	def _check_database_user_owner(
		global_context, subscription, subscription_backup, backup_db, target_db_server, add_report_issues
	):
		"""Check if there are any ownership conflicts for database users of specified database

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		:type subscription_backup: parallels.core.plesk_backup.data_model.Subscription
		:type backup_db: parallels.core.plesk_backup.data_model.Database
		:type target_db_server: parallels.core.connections.database_server.TargetDatabaseServer
		:type add_report_issues: bool
		:rtype: bool
		"""
		has_issues = False

		for db_user in subscription_backup.get_database_users(backup_db.name, backup_db.dbtype):
			target_user_subscription = get_database_user_subscription(
				subscription.panel_target_server, db_user.name, backup_db.dbtype, target_db_server.host()
			)

			if target_user_subscription is None:
				continue
			if target_user_subscription == subscription.name:
				continue

			if add_report_issues:
				subscription.add_report_issue(
					global_context.pre_check_report,
					Problem(
						'database-user-with-such-name-already-exists', Problem.ERROR,
						messages.DATABASE_USER_EXISTS_ISSUE.format(
							db_name=backup_db.name, db_type=backup_db.dbtype, db_user=db_user.name,
							target_owner_subscription=target_user_subscription
						)
					),
					messages.DATABASE_USER_EXISTS_SOLUTION
				)
			has_issues = True

		return has_issues

	@staticmethod
	def _check_database_owner(global_context, subscription, backup_db, target_db_server, add_report_issues):
		"""Check if there are any ownership conflicts for database

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		:type backup_db: parallels.core.plesk_backup.data_model.Database
		:type target_db_server: parallels.core.connections.database_server.TargetDatabaseServer
		:type add_report_issues: bool
		:rtype: bool
		"""
		target_database_subscription = get_database_subscription(
			subscription.panel_target_server,
			backup_db.name, backup_db.dbtype,
			target_db_server.host()
		)

		if target_database_subscription is None:
			return False
		if target_database_subscription == subscription.name:
			return False

		if add_report_issues:
			subscription.add_report_issue(
				global_context.pre_check_report,
				Problem(
					'database-with-such-name-already-exists', Problem.ERROR,
					messages.DATABASE_EXISTS_ISSUE.format(
						db_name=backup_db.name, db_type=backup_db.dbtype,
						target_owner_subscription=target_database_subscription
					)
				),
				messages.DATABASE_EXISTS_SOLUTION
			)
		return True
