import logging
import os
from xml.etree import ElementTree

from parallels.common.utils.plesk_utils import get_migrator_root_path
from parallels.common.utils import windows_utils
import parallels.common
from parallels.utils.xml import elem

logger = logging.getLogger(__name__)


class CopyMailPsaMailBackup(object):
	def __init__(self, get_mail_provider_by_subscription_name, get_rsync):
		self._get_mail_provider_by_subscription_name = get_mail_provider_by_subscription_name
		self._get_rsync = get_rsync

	def copy_mail(self, global_context, migrator_server, subscription, issues):
		for domain in subscription.converted_mail_backup.iter_domains():
			if domain.mailsystem is None:
				logger.debug(u"Skip copying mail content for the domain %s which has no mail hosting", domain.name)
				continue

			self._copy_domain_mail(migrator_server, subscription, domain)

	def _copy_domain_mail(self, migrator_server, subscription, domain):
		for mailbox in domain.iter_mailboxes():
			self._copy_mailbox(migrator_server, subscription, domain, mailbox)

	def _copy_mailbox(self, migrator_server, subscription, domain, mailbox):
		self._backup_mailbox_content(
			migrator_server, subscription, domain, mailbox
		)
		self._restore_mailbox_content(
			migrator_server, subscription, domain, mailbox
		)

	def _backup_mailbox_content(
		self, migrator_server, subscription, domain, mailbox
	):
		source_server = subscription.mail_source_server

		backup_tool = source_server.get_session_file_path(
			'PSAMailbackup.exe'
		)
		accounts_file = source_server.get_session_file_path(
			'Accounts.xml'
		)
		dump_file = source_server.get_session_file_path(
			'Dump.zip'
		)
		logpath = source_server.get_session_file_path(
			'MailBackupLogs'
		)

		if self._get_mail_provider_by_subscription_name:
			provider = self._get_mail_provider_by_subscription_name(
				subscription.name
			)
			provider_str = ' --provider %s' % (provider,)
		else:
			provider_str = ''

		with source_server.runner() as runner:
			if not windows_utils.file_exists(runner, backup_tool):
				self._upload_files(
					source_server, self._psa_mail_common_files, 'PSAMailcommon'
				)

				remote_dir = source_server.get_session_file_path(r"locale\en-US")
				runner.mkdir(remote_dir)					
				self._upload_files(
					source_server, self._psa_locale_files, 'PSAMailcommon'
				)

				self._upload_files(
					source_server, self._psa_mail_backup_files, 'PSAMailbackup'
				)

			runner.remove_file(dump_file)
			runner.remove_file(accounts_file)
			runner.upload_file_content(
				accounts_file, self._generate_accounts_file(domain, mailbox)
			)

			runner.sh(
				ur'{backup_tool} --dump-file="{dump}" '
				ur'--logpath="{logpath}" '
				ur'--account-file="{accounts_file}"' + provider_str,
				dict(
					backup_tool=backup_tool,
					dump=dump_file,
					accounts_file=accounts_file,
					logpath=logpath,
				)
			)

	def _restore_mailbox_content(self, migrator_server, subscription, domain, mailbox):
		target_server = subscription.mail_target_server
		source_server = subscription.mail_source_server

		restore_tool = target_server.get_session_file_path(
			"PSAMailrestore.exe"
		)
		accounts_file = target_server.get_session_file_path(
			'Accounts.xml'
		)
		dump_file = target_server.get_session_file_path(
			'Dump.zip'
		)
		logpath = target_server.get_session_file_path(
			'MailRestoreLogs'
		)

		with target_server.runner() as runner:
			if not windows_utils.file_exists(runner, restore_tool):
				self._upload_files(
					target_server, self._psa_mail_common_files, 
					'PSAMailcommon'
				)

				remote_dir = target_server.get_session_file_path(r"locale\en-US")
				runner.mkdir(remote_dir)					
				self._upload_files(
					target_server, self._psa_locale_files, 'PSAMailcommon'
				)

				self._upload_files(
					target_server, self._psa_mail_restore_files, 
					'PSAMailrestore'
				)

			runner.remove_file(dump_file)
			runner.remove_file(accounts_file)
			runner.upload_file_content(
				accounts_file, self._generate_accounts_file(domain, mailbox)
			)

		rsync = self._get_rsync(source_server, target_server, subscription.source_mail_ip)
		rsync.sync(
			'migrator/Dump.zip',
			windows_utils.convert_path_to_cygwin(dump_file)
		)

		with target_server.runner() as runner:
			runner.sh(
				ur'{restore_tool} --dump-file="{dump}" '
				ur'--logpath="{logpath}" '
				ur'--account-file="{accounts_file}"',
				dict(
					restore_tool=restore_tool,
					dump=dump_file,
					accounts_file=accounts_file,
					logpath=logpath
				)
			)

	@staticmethod
	def _generate_accounts_file(domain, mailbox):
		xml_node = elem('Accounts', [
			elem(
				'Domain',
				[elem('Account', attrs={'Name': mailbox.name, 'Pwd': mailbox.password})],
				{'Name': domain.name.encode('idna'), 'StoredName': domain.name.encode('idna')}
			),
		])
		return ElementTree.tostring(xml_node, 'utf-8', 'xml')

	@staticmethod
	def _upload_files(server, files, local_dir):
		with server.runner() as runner:
			for file_name in files:
				local_path = os.path.join(
					get_migrator_root_path(parallels.common), 
					'extras', local_dir, file_name
				)
				remote_path = server.get_session_file_path(file_name)
				runner.upload_file(local_path, remote_path)

	_psa_mail_common_files = [
		"CommunigateProMailsrvprovider.dll", "ForeignMigratorCoreCommon.dll", "ForeignMigratorCoreInterfaces.dll",
		"ForeignMigratorEngineCore.dll", "hMail3mailsrvprovider.dll", "hMail4mailsrvprovider.dll",
		"hMailmailsrvprovider.dll", "ICSharpCode.SharpZipLib.dll", "IMailmailsrvprovider.dll", "Legacy.dll",
		"libmariadb.dll", "MailEnablemailsrvprovider.dll", "MailMsgMigrMng.dll", "MDaemonmailsrvprovider.dll",
		"Merakmailsrvprovider.dll", "msvcr110.dll", "MySqlClient.dll", "psabackupcommon.dll", "psacommon.dll",
		"psacontentfile.dll", "PsaFactory110.dll", "PsaFactory115.dll", "PsaFactory120.dll", "PsaFactory83.dll",
		"PsaFactory90.dll",	"PsaFactory.dll", "PsaMailBackupRestoreCommon.dll", "SmarterMailmailsrvprovider.dll",
		"TCPmailsrvprovider.dll", "zlib1.dll"

	]

	_psa_locale_files = [
		"locale/en-US/CrossSysAgentSup.xml", "locale/en-US/DbMigrator.xml", "locale/en-US/DNSMigrator.xml",
		"locale/en-US/FtpMigrator.xml", "locale/en-US/MailMigrator.xml", "locale/en-US/migrmng.xml",
		"locale/en-US/PsaMigrMng90.xml", "locale/en-US/WINAgentMng.xml", "locale/en-US/WinAgent.xml"
	]

	_psa_mail_backup_files = [
		"PSAMailbackup.exe", "PSAMailbackup.exe.config"
	]

	_psa_mail_restore_files = [
		"PSAMailrestore.exe", "PSAMailrestore.exe.config"
	]
