import logging
import posixpath

import settings
from parallels.common.plesk_backup.data_model import DatabaseServer
from parallels.common.utils import plesk_utils
from parallels.confixx_migrator.pmm_agent import ConfixxPmmMigrationAgent
from parallels.confixx_migrator.server import ConfixxSourceServer
from parallels.confixx_migrator.utils import ConfixxConfiguration
from parallels.confixx_migrator.content.mail import ConfixxCopyMailContent
from parallels.plesk_api.operator.subscription import Ips
from parallels.plesks_migrator.infrastructure_checks import checks as infrastructure_checks
from parallels.utils import cached
import connections
import parallels.common.migrator
import parallels.confixx_migrator.utils
from parallels.pmm_unix_migrator.migrator import PmmUnixMigrator
from parallels.confixx_migrator.workflow import FromConfixxWorkflow
from parallels.confixx_migrator.global_context import ConfixxGlobalMigrationContext


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

	def __init__(self, config):
		super(Migrator, self).__init__(config, settings)
		self.global_context.pmm_agent = self._get_pmm_agent()
		self.global_context.confixx_configuration = self._get_confixx_configuration()

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

	def _create_workflow(self):
		return FromConfixxWorkflow()

	def _create_global_context(self):
		context = ConfixxGlobalMigrationContext()
		context.source_has_dns_forwarding = False
		return context

	# ======================== copy mail content ==============================

	def _copy_mail_content_single_subscription(self, migrator_server, subscription, issues):
		copy_mail = ConfixxCopyMailContent(
			self.global_context.confixx_configuration,
			agent_home=self._get_settings().agent_home,
			mailmapping_tool='mailmapping.pl'
		)
		return copy_mail.copy_mail(self.global_context, migrator_server, subscription, issues)

	# ======================== databases =====================================

	def _get_src_db_server(self, db, backup):
		configuration = self.global_context.confixx_configuration
		return DatabaseServer(
			None,
			host='localhost',
			port='3306',
			login=configuration.get_mysql_user(),
			password=configuration.get_mysql_password(),
			dbtype='mysql',
			is_default=True,
		)

	def _get_mailserver_ip_by_subscription_name(
			self, source_settings, subscription_name
		):
		"""Confixx MySQL server IP equals to panel's IP; return None."""
		# TODO This seems to be wrong, why Confixx has no mail IP?
		return Ips(None, None)

	# ======================== infrastructure checks ==========================
 
	def _get_check_service_connection_commands(self):
		return {
			'web': self._check_unix_copy_web_content_rsync_connections,
			'mail': self._check_unix_copy_mail_content_rsync_connections,
			'db': self._check_unix_copy_db_content_scp_connections
		}

	def _check_infrastructure_connections(self, report, safe):
		self.logger.info(u"Check connection requirements")

		for service in ('web', 'mail', 'db'):
			self._check_connection(service, report, safe)

	def _check_connection(self, service, report, safe):
		service_checkers = self._get_check_service_connection_commands()
		report_messages = {
			'title':
				u"Connections required for source and the destination %s"
				u" server",
			'error':
				u"Failed to check connections between for source and the"
				u" destination %s server"
		}
		report = report.subtarget(report_messages['title'] % service, None)
		checks = infrastructure_checks.InfrastructureChecks()
		with safe(report, report_messages['error'] % service):
			service_checkers[service](checks, report)

	def _check_disk_space(self, report, safe):
		self.logger.info(u"Check disk space requirements")
		disk_space_report = report.subtarget(u"Disk space requirements", None)
		super(Migrator, self)._check_disk_space_unix(disk_space_report)

	# ======================== utility functions ==============================

	@cached
	def _get_confixx_configuration(self):
		return ConfixxConfiguration(
			self.conn.confixx, 
			self._get_pmm_agent().get_confixx_config_path()
		)

	@cached # to avoid re-deploying, have a single PMM agent object
	def _get_pmm_agent(self):
		migrator_pmm_dir = posixpath.join(
			plesk_utils.get_migrator_root_path(parallels.confixx_migrator),
			'extras', 'pmm')
		return ConfixxPmmMigrationAgent(
			self.global_context,
			self.conn.confixx,
			migrator_pmm_dir,
			self._get_settings()
		)

	@cached
	def _get_source_node(self, node_id):
		node_settings = self._get_source_servers()[node_id]
		return ConfixxSourceServer(
			node_id, node_settings, self.global_context.confixx_configuration
		)
