from collections import defaultdict

from parallels.utils import if_not_none, group_by, group_by_id
from parallels.common.migration_list import MigrationList as PlesksMigrationList


class MigrationList(PlesksMigrationList):
	@classmethod
	def _extract_subscriptions(
		cls, source_data, subscriptions_mapping=None, subscription_filter=None,
		include_addon_plans=False, target_panel=None
	):
		processed_subscriptions = set()
		subscriptions = []
	
		plesk_clients_by_id = group_by_id(source_data.expand_objects.plesk_clients, lambda c: c.id)
		expand_clients_by_id = group_by_id(source_data.expand_objects.expand_clients, lambda c: c.id)
		assigned_clients_by_client_id = group_by(
			source_data.expand_objects.assigned_plesk_clients, lambda c: c.client_id
		)
		resellers_by_id = group_by_id(source_data.expand_objects.expand_resellers, lambda r: r.id)
		plesk_domains_by_plesk_id = group_by(source_data.expand_objects.plesk_domains, lambda d: d.plesk_id)

		for plesk_id in source_data.plesks:
			for domain in plesk_domains_by_plesk_id[plesk_id]:
				owner_id = (
					assigned_clients_by_client_id[domain.client_id][0].reseller_id
					if domain.client_id in assigned_clients_by_client_id
					else None
				)
				owner_login = if_not_none(owner_id, lambda oid: resellers_by_id[oid].login)
				plesk_client = plesk_clients_by_id[domain.client_id]
				if plesk_client.expand_client_id is None:
					if plesk_client.login != 'admin':
						client_login = plesk_client.login
					else:
						if owner_login is None:
							# subscription belongs to Plesk admin,
							# and not assigned to an Expand reseller -> move under ppa-admin
							client_login = 'ppa-admin'
						else:
							# subscription belongs to Plesk admin, and assigned
							# to an Expand reseller 'reseller' -> move under ppa-reseller
							client_login = 'ppa-%s' % owner_login
				else:
					client_login = expand_clients_by_id[plesk_client.expand_client_id].info['login']

				if domain.name not in processed_subscriptions:
					subscriptions.append(cls.SubscriptionSourceInfo(
						name=domain.name, plan=domain.tmpl_name, addon_plans=[], 
						reseller=owner_login, customer=client_login
					))
					processed_subscriptions.add(domain.name)

		return subscriptions

	@classmethod
	def _get_plans(cls, source_data, ppa_service_templates, addon_plans=False, include_source_plans=True):
		"""Return the following structure:
		plans[reseller_login][plan_name] = bool: whether this plan exists in PPA
		reseller_login is either a reseller login or None if owner is admin
		"""
		plans = defaultdict(lambda: defaultdict(bool))
		subscriptions = cls._extract_subscriptions(source_data)
		for subscription in subscriptions:
			plans[subscription.reseller][subscription.plan] = False

		expand_resellers_by_id = group_by_id(source_data.expand_objects.expand_resellers, lambda r: r.id)
		for p in source_data.expand_objects.expand_plans:
			reseller_login = (
				expand_resellers_by_id[p.reseller_id].login
				if p.reseller_id in expand_resellers_by_id else None
			)
			plans[reseller_login][p.name] = False

		for reseller_login, template_names in ppa_service_templates.iteritems():
			for template_name in template_names:
				plans[reseller_login][template_name] = True

		return plans
	
	@classmethod
	def _get_reseller_contacts(cls, source_data):
		reseller_contacts = {}
		for reseller in source_data.expand_objects.expand_resellers:
			if reseller.login not in reseller_contacts:
				reseller_contacts[reseller.login] = reseller.name
		return reseller_contacts

	@staticmethod
	def _get_reseller_plans(plesk_backup_iter):
		"""Get dictionary with keys - reseller logins, values - plans they are assigned to

		For Expand this function returns empty dictionary, as source Expand reseller plans
		do not map directly to target panel (now PPA only) plans. This could be improved in the future.

		:rtype: dict[basestring, basestring]
		"""
		return {}

	@classmethod
	def _get_customer_contacts(cls, source_data):
		customer_contacts = {}
		expand_clients_by_id = group_by_id(source_data.expand_objects.expand_clients, lambda c: c.id)
		for customer in source_data.expand_objects.plesk_clients:
			if customer.expand_client_id is None:
				customer_login = customer.login
				customer_pname = customer.pname
			else:
				customer_login = expand_clients_by_id[customer.expand_client_id].info['login']
				customer_pname = expand_clients_by_id[customer.expand_client_id].personal_info['pname']

			if customer_login not in customer_contacts:
				customer_contacts[customer_login] = customer_pname
		return customer_contacts
	
	@classmethod
	def _get_source_subscriptions(cls, source_data):
		return [domain.name for domain in source_data.expand_objects.plesk_domains]
