import logging
from parallels.ppa import messages
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.migrator import LicenseValidationError
from parallels.core.utils.common import if_not_none
from parallels.plesk.utils.xml_rpc.plesk.operator import ServerOperator

logger = logging.getLogger(__name__)


class CheckServiceNodeLicenses(CommonAction):
	def get_description(self):
		return messages.CHECK_PPA_SERVICE_NODES_LICENSES

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

	def filter_action(self, global_context):
		"""Check whether we should run this action or not.

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:rtype: bool
		"""
		return not global_context.options.skip_license_checks

	def run(self, global_context):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		try:
			licensing_schema = if_not_none(
				global_context.conn.target.plesk_api().send(
					ServerOperator.Get(dataset=[ServerOperator.Dataset.KEY])
				).data.key,
				lambda key: key.properties.get('licensing-scheme')
			)
		except Exception as e:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			logger.error(messages.FAILED_TO_GET_INFO_ABOUT_PPA_MAIN_KEY % e)
			return

		logger.debug(messages.DEBUG_PPA_LICENSING_SCHEMA, licensing_schema)
		# In "websites" mode PPA does not require a license for each service node,
		# only one main license is necessary, and there is a limit of webspaces you can create
		# in "nodes" mode PPA requires licenses for each Web and Mail node

		if licensing_schema == 'websites':
			logger.info(messages.SERVICE_NODES_LICENSES_ARE_OK)
			# no need to perform checks for each of service nodes
			return

		service_nodes_info = global_context.conn.target.poa_api().get_service_nodes_info()

		# DNS and all database nodes do not require any license to work
		unlicensed_services = {'dns', 'db'}

		node_services = {
			node_info['host_id']: set(node_info['node_services'])
			for node_info in global_context.conn.target.poa_api().msp_license_manager_get_sip_data()
		}

		for service_node_info in service_nodes_info:
			if all([
				service_node_info.is_ready_to_provide,
				service_node_info.license_status != 'licensed',
				not node_services[service_node_info.host_id] <= unlicensed_services
			]):
				raise LicenseValidationError(
					messages.NO_PLESK_LICENSE_AT_SERVICE_NODE % (
						global_context.conn.target.get_ppa_node_description(service_node_info.host_id)
					)
				)
		logger.info(messages.SERVICE_NODES_LICENSES_ARE_OK)
