import xml.etree.ElementTree as et

from parallels.core.logging import get_logger
from parallels.plesk.utils.xml_rpc.expand import messages
from parallels.core.utils.common.http_xml_client import HttpXmlClient
from parallels.plesk.utils.xml_rpc.expand.core import ExpandSystemError

logger = get_logger(__name__)


class ExpandClientError(Exception):
    pass


class UnsupportedOperationException(Exception):
    pass


class Client(HttpXmlClient):
    def __init__(self, url, username, password, api_version):
        super(Client, self).__init__(url)
        self.username = username
        self.password = password
        self.api_version = api_version
        
    def send(self, operation):
        return self.send_many(operation)[0]
    
    def send_many(self, *operations):
        if len(operations) == 0:
            raise ExpandClientError(messages.AT_LEAST_ONE_OPERATION_MUST_BE_SPECIFIED)

        if not all(o.operator_name == operations[0].operator_name for o in operations):
            raise ExpandClientError(messages.ALL_OPERATIONS_MUST_BELONG_TO_SAME_OPERATOR)
        operator_name = operations[0].operator_name

        request = self._create_packet(operations)

        response = self.send_xml(request, operator_name)
        
        operation_responses = []
        root = response.getroot()

        system_error = root.find('system_error')  # handle system-level error
        if system_error is not None:
            raise ExpandSystemError(
                code=int(system_error.findtext('code')), 
                message=system_error.findtext('text')
            )

        if root.findtext('system/status') == 'error':
            raise ExpandSystemError(
                code=int(root.findtext('system/errcode')), 
                message=root.findtext('system/errtext')
            )

        assert len(operations) == len(root)
        for operation, node in zip(operations, root):
            assert operation.operation_name == node.tag
            operation_responses.append(operation.parse(node))
        return operation_responses
    
    def _create_packet(self, operations):
        request = et.ElementTree(et.Element('packet', dict(version=self.api_version)))
        for op in operations:
            operation_node = et.Element(op.operation_name)
            operation_node.extend(op.inner_xml())
            request.getroot().append(operation_node)
        return request

    def _get_http_headers(self, data, operator_name):
        headers = super(Client, self)._get_http_headers(data)
        headers['HTTP_AUTH_LOGIN'] = self.username
        headers['HTTP_AUTH_PASSWD'] = self.password
        headers['HTTP_AUTH_OP'] = operator_name
        return headers
