from parallels.pvps import messages
from collections import defaultdict
import logging

from parallels.ppa.utils.xml_rpc.poa import poa_api
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.utils.yaml_utils import write_yaml
from parallels.pvps.models.existing_objects_model import \
	PVPSExistingObjectsModel, PVPSSubscription


logger = logging.getLogger(__name__)


class FetchTarget(CommonAction):
	def get_description(self):
		return messages.FETCH_INFO_FROM_TARGET_PANEL

	def get_failure_message(self, global_context):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		return messages.FAILED_TO_FETCH_INFO_FROM_TARGET

	def run(self, global_context):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		existing_objects = PVPSExistingObjectsModel(
			resellers={},
			customers={},
			vps_service_templates=[],
			vps_subscriptions=[]
		)

		self._fetch_customers(existing_objects, global_context)
		self._fetch_resellers(existing_objects, global_context)
		self._fetch_plans(existing_objects, global_context)
		self._fetch_pvps_subscriptions(existing_objects, global_context)

		target_filename = global_context.session_files.get_path_to_existing_objects_model()
		write_yaml(target_filename, existing_objects)
		global_context.target_existing_objects = existing_objects

	@staticmethod
	def _fetch_customers(existing_objects, global_context):
		"""Get information about customers from target panel and put it into model

		:type existing_objects: parallels.pvps.models.existing_objects_model.PVPSExistingObjectsModel
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		clients_logins_in_migration_list = global_context.migration_list_data.customers_mapping.keys()
		existing_objects.customers.update({
			customer.contact.username: customer
			for customer in global_context.import_api.list_customers(
				clients_logins_in_migration_list
			)
		})

	@staticmethod
	def _fetch_resellers(existing_objects, global_context):
		"""Get information about resellers from target panel and put it into model

		:type existing_objects: parallels.pvps.models.existing_objects_model.PVPSExistingObjectsModel
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		reseller_logins_in_migration_list = global_context.migration_list_data.resellers
		existing_objects.resellers.update({
			reseller.contact.username: reseller
			for reseller in global_context.import_api.list_resellers(reseller_logins_in_migration_list)
		})

	@staticmethod
	def _fetch_plans(existing_objects, global_context):
		"""Get information about plans (service templates) from target panel and put it into model

		:type existing_objects: parallels.pvps.models.existing_objects_model.PVPSExistingObjectsModel
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		st_ids = []
		for owner, plan_names in global_context.migration_list_data.plans.iteritems():
			if owner is None:
				owner_id = poa_api.Identifiers.OID_ADMIN
			else:
				if owner in existing_objects.resellers:
					owner_id = existing_objects.resellers[owner].id
				else:
					continue  # reseller with such login does not exist yet
			for st in global_context.import_api.get_service_template_list(owner_id):
				if st.name in plan_names:
					st_ids.append(st.st_id)

		existing_objects.vps_service_templates.extend(global_context.import_api.get_service_template_info_list(st_ids))

	@staticmethod
	def _fetch_pvps_subscriptions(existing_objects, global_context):
		"""Get information about PVPS subscriptions from target panel and put it into model

		:type existing_objects: parallels.pvps.models.existing_objects_model.PVPSExistingObjectsModel
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		subscription_names_by_owner_id = defaultdict()
		for name, info in global_context.migration_list_data.subscriptions_mapping.iteritems():
			subscription_owner = info.owner
			if subscription_owner in existing_objects.customers:
				owner_id = existing_objects.customers[subscription_owner].id
				subscription_names_by_owner_id[owner_id] = name
		for owner_id, subscription_names in subscription_names_by_owner_id.iteritems():
			for subscription_id in global_context.conn.target.poa_api().getAccountSubscriptions(owner_id):
				subscription = global_context.conn.target.poa_api().getSubscription(subscription_id)
				if subscription.name in subscription_names:
					existing_objects.vps_subscriptions.append(PVPSSubscription(
						id=subscription_id,
						name=subscription.name,
						owner_id=owner_id,
						plan_id=subscription.st_id
					))
