import logging
import os

from parallels.common.actions.base.common_action import CommonAction
from parallels.common.logging_context import log_context
from parallels.common.utils.pmm.agent import DumpSelected, DumpAll
from parallels.common.utils.yaml_utils import read_yaml, write_yaml
from parallels.plesks_migrator.pmm_agent import create_pmm_agent

logger = logging.getLogger(__name__)


class FetchBackupActionBase(CommonAction):
	def run(self, global_context):
		"""

		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		for source_id in self._get_source_servers(global_context):
			with log_context(source_id), global_context.migrator_server.runner() as local_runner:
				source_server = global_context.conn.get_source_node(source_id)
				backup_filename = global_context.session_files.get_path_to_raw_plesk_backup(source_id)

				if source_server.is_windows():
					self._fetch_windows(source_server, backup_filename, global_context, source_id)
				else:
					self._fetch_unix(source_server, backup_filename, global_context, local_runner, source_id)

	@staticmethod
	def _fetch_unix(source_server, backup_filename, global_context, local_runner, source_id):
		if global_context.migration_list_data is None:
			selection = DumpAll()
		else:
			selection = DumpSelected(
				resellers=set(global_context.migration_list_data.resellers),
				clients=set(global_context.migration_list_data.customers_mapping.keys()),
				domains=set(global_context.migration_list_data.subscriptions_mapping.keys())
			)
		session_files = global_context.session_files
		selection_filename = session_files.get_path_to_raw_plesk_backup_selection(
			source_id
		)
		if local_runner.file_exists(selection_filename):
			previous_selection = read_yaml(selection_filename)
		else:
			previous_selection = None

		if (
			previous_selection is not None and
			previous_selection.covers(selection) and
			local_runner.file_exists(backup_filename) and
			not global_context.options.reload_source_data
		):
			logger.info(u"Using the existing migration dump for '%s'", source_id)
		else:
			if local_runner.file_exists(selection_filename):
				local_runner.remove_file(selection_filename)
			agent = create_pmm_agent(global_context, source_server)
			agent.create_dump(backup_filename, selection=selection)
			write_yaml(selection_filename, selection)

	@staticmethod
	def _fetch_windows(source_server, backup_filename, global_context, source_id):
		if global_context.migration_list_data is None:
			selection = DumpAll()
		else:
			selection = DumpSelected(
				resellers=set(global_context.migration_list_data.resellers),
				clients=set(global_context.migration_list_data.customers_mapping.keys()),
				domains=set(global_context.migration_list_data.subscriptions_mapping.keys())
			)
		if not global_context.options.reload_source_data and os.path.exists(backup_filename):
			logger.info(u"Using the existing migration dump for '%s'", source_id)
		else:
			agent = create_pmm_agent(global_context, source_server)
			agent.create_dump(backup_filename, selection=selection)

	def _get_source_servers(self, global_context):
		raise NotImplementedError()


class FetchBackupAction(FetchBackupActionBase):
	def get_description(self):
		return "Fetch configuration data from Plesk servers"

	def get_failure_message(self, global_context):
		"""
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		return "Failed to fetch configuration data from Plesk servers"

	def _get_source_servers(self, global_context):
		"""
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		return global_context.conn.get_source_plesks()
