import logging
import paramiko

from parallels.plesk_api.core import PleskError
from parallels import plesk_api
from parallels.common.utils import ssh_utils
from parallels.common import MigrationError

logger = logging.getLogger(__name__)

class ConnectionChecker(object):
	def check(self, check_list):
		"""check_list contains items that should be checked here. Possible options are: ssh_auth, plesk_api, windows_auth."""
		for server, checks in check_list:
			server_options = server.node_settings
			if hasattr(server_options, "ssh_auth") and "ssh_auth" in checks: 
				self.check_ssh(server.description(), server_options)
			if hasattr(server_options, "plesk_api") and "plesk_api" in checks:
				self.check_plesk_api(server.description(), server_options)
			if hasattr(server_options, "windows_auth") and "windows_auth" in checks:
				with server.runner() as runner:
					runner.check(server.description())

	def check_ssh(self, server_name, server_options):
		logger.debug(u"Check SSH connection for %s server" % server_name)
		try:
			with ssh_utils.connect(server_options) as ssh_client:
				ssh_client.get_transport().open_session()
		except paramiko.AuthenticationException as e:
			logger.debug(u'Exception:', exc_info=e)
			raise MigrationError(
				u"Unable to login to %s SSH service due to incorrect login/password specified in config file.\n"
				u"Set valid credentials in 'ssh-username' and 'ssh-password' options in corresponding section in config file and re-run migration tool." % (
					server_name
				)
			)
		except (paramiko.SSHException, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to %s by SSH: %s"
				% (server_name, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check SSH connection to %s: %s"
				% (server_name, err)
			)

	def check_target_plesk_api(self, node_plesk_api, node_description):
		logger.debug(u"Check %s API connection", node_description)
		try:
			node_plesk_api.send(plesk_api.operator.ServerOperator.Get([
				plesk_api.operator.ServerOperator.Dataset.GEN_INFO
			])).data
		except (PleskError, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to %s Plesk API to '%s' url: %s"
				% (node_description, node_plesk_api.url, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check %s Plesk API at '%s': %s"
				% (node_description, node_plesk_api.url, err)
			)

	def check_plesk_api(self, server_name, server_options):
		logger.debug(u"Check API connection for %s." % server_name)
		try:
			plesk_api.Client(
				server_options.plesk_api.url,
				server_options.plesk_api.auth.username,
				server_options.plesk_api.auth.password,
				'1.5.2.1',
				pretty_print=True
			).send(
				plesk_api.operator.ServerOperator.Get([
					plesk_api.operator.ServerOperator.Dataset.GEN_INFO
			])).data
		except PleskError as e:
			logger.debug(u"Exception:", exc_info=e)
			if e.code == 1001:
				raise PleskConnectionCheckError(
					u'Unable to login to Plesk API service due to incorrect login/password specified in config file.\n'
					u"Set valid credentials in 'panel-username' and 'panel-password' options in [%s] section in config file and re-run migration tool." % server_options.id
				)
			if e.code == 1030:
				raise PleskConnectionCheckError(
					u"The license key has expired on the source Plesk server '%s' (%s).\n"
					u"To continue with migration, you need to install a valid license key, and then re-run the migration tool." % (
						server_options.id, server_options.ip
					)
				)
			raise
		except (PleskError, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to Plesk to '%s' url: %s"
				% (server_options.plesk_api.url, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check Plesk API at '%s': %s"
				% (server_options.plesk_api.url, err)
			)

class PleskConnectionCheckError(MigrationError):
	pass

