from parallels.core.utils.restore_hosting_utils import restore_hosting_settings_lock
from parallels.plesk.source.plesk import messages
import logging
import os

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.windows_utils import cmd_command
from parallels.core.utils.windows_utils import path_join as windows_path_join

logger = logging.getLogger(__name__)


class Transfer(SubscriptionAction):
	def get_description(self):
		return messages.ACTION_TRANSFER_WPB_DESRIPTION

	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_TRANSFER_WPB_FAILURE % 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 len(self._list_wpb_sites(global_context, subscription)) > 0

	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 run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		with restore_hosting_settings_lock:
			self._run_plain(global_context, subscription)

	def _run_plain(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		logger.debug(messages.DEBUG_COLLECTING_INFO_ABOUT_WPB_SITES)
		wpb_sites = self._list_wpb_sites(global_context, subscription)

		with subscription.panel_target_server.runner() as runner_target:
			source_server = subscription.web_source_server
			is_windows = source_server.is_windows()
			with source_server.runner() as runner_source:
				for domain_name, sitebuilder_site_id in wpb_sites:
					base_filename = u'wpb_%s.zip' % domain_name
					source_filename = source_server.get_session_file_path(base_filename)
					local_filename = global_context.migrator_server.get_session_file_path(base_filename)
					target_filename = subscription.panel_target_server.get_session_file_path(base_filename)

					logger.debug(messages.LOG_BACKUP_WPB_SITE_ON_SOURCE)
					if is_windows:
						runner_source.sh(
							ur'cmd.exe /c "{php} -dauto_prepend_file="" {bru} backup --target=site --uuid={site_id} --file={filename}"',
							dict(
								php=ur"%s\admin\bin\php" % (source_server.plesk_dir,),
								bru=u"%s\\sb\\utils\\bru.php" % (source_server.plesk_dir,),
								source_plesk_dir=source_server.plesk_dir,
								site_id=sitebuilder_site_id, filename=source_filename
							)
						)
					else:
						runner_source.sh(
							u'{plesk_dir}/bin/sw-engine-pleskrun /usr/local/sb/utils/bru.php backup '
							u'--target=site --uuid={site_id} --file={filename}',
							dict(
								plesk_dir=source_server.plesk_dir,
								site_id=sitebuilder_site_id,
								filename=source_filename
							)
						)

					logger.debug(messages.LOG_DOWNLOAD_BACKUP_FILE_TO_LOCAL_SERVER)
					runner_source.get_file(source_filename, local_filename)
					runner_source.remove_file(source_filename)  # remove immediately as all WPB sites could take a lot of disk space
					logger.debug(messages.LOG_UPLOAD_BACKUP_FILE_TO_TARGET)
					runner_target.upload_file(local_filename, target_filename)
					os.remove(local_filename)

					logger.debug(messages.LOG_RESTORE_WPB_SITE_ON_TARGET)
					target_plesk_dir = subscription.panel_target_server.plesk_dir
					if subscription.panel_target_server.is_windows():
						runner_target.sh(
							cmd_command('{php} -dauto_prepend_file="" {bru} restore --target=site --uuid={site_id} --file={filename} --use_defaults'),
							dict(
								php=ur"%s\admin\bin\php" % (target_plesk_dir,),
								bru=u"%s\\sb\\utils\\bru.php" % (target_plesk_dir,),
								source_plesk_dir=target_plesk_dir,
								site_id=sitebuilder_site_id, filename=target_filename
							)
						)
						runner_target.remove_file(target_filename)
						plesk_bin_domain = windows_path_join(target_plesk_dir, "bin/domain")
					else:
						runner_target.sh(
							u'{plesk_dir}/bin/sw-engine-pleskrun /usr/local/sb/utils/bru.php restore '
							u'--target=site --uuid={site_id} --file={filename} --use_defaults',
							dict(
								plesk_dir=target_plesk_dir,
								site_id=sitebuilder_site_id,
								filename=target_filename
							)
						)
						runner_target.remove_file(target_filename)
						plesk_bin_domain = "%s/bin/domain" % target_plesk_dir

					logger.debug(messages.LOG_RESTORE_RELATION_PLESK_DOMAIN_TO_WPB_SITE)
					runner_target.sh(
						u'{plesk_bin_domain} --update {domain_name} -publish-sb-site true -sb-site-id {site_id}',
						dict(plesk_bin_domain=plesk_bin_domain, domain_name=domain_name, site_id=sitebuilder_site_id)
					)

	@staticmethod
	def _list_wpb_sites(global_context, subscription):
		""" Returns the following structure:
		wpb_sites = [
			(subscription_name, site_id),
			(subdomain1_name, site_id), (subdomain2_name, site_id), ...,
			(addondomain1_name, site_id), (addondomain2_name, site_id), ...
		]
		where site_id is an id of WPB site for subscription/addon domain/subdomain
		the function guarantees that site_id is not None
		"""

		safe = global_context.safe
		wpb_sites = []

		with safe.try_subscription(
			subscription.name,
			messages.FAILED_TO_READ_INFORMATION_ABOUT_WPB_SITES, is_critical=False
		):
			for site in subscription.converted_dump.iter_domains():
				if site.sitebuilder_site_id is not None:
					wpb_sites.append((site.name, site.sitebuilder_site_id))

		return wpb_sites
