from parallels.core.utils.common_constants import PLESK_PANEL_DEFAULT_PORT
from parallels.pvps import messages
from contextlib import contextmanager

from parallels.plesk.utils.xml_rpc import plesk as plesk_api
from parallels.core.connections.checker import ConnectionChecker
from parallels.core.connections.ssh.connection_pool import SSHConnectionPool
from parallels.core.connections.target_servers import TargetServer
from parallels.core.connections.plesk_server import PleskServer
from parallels.core.panel.server.plesk_family import HostingServer
from parallels.core.run_command import SSHRunner, WinexeRunner
from parallels.core.utils.session_dir import WindowsSessionDir, UnixSessionDir
from parallels.core.utils.common import cached


class PleskInVPSTargetServer(TargetServer, PleskServer):
	def __init__(self, settings):
		"""
		:type settings: PleskInVPSTargetSettings
		"""
		self.settings = settings
		session_dir = WindowsSessionDir if self.is_windows() else UnixSessionDir
		self.session_dir_obj = session_dir(self.runner, settings.session_dir)

	@contextmanager
	def runner(self):
		if self.is_windows():
			yield self._get_winexe_runner()
		else:
			ssh_conn = SSHConnectionPool.get_instance().get(self.settings, self.description())
			with ssh_conn.ssh() as ssh:
				yield SSHRunner(ssh, self.description())

	@cached
	def plesk_api(self):
		return plesk_api.Client(
			'https://%s:%s/enterprise/control/agent.php' % (self.settings.ip, PLESK_PANEL_DEFAULT_PORT),
			self.settings.panel_auth.username,
			self.settings.panel_auth.password,
			plesk_api.api_versions['11.5'],
			pretty_print=True
		)

	def get_hosting_server(self):
		return HostingServer(self)

	def get_session_file_path(self, filename):
		return self.session_dir_obj.get_file_path(filename)

	def session_dir(self):
		return self.session_dir_obj.get_session_dir_path()

	def is_windows(self):
		return self.settings.is_windows

	def description(self):
		return messages.TARGET_PVPS_SERVER % (self.ip())

	def ip(self):
		return self.settings.ip

	def ips(self):
		return {self.ip()}

	@property
	@cached
	def plesk_version(self):
		return self.get_plesk_version()

	def check_connections(self):
		connection_checker = ConnectionChecker()
		connection_checker.check_plesk_api(self)
		if not self.settings.is_windows:
			connection_checker.check_ssh(self.description(), self.settings)
		else:
			with self.runner() as runner:
				runner.check(self.description())

	@cached
	def _get_winexe_runner(self):
		return WinexeRunner(self.settings, False, '/tmp/')

	def __hash__(self):
		return hash((self.ip()))

	def __eq__(self, another):
		"""
		:type another: PleskInVPSTargetServer
		"""
		return isinstance(another, PleskInVPSTargetServer) and another.ip() == self.ip()


class PleskInVPSTargetSettings(object):
	def __init__(self, ip, panel_auth, session_dir):
		"""
		:type ip: basestring
		:type panel_auth: parallels.core.utils.config_utils.Auth
		:type session_dir: basestring
		"""
		self.ip = ip
		self.panel_auth = panel_auth
		self.session_dir = session_dir
		self.is_windows = None


class PleskInVPSUnixSettings(PleskInVPSTargetSettings):
	def __init__(self, ip, ssh_auth, panel_auth, session_dir):
		"""
		:type ip: basestring
		:type ssh_auth: parallels.core.migrator_config.SSHAuthPassword
		:type panel_auth: parallels.core.utils.config_utils.Auth
		:type session_dir: basestring
		"""
		super(PleskInVPSUnixSettings, self).__init__(ip, panel_auth, session_dir)
		self.ssh_auth = ssh_auth
		self.is_windows = False


class PleskInVPSWindowsSettings(PleskInVPSTargetSettings):
	def __init__(self, ip, windows_auth, panel_auth, session_dir):
		"""
		:type ip: basestring
		:type windows_auth: parallels.core.utils.config_utils.Auth
		:type panel_auth: parallels.core.utils.config_utils.Auth
		:type session_dir: basestring
		"""
		super(PleskInVPSWindowsSettings, self).__init__(ip, panel_auth, session_dir)
		self.windows_auth = windows_auth
		self.is_windows = True
