from parallels.core.utils.plesk_utils import get_php_handlers
from parallels.plesk import messages
import logging
from parallels.core import MigrationError

from parallels.core.actions.base.common_action import CommonAction
from parallels.core.converter.business_objects.plans import PlansConverter
from parallels.core.utils import plesk_api_utils
from parallels.plesk.converter.hosting_plan import BackupToTargetPleskModelPlanConverter
from parallels.core.utils.common import format_list, format_multiline_list

logger = logging.getLogger(__name__)


class CreateHostingPlans(CommonAction):
	def get_description(self):
		"""
		:rtype: basestring
		"""
		return messages.ACTION_CREATE_HOSTING_PLANS_DESCRIPTION

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

	def run(self, global_context):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:rtype: None
		"""
		# 1) read migration list data
		plan_migration_list = global_context.migrator._read_migration_list_plans(global_context.options)

		# 2) convert plans to target model
		target_plesk_api = global_context.conn.target.plesk_server.plesk_api()

		allowed_limits = plesk_api_utils.get_service_template_allowed_limits(target_plesk_api)
		logger.debug(messages.ALLOWED_SERVICE_TEMPLATE_LIMITS, format_list(allowed_limits))
		allowed_permissions = plesk_api_utils.get_service_template_allowed_permissions(target_plesk_api)
		logger.debug(messages.ALLOWED_PLAN_PERMISSIONS, format_list(allowed_permissions))
		allowed_hosting_settings = plesk_api_utils.get_service_template_allowed_hosting_settings(target_plesk_api)
		logger.debug(messages.ALLOWED_PLAN_HOSTING_SETTINGS, format_list(allowed_hosting_settings))
		plesk_version = global_context.conn.target.plesk_server.get_plesk_version()
		if plesk_version <= (12, 5):
			allowed_php_handlers = None
		else:
			allowed_php_handlers = get_php_handlers(global_context.conn.target.plesk_server)

		converted_plans = PlansConverter().convert_plans(
			global_context.get_source_servers_info(), global_context.import_api, plan_migration_list,
			BackupToTargetPleskModelPlanConverter(
				allowed_limits, allowed_permissions, allowed_hosting_settings, allowed_php_handlers,
				global_context.conn.target.plesk_server.is_windows()
			)
		)
		# 3) import plans to the target panel
		self._import_plans(global_context, converted_plans)

	def _import_plans(self, global_context, plans):
		"""Import converted service service plans to target panel

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type plans: dict[(basestring | None, basestring, bool), parallels.core.converter.business_objects.plans.ConvertedPlanInfo]
		"""
		failed_plans = []

		for (owner, name, is_addon), plan_info in plans.iteritems():
			# Add errors reported by converter
			for issue in plan_info.issues:
				global_context.safe.fail_plan(
					reseller_name=owner,
					plan_name=name,
					error_message=issue.problem.description,
					severity=issue.problem.severity,
					solution=issue.solution
				)

			# Perform import
			plan = plan_info.plan
			owner_title = 'admin' if owner is None else messages.RESELLER_TITLE % owner
			plan_type_title = messages.HOSTING_PLAN if not is_addon else messages.HOSTING_ADDON_PLAN
			if plan.source != 'target':
				logger.info(messages.CREATE_PLAN_OWNED_BY, plan_type_title, name, owner_title)
				logger.debug(messages.PLAN_SETTINGS, plan.settings)
				try:
					if not plan.is_addon:
						global_context.import_api.create_service_template(owner, name, plan.settings)
					else:
						global_context.import_api.create_addon_service_template(owner, name, plan.settings)
				except Exception as e:
					logger.debug(messages.LOG_EXCEPTION, exc_info=True)
					logger.error(
						messages.FAILED_TO_CREATE_SERVICE_TEMPLATE, plan_type_title, name, owner_title, e
					)
					failed_plans.append((name, plan_type_title, owner_title))
			else:
				logger.info(
					messages.PLAN_ALREADY_EXISTS,
					plan_type_title.capitalize(), name, owner_title
				)

		self._check_failed_plans(failed_plans)

	@staticmethod
	def _check_failed_plans(failed_plans):
		"""Check if there are failed plans and raise nice exception in case there are som

		:param list[(basestring, basestring, basestring)] failed_plans: list of failed plans
		:rtype: None
		"""
		if len(failed_plans) > 0:
			raise MigrationError(
				messages.FAILED_TO_CREATE_SERVICE_TEMPLATES_ON_TARGET % format_multiline_list([
					messages.PLAN_TITLE % (plan_type_title, plan_name, owner)
					for plan_name, plan_type_title, owner in failed_plans
				])
			)
