import logging

from parallels.ppa_sn import messages
from parallels.core.utils.rsync_pool import RsyncPool
from parallels.core.utils import plesk_utils
from parallels.ppa.utils.poa_utils import get_host_id_by_ip
from parallels.core.utils import windows_utils
from parallels.ppa_sn.common import HostingType
from parallels.ppa.connections.target_server import PPATargetServer
from . import MultipleSubscriptionOperation


logger = logging.getLogger(__name__)

class CopyWindowsWebContentOperation(MultipleSubscriptionOperation):
	logger = logging.getLogger(__name__)

	def __init__(self, move_context):
		self.move_context = move_context

	def run(self, try_subscription, subscriptions):
		logger.info(messages.COPY_WEB_CONTENT_OF_WINDOWS_SUBSCRIPTIONS)
		for subscription in subscriptions:
			with try_subscription(subscription.name):
				subscription_info = self.move_context.ppa_data.get_subscription_info(
					subscription.name
				)
				self._copy_windows_web_content_single_subscription(
					subscription, subscription_info
				)

	def _copy_windows_web_content_single_subscription(self, subscription, subscription_info):
		source_ppa_host_id = get_host_id_by_ip(self.move_context.conn.poa_api(), subscription.source_ip)
		target_ppa_host_id = get_host_id_by_ip(self.move_context.conn.poa_api(), subscription.target_ip)

		if subscription_info.hosting_type == HostingType.Virtual:
			source_server = PPATargetServer(
				self.move_context.conn, source_ppa_host_id, 
				subscription.source_ip
			)
			target_server = PPATargetServer(
				self.move_context.conn, target_ppa_host_id, 
				subscription.target_ip
			)
			logger.info(
				messages.LOG_COPY_CONTENT_OF_SUBSCRIPTION,
				subscription.name, source_server.description(), target_server.description()
			)
			with source_server.runner() as runner:
				self._configure_firewall_source(
					runner, source_server.description()
				)
			with target_server.runner() as runner:
				self._configure_firewall_target(
					runner, target_server.description()
				)
			
			with target_server.runner() as runner:
				vhosts_dir_target = plesk_utils.get_windows_vhosts_dir(runner)
			with source_server.runner() as runner:
				vhosts_dir_source = plesk_utils.get_windows_vhosts_dir(runner)

			rsync_pool = RsyncPool(self.move_context.session_dir.get_file_path('rsync_path_'))
			rsync = rsync_pool.get(source_server, target_server, vhosts_dir_source)
			rsync.sync(
				source_path="vhosts/%s" % (subscription.name.encode('idna'),),
				target_path=windows_utils.convert_path_to_cygwin(vhosts_dir_target)
			)

			with source_server.runner() as runner:
				self._unconfigure_firewall_source(
					runner, source_server.description()
				)
			with target_server.runner() as runner:
				self._unconfigure_firewall_target(
					runner, target_server.description()
				)

	def _configure_firewall_source(self, runner, node_description):
		try:
			logger.debug(messages.SET_UP_FIREWALL_ON_SOURCE_IIS, node_description)
			runner.sh(
				'netsh advfirewall firewall '
				'add rule name=PPA_MOVE_SUBSCRIPTIONS_INCOMING protocol=TCP '
				'dir=in profile=any localport=873 localip=any action=allow'
			)
		except Exception as e:
			logger.error(messages.FAILED_TO_SET_UP_FIREWALL_ON_SOURCE, node_description, e)
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)

	def _configure_firewall_target(self, runner, node_description):
		try:
			logger.debug(messages.SET_UP_FIREWALL_ON_TARGET_IIS, node_description)
			runner.sh(
				'netsh advfirewall firewall '
				'add rule name=PPA_MOVE_SUBSCRIPTIONS_OUTGOING protocol=TCP '
				'dir=out profile=any remoteport=873 localip=any action=allow'
			)
		except Exception as e:
			logger.error(messages.FAILED_TO_SET_UP_FIREWALL_ON_TARGET, node_description, e)
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)

	def _unconfigure_firewall_source(self, runner, node_description):
		try:
			logger.debug(messages.REMOVE_FIREWALL_RULES_ON_SOURCE_IIS, node_description)
			runner.sh('netsh advfirewall firewall delete rule name=PPA_MOVE_SUBSCRIPTIONS_INCOMING')
		except Exception as e:
			logger.error(messages.FAILED_TO_REMOVE_FIREWALL_RULE_ON_SOURCE, node_description, e)
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)

	def _unconfigure_firewall_target(self, runner, node_description):
		try:
			logger.debug(messages.REMOVE_FIREWALL_RULES_ON_TARGET_IIS, node_description)
			runner.sh('netsh advfirewall firewall delete rule name=PPA_MOVE_SUBSCRIPTIONS_OUTGOING')
		except Exception as e:
			logger.error(messages.FAILED_TO_REMOVE_FIREWALL_RULE_TARGET, node_description, e)
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
