"""Connections to source custom panel servers"""

from parallels.core.migrator_config import read_source_server_settings
from parallels.core.connections.connections import Connections
from parallels.core.connections.source_server import SourceServer
from parallels.core.utils.config_utils import ConfigSection, get_sections_list
from parallels.core.utils.entity import Entity
from parallels.core.utils.common import group_by_id, cached
from parallels.core.utils.windows_mysql_client_deploy import deploy_mysqldump
from parallels.core.utils.windows_mysql_client_deploy import deploy_mysql_client
from parallels.plesk.source.custom import messages


class MigratorConnections(Connections):
	def __init__(self, global_context, target_panel):
		"""
		:type global_context: parallels.plesk.source.custom.global_context.CustomPanelGlobalMigrationContext
		"""
		super(MigratorConnections, self).__init__(global_context, target_panel)
		self._global_context = global_context

	def get_information_servers(self):
		return {}

	def get_source_server_by_id(self, server_id):
		section = ConfigSection(self._config, server_id)
		if 'ip' in section:
			settings = read_source_server_settings(self._config, server_id)
			return CustomPanelSourceServer(server_id, settings, self._global_context.migrator_server)
		else:
			return None

	def get_plesk_configuration_dump_paths(self):
		"""
		:rtype: dict[basestring, basestring]
		"""
		dump_paths = {}

		for section in self._get_source_dump_config_sections():
			if self._config.has_option(section, 'plesk-configuration-dump'):
				# for Plesk configuration dump, just provide the path specified in config
				dump_paths[section] = self._config.get(section, 'plesk-configuration-dump')
			elif self._config.has_option(section, 'hosting-description'):
				# for hosting description path, provide path, where Plesk configuration dump will be put
				session_files = self._global_context.session_files
				dump_paths[section] = (
					session_files.get_path_to_plesk_configuration_dump_created_from_hosting_description(section)
				)

		return dump_paths

	def iter_hosting_description_configs(self):
		"""
		:rtype: collections.Iterable[parallels.plesk.source.custom.connections.HostingDescriptionConfig]
		"""
		for section_name in self._get_source_dump_config_sections():
			section = ConfigSection(self._config, section_name)
			if 'hosting-description' in section:
				yield HostingDescriptionConfig(
					source_id=section_name,
					path=section.get('hosting-description'),
					file_format=section.get('description-format', 'yaml').lower()
				)

	def iter_database_servers(self):
		"""
		:rtype: collections.Iterable[parallels.custom_panel_migrator.connections.DatabaseServerConfig]
		"""
		for section_name in self._get_source_database_servers_config_sections():
			section = ConfigSection(self._config, section_name)
			yield DatabaseServerConfig(
				db_server_id=section_name,
				db_type=section.get('type'),
				host=section.get('host'),
				port=section.get('port'),
				login=section.get('login'),
				password=section.get('password')
			)

	def get_hosting_description_config(self, server_id):
		"""
		:type server_id: basestring
		:rtype: parallels.custom_panel_migrator.connections.HostingDescriptionConfig
		"""
		hosting_description_configs = group_by_id(self.iter_hosting_description_configs(), lambda l: l.source_id)
		return hosting_description_configs[server_id]

	def has_hosting_description_config(self, server_id):
		"""
		:type server_id: basestring
		:rtype: bool
		"""
		hosting_description_configs = group_by_id(self.iter_hosting_description_configs(), lambda l: l.source_id)
		return server_id in hosting_description_configs

	def _get_source_dump_config_sections(self):
		"""Get names of sections describing sources of data (servers and hosting description or Plesk dump)

		:rtype: list[basestring]
		"""
		return get_sections_list(self._config, 'GLOBAL', 'sources')

	def _get_source_database_servers_config_sections(self):
		"""Get names of sections describing database servers

		:rtype: list[basestring]
		"""
		return get_sections_list(self._config, 'GLOBAL', 'db-servers')

	def get_plesk_configuration_dump_path(self, dump_id):
		"""Get path to Plesk configuration dump file by its ID (which is the same as section name in configuration file)

		:type dump_id: basestring
		:rtype: basestring
		"""
		dump_paths = self.get_plesk_configuration_dump_paths()
		if dump_id not in dump_paths:
			raise Exception(messages.UNABLE_TO_GET_DUMP_PATH % dump_id)
		return dump_paths[dump_id]


class HostingDescriptionConfig(Entity):
	def __init__(self, source_id, path, file_format):
		"""
		:type source_id: basestring
		:type path: basestring
		:type file_format: basestring
		"""
		self._source_id = source_id
		self._path = path
		self._file_format = file_format

	@property
	def source_id(self):
		"""Source ID - section name in migrator's configuration file

		:rtype: basestring
		"""
		return self._source_id

	@property
	def path(self):
		"""Path to the hosting description file

		:rtype: basestring
		"""
		return self._path

	@property
	def file_format(self):
		"""File format of the hosting description file: JSON or YAML (see FORMAT_* constants)

		:rtype: basestring
		"""
		return self._file_format


class DatabaseServerConfig(Entity):
	def __init__(self, db_server_id, db_type, host, port, login, password):
		"""
		:type db_server_id: basestring
		:type db_type: basestring
		:type host: basestring
		:type port: basestring
		:type login: basestring
		:type password: basestring
		"""
		self._db_server_id = db_server_id
		self._db_type = db_type
		self._host = host
		self._port = port
		self._login = login
		self._password = password

	@property
	def db_server_id(self):
		"""Database server ID - name of a section of the server in migrator's configuration file

		:rtype: basestring
		"""
		return self._db_server_id

	@property
	def db_type(self):
		"""Database type - 'mysql' or 'mssql'

		:rtype: basestring
		"""
		return self._db_type

	@property
	def host(self):
		"""Database server host - hostname or IP address

		:rtype: basestring
		"""
		return self._host

	@property
	def port(self):
		"""Database server port

		:rtype: basestring
		"""
		return self._port

	@property
	def login(self):
		"""Administrator login of database server

		:rtype: basestring
		"""
		return self._login

	@property
	def password(self):
		"""Administrator password of database server

		:rtype: basestring
		"""
		return self._password


class CustomPanelSourceServer(SourceServer):
	"""Source server for migration from custom panel"""

	@cached
	def get_path_to_mysqldump(self):
		"""Deploy mysqldump.exe and return path to it on that source server

		:rtype: str
		"""
		return deploy_mysqldump(self)

	@cached
	def get_path_to_mysql(self):
		"""Deploy mysql.exe and return path to it on that source server

		:rtype: str
		"""
		return deploy_mysql_client(self)

	def mysql_use_skip_secure_auth(self):
		"""Whether to pass --skip-secure-auth flag to MySQL client

		This flag is necessary when client version is greater than server version.
		We deploy own MySQL client, it could be of greater version than server,
		so we should pass the flag.
		"""
		return True