import logging
import os

import parallels.common.migrator
from contextlib import closing
from contextlib import contextmanager

from parallels.common import MigrationError
from parallels.common.migrator import trace

from parallels.common.migrator import Migrator as CommonMigrator
from parallels.common.windows_rsync import windows_rsync_preconfigured_source
from parallels.common.content.mail.imapsync import CopyMailImapsync
from parallels.common.connections_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.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

	@staticmethod
	@contextmanager
	def _windows_rsync(source_server, target_server, source_ip=None):
		with windows_rsync_preconfigured_source(
			target_server, source_ip
		) as rsync:
			yield rsync

	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
			)

	# To dump mysql database need run mysqldump
	def _get_path_to_mysqldump_on_source_server(self, source_plesk_dir):
		return "mysqldump"

	def _get_path_to_mysql_on_source_server(self, runner_source):
		return "mysql"

	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(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()
