from collections import namedtuple
from datetime import datetime

from parallels.utils import if_not_none
from parallels.utils.xml import elem, text_elem, seq

from .. import core

ResellerInfo = namedtuple('ResellerInfo', (
	'gen_info', 'statistics', 'permissions', 'limits', 'ip_pool', 'subscriptions'
))

ResellerGenInfo = namedtuple('ResellerGenInfo', (
	'creation_date', 'cname', 'pname', 'login', 'status', 'phone', 'fax', 'email', 'address',
	'city', 'state', 'pcode', 'country', 'locale', 'guid', 'external_id',
))

ResellerAddGenInfo = namedtuple('ResellerAddGenInfo', (
	'cname', 'pname', 'login', 'passwd', 'status', 'phone', 'fax', 'email', 'address',
	'city', 'state', 'pcode', 'country', 'locale', 'external_id',
))
ResellerAddLimits = namedtuple('ResellerAddLimits', (
	'limits',  # list of ResellerAddLimit
	'resource_policy',  # instance of ResellerAddResourcePolicy
))
ResellerAddResourcePolicy = namedtuple('ResellerAddResourcePolicy', (
	'overuse', 'oversell',
))
ResellerAddLimit = namedtuple('ResellerAddLimit', ('name', 'value',))
ResellerAddPermission = namedtuple('ResellerAddPermission', ('name', 'value',))
ResellerAddResult = namedtuple('ResellerAddResult', (
	'reseller_id', 'guid'
))

ResellerStat = namedtuple('ResellerStat', (
	'active_clients', 'active_domains', 'subdomains', 'domain_aliases', 'disk_space', 'web_users',
	'data_bases', 'postboxes', 'mbox_quota', 'redirects', 'mail_groups', 'mail_resps', 'mail_lists',
	'webapps', 'traffic', 'traffic_prevday',
))
ResellerLimits = namedtuple('ResellerLimits', ('oversell', 'overuse', 'limits'))
SubscriptionInfo = namedtuple('SubscriptionInfo', ('locked', 'synchronized', 'plans'))
PlanReference = namedtuple('PlanReference', ('guid', 'external_id'))


