from collections import namedtuple
import os.path

from parallels.core.migrator_config import read_ssh_auth, \
	read_windows_auth, read_windows_agent_settings, \
	read_copy_mail_content_settings, get_local_session_dir
from parallels.core.utils.common_constants import PLESK_PANEL_DEFAULT_PORT, WINDOWS_SOURCE_DEFAULT_SESSION_DIR, \
	UNIX_SOURCE_DEFAULT_SESSION_DIR, WINDOWS_REMOTE_TARGET_DEFAULT_SESSION_DIR
from parallels.core.utils.config_utils import \
	ConfigSection, read_http_connection_settings
from parallels.core.utils.common import default
from parallels.core.utils.entity import Entity


class TargetPleskConfigBase(object):
	def __init__(
		self, ip, is_local, plesk_api, unix_session_dir, windows_session_dir,
		cligate_ip=None, apache_restart_interval=None
	):
		self._ip = ip
		self._is_local = is_local
		self._cligate_ip = cligate_ip
		self._plesk_api = plesk_api
		self._unix_session_dir = unix_session_dir
		self._windows_session_dir = windows_session_dir
		self._apache_restart_interval = apache_restart_interval

	@property
	def ip(self):
		return self._ip

	@property
	def cligate_ip(self):
		default_cligate_ip = '127.0.0.1' if self.is_local else self.ip
		return default(self._cligate_ip, default_cligate_ip)

	@property
	def plesk_api(self):
		return self._plesk_api

	@property
	def unix_session_dir(self):
		return self._unix_session_dir

	@property
	def windows_session_dir(self):
		return self._windows_session_dir

	@property
	def apache_restart_interval(self):
		return self._apache_restart_interval

	@property
	def is_windows(self):
		raise NotImplementedError()

	@property
	def is_local(self):
		"""If target server is local or remote

		Local server means that migrator works on the target node, remote means
		that migrator's node and target node are different servers
		:rtype: bool
		"""
		return self._is_local


class TargetPleskUnixConfig(TargetPleskConfigBase):
	def __init__(
		self, ip, is_local, ssh_auth, plesk_api, unix_session_dir, windows_session_dir,
		cligate_ip=None, apache_restart_interval=None
	):
		super(TargetPleskUnixConfig, self).__init__(
			ip, is_local, plesk_api, unix_session_dir, windows_session_dir, cligate_ip, apache_restart_interval
		)
		self._ssh_auth = ssh_auth

	@property
	def ssh_auth(self):
		return self._ssh_auth

	@property
	def is_windows(self): 
		return False


class TargetPleskWindowsConfig(TargetPleskConfigBase):
	def __init__(
		self, ip, is_local, windows_auth, plesk_api, unix_session_dir, windows_session_dir,
		agent_settings, cligate_ip=None
	):
		super(TargetPleskWindowsConfig, self).__init__(
			ip, is_local, plesk_api, unix_session_dir, windows_session_dir, cligate_ip,
			# Apache restart interval is not applicable for Windows
			apache_restart_interval=None
		)
		self._windows_auth = windows_auth
		self._agent_settings = agent_settings

	@property
	def windows_auth(self):
		return self._windows_auth

	@property
	def agent_settings(self):
		return self._agent_settings

	@property
	def is_windows(self):
		return True


class SourcePleskUnixConfig(namedtuple('SourcePleskUnixConfig', (
	'id', 'ip', 'ssh_auth', 'plesk_api', 'session_dir', 'mail_settings',
))):
	@property
	def is_windows(self):
		return False


class SourcePleskWindowsConfig(Entity):
	def __init__(self, id, ip, windows_auth, plesk_api, session_dir, mail_settings, agent_settings):
		self._id = id
		self._ip = ip
		self._windows_auth = windows_auth
		self._plesk_api = plesk_api
		self._session_dir = session_dir
		self._mail_settings = mail_settings
		self._agent_settings = agent_settings

	@property
	def id(self):
		return self._id

	@property
	def ip(self):
		return self._ip

	@property
	def windows_auth(self):
		return self._windows_auth

	@property
	def plesk_api(self):
		return self._plesk_api

	@property
	def session_dir(self):
		return self._session_dir

	@property
	def mail_settings(self):
		return self._mail_settings

	@property
	def agent_settings(self):
		return self._agent_settings

	@property
	def is_windows(self):
		return True


