from parallels.plesk import messages
import itertools
from parallels.core.actions.base.common_action import CommonAction
from parallels.core import target_data_model, MigrationError


class ConvertAuxUserRoles(CommonAction):
	def get_description(self):
		return messages.ACTION_CONVERT_AUXILIARY_USER_ROLES_DESCRIPTION

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

	def run(self, global_context):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		target_model = global_context.target_model.model
		for target_client_id, target_client in target_model.clients.items():
			if not target_client_id:
				roles = get_admin_aux_user_roles(global_context) 
			else:
				source_clients = get_source_clients(global_context, target_client.login)
				source_user_roles = (c.auxiliary_user_roles for c in source_clients)
				roles = list(itertools.chain.from_iterable(source_user_roles))
			target_client.auxiliary_user_roles.extend(roles)


class ConvertAuxUsers(CommonAction):
	def get_description(self):
		return messages.ACTION_CONVERT_AUXILIARY_USERS

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

	def run(self, global_context):
		"""Find and add auxusers to the target model.

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		target_model = global_context.target_model.model
		for target_client_id, target_client in target_model.clients.items():
			if not target_client_id:
				auxuser_list = get_admin_aux_users(global_context)
			else:
				source_clients = get_source_clients(global_context, target_client.login)
				source_aux_users = (c.auxiliary_users for c in source_clients)
				auxuser_list = itertools.chain.from_iterable(source_aux_users)
			for auxuser in auxuser_list:
				self._add_auxuser(auxuser, target_client, global_context)

	def _add_auxuser(self, raw_auxuser, client, context):
		"""Convert aux users, append them to the target model."""
		if raw_auxuser.name == 'admin':
			return
		converted_auxuser = self._convert_auxuser(raw_auxuser)
		password = self._get_auxuser_password(
			raw_auxuser, client.login, context
		)
		converted_auxuser.password = password
		client.auxiliary_users.append(converted_auxuser)
	
	def _convert_auxuser(self, raw_auxuser):
		"""Create aux user object for target model."""
		personal_info = dict(raw_auxuser.personal_info)
		if 'email' not in personal_info:
			personal_info['email'] = self._get_auxuser_email(raw_auxuser)
		if raw_auxuser.contact is not None:
			auxuser_contact = raw_auxuser.contact
		else:
			auxuser_contact = raw_auxuser.name
		return target_data_model.AuxiliaryUser(
			login=raw_auxuser.name, password=None, name=auxuser_contact,
			roles=set(raw_auxuser.roles), personal_info=personal_info,
			is_active=raw_auxuser.is_active,
			subscription_name=raw_auxuser.subscription_name,
			is_domain_admin=raw_auxuser.is_domain_admin
		)

	def _get_auxuser_email(self, raw_auxuser):
		# 'email' is mandatory parameter (according to importer), but it
		# may be missing in Plesk 8 domain admin or mail accounts
		if raw_auxuser.email:
			return raw_auxuser.email
		elif '@' in raw_auxuser.name:
			return raw_auxuser.name
		else:
			return u"admin@%s" % raw_auxuser.name

	def _get_auxuser_password(self, raw_auxuser, client_login, context):
		if raw_auxuser.password.type == 'plain':
			password = raw_auxuser.password.text
		else:
			password = context.password_holder.get('auxiliary_user', (client_login, raw_auxuser.name))
		return password


def get_source_clients(context, client_login):
	"""Search for clients with a given login in all available source panels."""
	dumps = (dump for (id, dump) in context.migrator.iter_all_server_raw_dumps())
	all_clients = (dump.iter_all_clients() for dump in dumps)
	found_clients = [x for x in itertools.chain(*all_clients) if x.login == client_login]

	if len(found_clients) > 0:
		return found_clients
	else:
		raise MigrationError(messages.CONVERTER_UNABLE_FIND_CLIENT_WITH_LOGIN % client_login)


def get_admin_aux_user_roles(context):
	"""Return a list of admin auxiliary user roles from all source panels."""
	dumps = (dump for (id, dump) in context.migrator.iter_all_server_raw_dumps())
	admin_user_roles = (dump.iter_admin_auxiliary_user_roles() for dump in dumps)
	return list(itertools.chain(*admin_user_roles))


def get_admin_aux_users(context):
	"""Return a list of admin auxiliary users found in all source panels."""
	dumps = (dump for (id, dump) in context.migrator.iter_all_server_raw_dumps())
	admin_users = (dump.iter_admin_auxiliary_users() for dump in dumps)
	return list(itertools.chain(*admin_users))
