from parallels.core import messages
import logging
import threading

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.actions.utils.multithreading_properties import MultithreadingProperties
from parallels.core.dump.data_model import get_hosting_type
from parallels.core.utils.common import if_not_none, group_by_id, find_first
from parallels.core.utils.common_constants import ADMIN_ID

logger = logging.getLogger(__name__)


class ImportSubscriptions(SubscriptionAction):
	def __init__(self):
		self._lock = threading.Lock()

	def get_description(self):
		return messages.CREATE_SUBSCRIPTION_IN_TARGET_PANEL

	def get_failure_message(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return (
			messages.FAILED_CREATE_SUBSCRIPTION_S_IN_TARGET) % (subscription.name,)

	def filter_subscription(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return True

	def get_multithreading_properties(self):
		return MultithreadingProperties(
			can_use_threads=True, use_threads_by_default=True
		)

	def run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		webspaces_by_name = group_by_id(
			global_context.target_existing_objects.webspaces, lambda ws: ws.name
		)

		reseller = subscription.model_reseller
		client = subscription.model_client

		if subscription.name in webspaces_by_name:
			# subscription already exists, just enable virtual hosting if it is not enabled
			existing_hosting_type = webspaces_by_name[subscription.name].htype
			if subscription.raw_dump.is_virtual_hosting and existing_hosting_type == 'none':
				logger.info(messages.SUBSCRIPTION_ALREADY_EXISTS_BUT_NO_HOSTING)
				global_context.import_api.enable_subscription_virtual_hosting(
					subscription.model, subscription.model_client,
				)
			return

		reseller_login = if_not_none(reseller, lambda r: r.login)

		if reseller is None:
			reseller_id = ADMIN_ID
		else:
			reseller_id = global_context.target_existing_objects.resellers[reseller.login].id

		if subscription.model.plan_name is not None:
			plan_id = find_first(
				global_context.target_existing_objects.service_templates,
				lambda st: st.owner_id == reseller_id and st.name == subscription.model.plan_name,
			).st_id
		else:
			# custom subscription - subscription that is not
			# assigned to any service template (service plan)
			plan_id = None

		if client.login != reseller_login:
			owner_id = global_context.target_existing_objects.customers[client.login].id
		else:
			owner_id = reseller_id

		target_plesk_server = global_context.conn.target.plesk_server

		# Workaround for Plesk for Linux <= 12.0
		# parallel creation of subscription may fail (bugs PPPM-2705, PPPM-2734, PPP-16935)
		parallel_create_could_fail = (
			target_plesk_server.plesk_version < (12, 6)
			and
			not target_plesk_server.is_windows()
		)

		if parallel_create_could_fail:
			logger.debug(messages.PARALLEL_CREATION_SUBSCRIPTIONS_MAY_FAIL_ACQUIRE)
			self._lock.acquire()

		addon_plan_names = [
			st.name for st in global_context.target_existing_objects.addon_service_templates
			if st.owner_id == reseller_id and st.st_id in subscription.model.addon_plan_ids
		]

		try:
			global_context.import_api.create_hosting_subscription(
				owner_id,
				plan_id,
				addon_plan_names,
				subscription.model,
				subscription.model_client,
				subscription.model_reseller,
				get_hosting_type(subscription.raw_dump.node)
			)
		finally:
			if parallel_create_could_fail:
				logger.debug(messages.RELEASE_LOCK_FOR_CREATION_SUBSCRIPTIONS_OPERATION)
				self._lock.release()
