import logging
import os
from contextlib import closing

import parallels.common.migrator
from parallels.common import MigrationError
from parallels.common.migrator import trace
from parallels.common.migrator import Migrator as CommonMigrator
from parallels.common.content.mail.imapsync import CopyMailImapsync
from parallels.common.migrator_config import MailContent
from parallels.plesk_api.operator.subscription import Ips
from parallels.common.utils.migrator_utils import get_package_extras_file_path
from .backup_agent import BackupAgent
import connections
from parallels.helm_migrator.workflow import FromHelm4Workflow


class Migrator(CommonMigrator):
	logger = logging.getLogger(__name__)

	def _load_connections_configuration(self):
		return connections.HelmMigratorConnections(
			self.config, self._get_target_panel(), self._get_migrator_server())

	def _create_workflow(self):
		return FromHelm4Workflow()

	def _create_global_context(self):
		context = super(Migrator, self)._create_global_context()
		context.source_has_dns_forwarding = False
		return context

	@trace('fetch-source', u'fetch info from source servers')
	def _fetch_source(self, options, overwrite):
		self.logger.info(u"Fetch Helm servers information.")

		helm_conn_settings = self.conn.helm.conn_settings
		backup_filename = self.session_files.get_path_to_raw_plesk_backup('helm')

		if not overwrite and os.path.exists(backup_filename):
			self.logger.info(u"Data files for Helm already exist, skip loading")
		else:		
			with self.conn.helm.runner() as runner_source:
				runner_source.mkdir(helm_conn_settings.migration_tool_dir)
				for script_name in ["HelmMigrationTool.exe", "WHA.Helm.Core.dll"]:
					remote_script_path = os.path.join(helm_conn_settings.migration_tool_dir, script_name)
					runner_source.upload_file(
						get_package_extras_file_path(parallels.helm_migrator, script_name),
						remote_script_path
					)

			try:
				with self.conn.helm.runner() as helm_runner:
					helm_runner.sh(ur'{migration_tool_path} --gac-install', dict(
						migration_tool_path=os.path.join(
							helm_conn_settings.migration_tool_dir,
							helm_conn_settings.migration_tool_name
						)
					))
			except Exception as e:
				self.logger.debug(u'Exception:', exc_info=e)
				self.logger.error(u"Can't install in GAC 'WHA.Helm.Core.dll'; migration was stopped. Check the connection to the control server and make sure that the version of Helm installed there is supported by the migrator.")
				raise MigrationError(u"Can't install in GAC 'WHA.Helm.Core.dll'; migration was stopped. Check the connection to the control server and make sure that the version of Helm installed there is supported by the migrator.")

			with closing(self.conn.helm.db()) as cursor:
				with self.conn.helm.runner() as runner:
					backup_agent = BackupAgent(cursor, runner, helm_conn_settings)
					backup_agent.make_backup()
					backup_agent.save_backup(backup_filename)

	@trace('check-infrastructure', u'check infrastructure')
	def check_infrastructure(self, options, show_skip_message=True):
		pass  # silently skip for Helm migrator, we do not have any infrastructure checks yet

	def _get_rsync(self, source_server, target_server, source_ip=None):
		return self.global_context.rsync_pool.get(
			source=None,
			target=target_server,
			source_ip=source_ip
		)

	def _get_subscription_ip_by_guids(self, sub_name, guids, error_message=None, optional=False):
		with closing(self.conn.helm.db()) as cursor:
			cursor.execute(u"""SELECT Server.IpAddress FROM Service
				JOIN Server on Server.ServerId = Service.ServerId
				JOIN OnlineService_Service on OnlineService_Service.ServiceId = Service.ServiceId
				JOIN OnlineService on OnlineService.OnlineServiceId = OnlineService_Service.OnlineServiceId
				WHERE 
					ProviderGuid IN (%s)
					AND OnlineService.Name = '%s'"""
				% (guids, sub_name))

			if cursor.rowcount() == 0:
				if optional:
					return None
				else:
					raise MigrationError(error_message)

			return cursor.fetchone()[0]

	def _get_subscription_content_ip(self, sub):
		return self._get_subscription_ip_by_guids(
			sub.name,
			"'62541890-8A7F-47B3-A099-ED7569347718', 'EF9200DF-2A17-4956-94D5-3B9911E19217'",
			u"Can't get server node ip with web content for domain '%s'; skip web content for this domain. Resolve inconsistency in the source panel database." % sub.name
		)

	def _copy_mail_content_single_subscription(self, migrator_server, subscription, issues):
		source_server = subscription.mail_source_server
		copy_content_mode = source_server.mail_settings.mode
		if copy_content_mode == MailContent.NONE:
			self.logger.info(
				u"Mail content migration for subscription '%s' is disabled by user",
				subscription.name
			)
		else:
			return CopyMailImapsync(
				copy_content_mode==MailContent.FULL
			).copy_mail(self.global_context, migrator_server, subscription, issues)

	def _get_mailserver_ip_by_subscription_name(self, source_settings, subscription_name):
		ipv4 = self._get_subscription_ip_by_guids(subscription_name,
				"'E2EA7F3E-C089-4E81-9097-55F13621DE4D'", optional=True
			)
		return Ips(ipv4, None)

	def _get_source_node(self, node_id):
		assert node_id == 'helm'
		return self.conn.helm.get_main_source_server()
