from parallels.core import messages
import logging

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core import checking
from parallels.core.actions.utils.multithreading_properties import MultithreadingProperties
from parallels.core.utils import plesk_api_utils
from parallels.core.import_api.import_api import UserAlreadyExistsException, LoginIsInvalidException

logger = logging.getLogger(__name__)


class RestoreSysuserLogins(SubscriptionAction):
	"""Restore system user login on target panel.

	The default workflow for system user logins is the following:
	1. Subscription is created with *some* system user login. It may be the same as on source system,
	or it may be auto generated by migrator or target panel.
	2. During subscription creation, migrator with target panel take care of new login uniqueness and correctness.
	So even if login from source system already exists on target system within another subscription,
	subscription is still created. Moreover, no error messages are emitted.
	3. Then, in this action we try to change login to the original one from source system.
	If update fails, we detect situations when:
	- such login already exists
	- login is not valid for target system
	and report them to subscription's report that is displayed to migrator's user.
	4. But anyway, even if there was an issue when restoring system user login, migration will go further.
	If restored login is not the same as on source system, it will be updated in backup at ChangeSysuserLogin action.
	"""
	def get_description(self):
		return messages.RESTORE_LOGINS_SYSTEM_USERS_1

	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.FAILED_RESTORE_LOGIN_SYSTEM_USER_FOR % (subscription.name)

	def filter_subscription(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return True

	def get_multithreading_properties(self):
		return MultithreadingProperties(can_use_threads=True)

	def run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		sysuser_name = subscription.raw_dump.phosting_sysuser_name
		if sysuser_name is None:
			logger.debug(messages.THERE_IS_NO_SYSTEM_USER_LOGIN)
			return

		for char in global_context.target_panel_obj.sysuser_name_disallowed_chars:
			# replace all disallowed characters to underline
			sysuser_name = sysuser_name.replace(char, '_')

		target_sysuser_name = plesk_api_utils.get_subscription_sysuser_name(
			subscription.panel_target_server.plesk_api(), subscription.name
		)

		if target_sysuser_name is None:
			# subscription has no system user on target
			# now we simply ignore that case, but probably it would be
			# better to handle such situation better to avoid issues
			# on the next steps of migration
			logger.debug(messages.THERE_IS_NO_SYSTEM_USER_LOGIN_1)
			return

		if target_sysuser_name != sysuser_name:
			try:
				global_context.import_api.change_sysuser_login(
					subscription.name, sysuser_name
				)
			except UserAlreadyExistsException:
				subscription.add_report_issue(
					global_context.pre_check_report,
					checking.Problem(
						'unable_to_restore_original_sysuser_name_already_exists', checking.Problem.WARNING,
						messages.UNABLE_RESTORE_ORIGINAL_USERNAME_FOR_SYSTEM % (subscription.name, sysuser_name)
					),
					messages.NOTIFY_SUBSCRIPTION_OWNER_NEW_FTP_USERNAME % target_sysuser_name
				)
			except LoginIsInvalidException:
				subscription.add_report_issue(
					global_context.pre_check_report,
					checking.Problem(
						'unable_to_restore_original_sysuser_name_does_not_conform_to_target_rules',
						checking.Problem.WARNING,
						messages.UNABLE_RESTORE_ORIGINAL_USERNAME_S_FOR % (sysuser_name, subscription.name)
					),
					messages.NOTIFY_SUBSCRIPTION_OWNER_NEW_FTP_USERNAME_1 % target_sysuser_name
				)
