from parallels.target.pvps import messages
from parallels.api.poa import poa_api
from parallels.core.checking import Problem
from parallels.core.converter.business_objects.common import SOURCE_TARGET
from parallels.core.logging_context import log_context
from parallels.target.pvps.models.target_data_model import PVPSSubscription
from parallels.core.utils.common import find_only


class PVPSSubscriptionConverter(object):
	def convert_subscriptions(
		self, source_panel_infos,
		target_existing_objects,
		subscription_mapping, model, report
	):
		converted_subscriptions = self._convert_subscriptions_plain(source_panel_infos)

		clients_by_logins = {}
		for client in model.clients.itervalues():
			clients_by_logins[client.login] = client, None
		for reseller in model.resellers.itervalues():
			for client in reseller.clients:
				clients_by_logins[client.login] = client, reseller

		for subscription_name, mapping in subscription_mapping.iteritems():
			if subscription_name not in converted_subscriptions:
				assert False

			converted_subscription = converted_subscriptions[subscription_name]

			self._assign_subscriptions(
				clients_by_logins, converted_subscription, mapping, report,
				target_existing_objects
			)

	@staticmethod
	def _convert_subscriptions_plain(source_panel_infos):
		"""Perform direct conversion: backup subscription to target model subscription"""
		converted_subscriptions = {}
		for source_panel_info in source_panel_infos:
			with log_context(source_panel_info.id):
				backup = source_panel_info.load_raw_backup()
				for hosting_subscription in backup.iter_all_subscriptions():
					converted_subscriptions[hosting_subscription.name] = PVPSSubscription(
						name=hosting_subscription.name,
						plan_name=None,
						plan_id=None,
						source=source_panel_info.id,
						is_windows=source_panel_info.is_windows,
						mail_is_windows=source_panel_info.is_windows,
						sysuser_login=hosting_subscription.phosting_sysuser_name,
						target_subscription=None,
					)
		return converted_subscriptions

	def _assign_subscriptions(
		self, clients_by_logins, converted_subscription, mapping, report, target_existing_objects
	):
		"""Assign subscription to clients, resellers and plans"""

		subscription_report = report.get_subscription_report(converted_subscription.source, converted_subscription.name)
		if not self._check_owner_exists(clients_by_logins, mapping, subscription_report):
			return

		client, reseller = clients_by_logins[mapping.owner]
		if reseller is None:
			reseller_id = poa_api.Identifiers.OID_ADMIN
		else:
			reseller_id = target_existing_objects.resellers[reseller.login].id

		service_template = self._get_service_template(reseller_id, mapping, subscription_report, target_existing_objects)
		if service_template is None:
			return

		converted_subscription.owner_reseller_id = reseller_id
		converted_subscription.plan_id = service_template.id
		client.subscriptions.append(
			converted_subscription
		)
		if client.source == SOURCE_TARGET:
			client_id = find_only(
				target_existing_objects.customers.values(),
				lambda c: c.contact.username == client.login,
				"Failed to find client"
			).id

			existing_subscriptions = filter(
				lambda s: (
					s.plan_id == converted_subscription.plan_id and
					s.name == converted_subscription.name and
					s.owner_id == client_id
				),
				target_existing_objects.vps_subscriptions,
			)
			if len(existing_subscriptions) > 0:
				converted_subscription.target_subscription = existing_subscriptions[0]

	@staticmethod
	def _check_owner_exists(clients_by_logins, mapping, report):
		if mapping.owner not in clients_by_logins:
			report.add_issue(
				Problem(
					'owner_of_subscription_does_not_exist', Problem.ERROR,
					messages.SUBSCRIPTION_IS_MAPPED_TO_UNEXISTING_CLIENT % mapping.owner
				),
				messages.CREATE_CLIENT_IN_DESTINATION_PANEL)
			return False
		else:
			return True

	@staticmethod
	def _get_service_template(reseller_id, mapping, report, target_existing_objects):
		service_template = filter(
			lambda plan: (plan.owner_id == reseller_id and plan.name == mapping.plan),
			target_existing_objects.vps_service_templates
		)
		if len(service_template) == 0:
			report.add_issue(
				Problem(
					'plan_does_not_exist', Problem.ERROR,
					messages.SUBSCRIPTION_IS_MAPPED_TO_UNEXISTING_PLAN % mapping.plan
				),
				messages.SOLUTION_CREATE_PLAN_IN_DESTINATION_PANEL_OR_MAP_TO_ANOTHER_PLAN)
			return None
		else:
			return service_template[0]
