import logging
import posixpath
from contextlib import closing

from parallels.common.actions.base.subscription_action import SubscriptionAction
from parallels.hsphere_migrator.remote_script import HsphereRunner
from parallels.common import MigrationError
from parallels.common.utils.migrator_utils import copy_directory_content_unix
from parallels.common.utils import ssh_utils
from parallels.common.utils import subscription_filter
from parallels.common.utils import unix_utils


logger = logging.getLogger(__name__)


class CopyUnixWebContent(SubscriptionAction):
	def get_description(self):
		return "Copy web files from Unix servers"

	def get_failure_message(self, global_context, subscription):
		return "Failed to copy web files for subscription '%s'" % 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 filter_subscription(self, global_context, subscription):
		return subscription_filter.unix_with_virtual_hosting(
			subscription
		)

	def run(self, global_context, subscription):
		logger.debug(u"Get httpdocs of '%s' subscription on target node" % subscription.name)

		source_server = subscription.web_source_server
		target_server = subscription.web_target_server

		source_ip = source_server.ip()

		logger.debug(u"Get httpdocs of %s subscription on H-Sphere" % subscription.name)
		with closing(global_context.conn.hsphere.db()) as cursor:
			cursor.execute(u""" SELECT dir FROM domains
				JOIN parent_child ON domains.id = parent_child.child_id
				JOIN unix_user ON unix_user.id = parent_child.parent_id
				WHERE
					domains.name = '%s'
			""" % subscription.name)
			source_path = cursor.fetchone()[0]

			cursor.execute(u""" SELECT l_server_ips.ip FROM domains
				JOIN parent_child ON parent_child.parent_id = domains.id
				JOIN apache_vhost ON apache_vhost.id = parent_child.child_id
				JOIN l_server_ips ON l_server_ips.l_server_id = apache_vhost.host_id
				WHERE
					parent_child.child_type = 9
					AND domains.name = '%s'
			""" % subscription.name)
			# 9 - Hosting
			ip_row = cursor.fetchone()
			if ip_row is None:
				raise MigrationError(
					u"Can not determine IP address of '%s' subscription. "
					u"Most probably reason: subscription has not hosting." % subscription.name
				)
			l_server_ip = ip_row[0]
			logger.debug(u"Detected subscription's server ip - '%s'" % l_server_ip)
			if source_server.ip() != l_server_ip:
				logger.debug(u"Change source ip address from '%s' to '%s'" % (source_server.ip(), l_server_ip))
				source_ip = l_server_ip

		logger.debug(u"Copy content for main domain for '%s' subscription." % subscription.name)
		sysuser_name = subscription.converted_backup.get_phosting_sysuser_name()
		if sysuser_name is None:
			logger.debug(u"'%s' subscription does not have sys user, so skip content migration." % subscription.name)
			return

		logger.debug(u"'%s' subscription's sys user: '%s'." % (subscription.name, sysuser_name))

		target_path = posixpath.join(
			target_server.vhosts_dir, subscription.name_idn
		)
		logger.debug(u"Source path: %s", source_path)
		logger.debug(u"Target path: %s", subscription)
		with source_server.runner() as runner_source:
			with target_server.runner() as runner_target:
				hsphere_runner = HsphereRunner(runner_source, source_ip)

				# It would be better to take the same logic as here:
				# parallels.common.actions.content.web.copy_unix_content_base.CopyUnixWebContentBase
				# but now we simply check H-Sphere Debian -> PPA CentOS case
				if unix_utils.is_debian(hsphere_runner):

					user_mapping = {'www-data': 'apache'}
					group_mapping = {'www-data': 'apache'}
				else:
					user_mapping = {}
					group_mapping = {}

				with ssh_utils.public_key_ssh_access_runner(
					runner_target, hsphere_runner
				) as key_pathname:
					try:
						copy_directory_content_unix(
							source_ip,
							source_server.user(),
							hsphere_runner,
							runner_target,
							source_path,
							target_path,
							key_pathname,
							exclude=['logs'],
							user_mapping=user_mapping,
							group_mapping=group_mapping,
						)
					except Exception as e:
						logger.debug(u"Exception: ", exc_info=e)
						raise MigrationError((
							u"Rsync failed to copy files from the source (%s) to the target server (%s): %s\n"
							u"""1. This could happen because of a network connection issue.
							Retry copying the files with the help of the "copy-content" command.\n"""
							u"2. Check whether rsync is installed and configured on the source server."
						) % (source_ip, target_server.description(), str(e)))

		with target_server.runner() as runner_target:
			vhost_dir = posixpath.join(target_server.vhosts_dir, subscription.name_idn)
			runner_target.sh(
				u'/usr/bin/find %s -type d '
				u'-user %s -not -group root -not -group psaserv '
				u'-exec chown :psacln {} \; -exec chmod o+rx {} \;' % (
					vhost_dir, sysuser_name
				)
			)
			runner_target.sh(
				u'/usr/bin/find %s -type f '
				u'-user %s -not -group root -not -group psaserv '
				u'-exec chown :psacln {} \; -exec chmod o+r {} \;' % (
					vhost_dir, sysuser_name
				)
			)
