import logging
import re
import xml.etree.ElementTree as et

from parallels.common.actions.base.subscription_action import SubscriptionAction
from parallels.common.utils import subscription_filter
from parallels.plesks_migrator.actions.content.web.utils import list_security_files
from parallels.common.utils import windows_utils

logger = logging.getLogger(__name__)


class FixSecurityFiles(SubscriptionAction):
	def get_description(self):
		return "Fix files with permissions settings for Windows"

	def get_failure_message(self, global_context, subscription):
		return "Failed to restore file permissions 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):
		"""
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		:type subscription: parallels.common.migrated_subscription.MigratedSubscription
		"""
		return subscription_filter.windows_with_virtual_hosting(
			subscription
		)

	def run(self, global_context, subscription):
		"""
		:type subscription: parallels.common.migrated_subscription.MigratedSubscription
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		vhost_name = subscription.name_idn
		source_server = subscription.web_source_server
		target_server = subscription.web_target_server

		logger.debug(u"Get IIS dedicated application pool user on target node")
		iis_app_user = global_context.import_api.get_dedicated_app_pool_user(subscription)
		logger.debug(u"IIS dedicated application pool user on target node: '%s'", iis_app_user)

		with target_server.runner() as runner_target:
			vhost_dir = u"%s/%s" % (target_server.vhosts_dir, vhost_name)
			source_plesk_version = source_server.plesk_version

			for i, security_file in enumerate(list_security_files(subscription, include_subdomains=True)):
				local_security_file = global_context.migrator_server.get_session_file_path(
					'windows-security-%s-%s.xml' % (vhost_name, i)
				)
				fixed_security_file = global_context.migrator_server.get_session_file_path(
					'windows-security-%s-%i.fixed.xml' % (vhost_name, i)
				)

				logger.debug(
					u"Get '%s' file to change dedicated IIS application user that was changed, put it to '%s'",
					security_file, local_security_file
				)
				if source_plesk_version >= (11, 5):
					security_file_on_source = windows_utils.path_join(
						target_server.vhosts_dir, vhost_name, '.plesk', security_file
					)
				else:
					security_file_on_source = windows_utils.path_join(
						target_server.vhosts_dir, vhost_name, security_file
					)

				with source_server.runner() as runner_source:
					if windows_utils.file_exists(runner_source, security_file_on_source):
						runner_source.get_file(
							security_file_on_source,
							local_security_file
						)

						logger.debug(u"Fix '%s' file, write fixed file to '%s'", security_file, fixed_security_file)
						with open(local_security_file, 'r') as security_fh:
							tree = et.ElementTree(file=security_fh)
							to_remove = []
							for entry in tree.getroot().findall('Entry'):
								if (
									iis_app_user is not None and 
									re.match('^IWPD_\d+\(.*\)$', entry.attrib['Account'])
								):
									entry.attrib['Account'] = iis_app_user

								# Fix issue when migrating from Windows 2003
								# with IIS 6 for domains that have ASP.NET
								# disabled on Plesk <= 9.5.3. For such domains
								# if you won't remove NoAccess permission from
								# .Security file, sites will response with 500
								# error because of insufficient permissions to
								# access httpdocs directory. For PPA 11.5/11.6
								# we fix the same issue by switching on and off
								# dedicated IIS pools - see comments at
								# _copy_content function.
								if (
									target_server.plesk_version >= (12, 0) and 
									source_server.plesk_version <= (9, 5, 2) and
									re.match('^(IWAM|IWPC)_', entry.attrib['Account']) and
									entry.attrib['AccessMask'] == 'NoAccess'
								):
										to_remove.append(entry)

							for entry in to_remove:
								tree.getroot().remove(entry)

						tree.write(fixed_security_file, encoding='UTF-8', xml_declaration=True)

						logger.debug(u"Upload fixed '%s' file to target node", security_file)
						with open(fixed_security_file, 'r') as fixed_security_fh:
							if not security_file.startswith('subdomains\\'):
								# put file to a new location
								target_path = windows_utils.path_join(
									vhost_dir, '.plesk', security_file
								)
							else:
								# put file to an old location - it will be
								# merged further with repair utility
								target_path = windows_utils.path_join(
									vhost_dir, security_file
								)
							runner_target.upload_file_content(target_path, fixed_security_fh.read())
					else:
						logger.debug("Skip processing '%s' file as it does not exist on source" % (security_file,))
