import logging
import posixpath

import settings
from parallels.common.plesk_backup.data_model import DatabaseServer
from parallels.common.utils import plesk_utils
from parallels.cpanel_migrator.pmm_agent import CpanelPmmMigrationAgent
from parallels.cpanel_migrator.server import CpanelSourceServer
from parallels.cpanel_migrator.content.mail import CpanelSourceMailDirectory
from parallels.cpanel_migrator.content.mail import CpanelCopyMailRsync
from parallels.cpanel_migrator.utils import CpanelConfiguration
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.cpanel_migrator.utils
from parallels.pmm_unix_migrator.migrator import PmmUnixMigrator
from parallels.cpanel_migrator.workflow import FromCpanelWorkflow
from parallels.cpanel_migrator.global_context import CpanelGlobalMigrationContext


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

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

	def _create_workflow(self):
		return FromCpanelWorkflow()

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

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

	def _copy_mail_content_single_subscription(self, migrator_server, subscription, issues):
		self.logger.info(
			u"Migrating mail content for subscription '%s'.", subscription.name)
		copy_action = CpanelCopyMailRsync(CpanelSourceMailDirectory)
		copy_action.copy_mail(
				self.global_context, migrator_server, subscription, issues)

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

	def _get_src_db_server(self, db, backup):
		if db.dbtype == 'mysql':
			configuration = self._get_cpanel_configuration()
			user, password = configuration.pmm_agent.get_mysql_credentials()
			port = '3306'
		else:
			user = 'postgres'
			password = None
			port = '5432'
		return DatabaseServer(
			None,
			host='localhost',
			port=port,
			login=user,
			password=password,
			dbtype=db.dbtype,
			is_default=True,
		)

	def _get_mailserver_ip_by_subscription_name(self, source_settings, subscription_name):
		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_cpanel_configuration(self):
		return CpanelConfiguration(
			self.conn.cpanel,
			self._get_pmm_agent()
		)

	@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.cpanel_migrator),
			'extras', 'pmm')
		return CpanelPmmMigrationAgent(
			self.global_context,
			self.conn.cpanel,
			migrator_pmm_dir,
			self._get_settings()
		)

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