class ResellerOperator(object):
	class Dataset(object):
		GEN_INFO = 'gen-info'
		STAT = 'stat'
		PERMISSIONS = 'permissions'
		LIMITS = 'limits'
		IP_POOL = 'ippool'
		SUBSCRIPTIONS = 'subscriptions'

		values = [GEN_INFO, STAT, PERMISSIONS, LIMITS, IP_POOL, SUBSCRIPTIONS]
	
	FilterAll = core.FilterAllWithNode
	FilterById = core.declare_filter('FilterById', 'id')
	FilterByLogin = core.declare_filter('FilterByLogin', 'login')
	FilterByGuid = core.declare_filter('FilterByGuid', 'guid')
	FilterByExternalId = core.declare_filter('FilterByExternalId', 'external-id')
		
	class Get(core.operation_with_filter('Get', ('dataset',))):
		operator_name = 'reseller'
		operation_name = 'get'
		min_api_version = '1.6.4.0'
		max_api_version = None

		def data_xml(self):
			return [
				elem('dataset', [elem(value) for value in ResellerOperator.Dataset.values if value in self.dataset])
			]
			
		@classmethod
		def parse(cls, elem):
			results = [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]
			if len(results) == 1 and results[0].ok and results[0].data is None:
				results = []
			return results
		
		@classmethod
		def _parse_data(cls, elem):
			reseller_id = if_not_none(elem.findtext('id'), int)
			if reseller_id is None:
				return None
			
			data = elem.find('data')
			gen_info = if_not_none(data.find('gen-info'), cls._parse_gen_info)
			statistics = if_not_none(data.find('stat'), cls._parse_statistics)
			permissions = if_not_none(data.find('permissions'), cls._parse_permissions)
			limits = if_not_none(data.find('limits'), cls._parse_limits)
			ip_pool = if_not_none(data.find('ippool'), cls._parse_ip_pool)
			subscriptions = if_not_none(data.find('subscriptions'), cls._parse_subscription)
			
			return (
				reseller_id,
				ResellerInfo(gen_info, statistics, permissions, limits, ip_pool, subscriptions)
			)
			
		@classmethod
		def _parse_gen_info(cls, elem):
			return ResellerGenInfo(
				datetime.strptime(elem.findtext('cr-date'), '%Y-%m-%d'),
				elem.findtext('cname'), elem.findtext('pname'), elem.findtext('login'),
				elem.findtext('status'),
				elem.findtext('phone'), elem.findtext('fax'), elem.findtext('email'),
				elem.findtext('address'), elem.findtext('city'), elem.findtext('state'),
				elem.findtext('pcode'), elem.findtext('country'), elem.findtext('locale'),
				elem.findtext('guid'), elem.findtext('external-id'),
			)
		
		@classmethod
		def _parse_statistics(cls, elem):
			return ResellerStat._make(int(elem.findtext(name.replace('_', '-'))) for name in ResellerStat._fields)
		
		@classmethod
		def _parse_permissions(cls, elem):
			return dict(
				(n.findtext('name'), n.findtext('value'))
				for n in elem.findall('permission')
			)
		
		@classmethod
		def _parse_limits(cls, elem):
			return ResellerLimits(
				if_not_none(elem.findtext('resource-policy/oversell'), lambda x: x == 'true'),
				elem.findtext('resource-policy/overuse'),
				dict((e.findtext('name'), e.findtext('value')) for e in elem.findall('limit'))
			)
		
		@classmethod
		def _parse_ip_pool(cls, elem):
			return [
				(e.findtext('ip-address'), e.findtext('ip-type'))
				for e in elem.findall('ip')
			]
		
		@classmethod
		def _parse_subscription(cls, elem):
			return if_not_none(elem.find('subscription'), lambda e: SubscriptionInfo(
				e.findtext('locked'),
				e.findtext('synchronized'),
				[cls._parse_plan_ref(p) for p in e.findall('plan')]
			))
			
		@classmethod
		def _parse_plan_ref(cls, elem):
			return PlanReference(
				elem.findtext('plan-guild'),
				elem.findtext('plan-external-id'),
			)

	class IppoolAddIp(core.operation('IppoolAddIp', ('reseller_id', 'ip_address', 'ip_type'))):
		operator_name = 'reseller'
		operation_name = 'ippool-add-ip'
		min_api_version = '1.6.4.0'
		max_api_version = None

		def inner_xml(self):
			return [
				text_elem('reseller-id', self.reseller_id),
				elem('ip', [
					text_elem('ip-address', self.ip_address),
					text_elem('ip-type', self.ip_type)
				])
			]

		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'))

	class Add(core.operation('Add', (
		'gen_info',  # instance of ResellerAddGenInfo
		'limits',  # instance of ResellerAddLimits
		'permissions',  # list of ResellerAddPermission
		'plan_name'
	))):
		operator_name = 'reseller'
		operation_name = 'add'
		min_api_version = '1.6.0.2'
		max_api_version = None

		def inner_xml(self):
			return seq( 
				elem('gen-info', seq(
					text_elem('cname', self.gen_info.cname),
					text_elem('pname', self.gen_info.pname),
					text_elem('login', self.gen_info.login),
					text_elem('passwd', self.gen_info.passwd),
					text_elem('status', self.gen_info.status),
					text_elem('phone', self.gen_info.phone),
					text_elem('fax', self.gen_info.fax),
					text_elem('email', self.gen_info.email),
					text_elem('address', self.gen_info.address),
					text_elem('city', self.gen_info.city),
					text_elem('state', self.gen_info.state),
					text_elem('pcode', self.gen_info.pcode),
					text_elem('country', self.gen_info.country),
					text_elem('locale', self.gen_info.locale),
					text_elem('external-id', self.gen_info.external_id),
				)),
				elem(
					'limits',
					seq(
						elem('resource-policy', seq(
							text_elem('oversell', self.limits.resource_policy.oversell),
							text_elem('overuse', self.limits.resource_policy.overuse),
						)) if self.limits.resource_policy is not None else None,
					) +
					[
						elem('limit', [
							text_elem('name', limit.name),
							text_elem('value', limit.value)
						])
						for limit in self.limits.limits
					]
				) if self.limits is not None else None,
				elem('permissions', [
					elem('permission', [
						text_elem('name', permission.name),
						text_elem('value', permission.value)
					])
					for permission in self.permissions
				]) if self.limits is not None else None,
				text_elem('plan-name', self.plan_name),
			)

		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'), cls._parse_data)

		@classmethod
		def _parse_data(cls, elem):
			return ResellerAddResult(
				reseller_id=elem.findtext('id'),
				guid=elem.findtext('guid')
			)