def read_source_dns_servers_settings(config, section_name):
	"""Read centralized dns ip addresses and credentials.
	"""
	section = ConfigSection(config, section_name)

	ip = section['ip']
	ssh_auth = read_ssh_auth(section)
	return SourcePleskUnixConfig(section_name, ip, ssh_auth, "false", "false", None)


def read_target_plesk_settings(config, section_name):
	"""
	:rtype:
		parallels.plesk.config.TargetPleskWindowsConfig |
		parallels.plesk.config.TargetPleskUnixConfig
	"""
	section = ConfigSection(config, section_name)
	ip = section['ip']
	target_os = section['os']
	is_local = section.getboolean('is-local', True)
	cligate_ip = section.get('cligate-ip')
	plesk_settings = dict(
		host=ip,
		username=section.get('panel-username', 'admin'),
		password=section.get('panel-password'),
	)
	plesk_api = read_http_connection_settings(
		section.prefixed('plesk-').with_defaults(dict(PLESK_URL_DEFAULTS, **plesk_settings))
	)

	if is_local:
		local_session_dir = get_local_session_dir(config)
		if target_os == 'windows':
			default_windows_session_dir = os.path.join(local_session_dir, 'target-server')
			default_unix_session_dir = None
		else:
			default_unix_session_dir = os.path.join(local_session_dir, 'target-server')
			default_windows_session_dir = None
	else:
		default_windows_session_dir = WINDOWS_REMOTE_TARGET_DEFAULT_SESSION_DIR
		default_unix_session_dir = '/tmp'

	windows_session_dir = section.get('windows-session-dir', default_windows_session_dir)
	unix_session_dir = section.get('unix-session-dir', default_unix_session_dir)

	if target_os == 'windows':
		windows_auth = read_windows_auth(section, required=False)
		return TargetPleskWindowsConfig(
			ip=ip, is_local=is_local, windows_auth=windows_auth, plesk_api=plesk_api,
			unix_session_dir=unix_session_dir,
			windows_session_dir=windows_session_dir,
			agent_settings=read_windows_agent_settings(config, section_name, windows_session_dir),
			cligate_ip=cligate_ip
		)
	else:
		ssh_auth = read_ssh_auth(section, required=False)
		apache_restart_interval = section.get('apache-restart-interval', '1800')
		return TargetPleskUnixConfig(
			ip=ip, is_local=is_local, ssh_auth=ssh_auth, plesk_api=plesk_api,
			unix_session_dir=unix_session_dir, windows_session_dir=windows_session_dir,
			cligate_ip=cligate_ip, apache_restart_interval=apache_restart_interval
		)


def read_source_plesk_settings(config, section_name):
	"""Read Plesk API and SSH connection settings.
	"""
	section = ConfigSection(config, section_name)

	ip = section['ip']
	os = section['os']
	session_dir = section.get(
		'session-dir',
		WINDOWS_SOURCE_DEFAULT_SESSION_DIR if os == 'windows' else UNIX_SOURCE_DEFAULT_SESSION_DIR
	)

	is_windows = (os == 'windows')
	mail_settings = read_copy_mail_content_settings(section, is_windows)

	plesk_api = _read_plesk_connection_settings(config, section_name)
	if os == 'windows':
		windows_auth = read_windows_auth(section)
		return SourcePleskWindowsConfig(
			section_name, ip, windows_auth, plesk_api, session_dir,
			mail_settings, read_windows_agent_settings(config, section_name, session_dir)
		)
	else:
		ssh_auth = read_ssh_auth(section)
		return SourcePleskUnixConfig(
			section_name, ip, ssh_auth, plesk_api, session_dir, mail_settings
		)


PLESK_URL_DEFAULTS = dict(
	protocol='https',
	port=PLESK_PANEL_DEFAULT_PORT,
	path='/enterprise/control/agent.php'
)


def _read_plesk_connection_settings(config, section_name):
	"""Read Plesk API connection settings.
	"""
	section = ConfigSection(config, section_name)

	ip = section['ip']

	api_defaults = dict(
		PLESK_URL_DEFAULTS,
		host=ip,
		username=section.get('panel-username', 'admin'),
		password=section.get('panel-password'),
	)
	return read_http_connection_settings(
		section.prefixed('plesk-').with_defaults(api_defaults)
	)

