import logging
import xmltodict

from dataclasses import dataclass, field
from typing import Iterable, Optional


_XML_ROOT = '___YaRoot'


def _unpack_xml_node_text(text: str):
    text = text.encode('latin1').decode('unicode_escape').strip()

    text_data = {}
    for line in text.splitlines():
        k, v = line.split(':', 1)
        text_data[k.strip()] = v.strip()

    return text_data


@dataclass
class ToolConfig:
    service: str
    ctype: str

    abc_group: int
    tvm_id: int
    tvm_secret: str
    logbroker_tvm_id: int

    logfile: Optional[str]
    logrotate_max_bytes: int
    logrotate_backup_count: int
    debug: bool


@dataclass
class StreamConfig:
    class Type:
        LOGBROKER = 'PersQueue'

    id: int
    type: str

    name: Optional[str] = None

    @classmethod
    def from_xml_dict(cls, data: dict) -> 'StreamConfig':
        text = data['#text']
        text_data = _unpack_xml_node_text(text)

        id_ = text_data['StreamId']
        type_ = text_data['StreamType']

        name = text_data.get('Name')

        return StreamConfig(
            id=int(id_) or 0,
            type=type_,
            name=name
        )


@dataclass
class DocfetcherConfig:
    enabled: bool
    streams: Iterable[StreamConfig] = field(default_factory=list)

    @classmethod
    def from_xml_dict(cls, data: dict) -> 'DocfetcherConfig':
        streams = data.get('Stream', [])
        if not isinstance(streams, list):
            streams = [streams]

        text = data['#text']
        text_data = _unpack_xml_node_text(text)

        return DocfetcherConfig(
            enabled=text_data.get('Enabled', False),
            streams=[StreamConfig.from_xml_dict(stream) for stream in streams]
        )


@dataclass
class RTYServerConfig:
    docfetcher: Optional[DocfetcherConfig]

    @classmethod
    def from_xml_dict(cls, data: dict) -> 'RTYServerConfig':
        modules = data.get('ModulesConfig', {})

        docfetcher_config = None
        if modules.get('DOCFETCHER'):
            docfetcher_config = DocfetcherConfig.from_xml_dict(modules['DOCFETCHER'])

        return RTYServerConfig(docfetcher=docfetcher_config)

    @classmethod
    def from_content(cls, content: bytes) -> 'RTYServerConfig':
        raw_config = f'<{_XML_ROOT}>{content.decode()}</{_XML_ROOT}>'

        try:
            data = xmltodict.parse(raw_config)
        except:
            logging.exception('Unable to parse raw config data, invalid xml')
            raise MalformedConfigException

        try:
            server_config = cls.from_xml_dict(data[_XML_ROOT]['Server'])
        except:
            logging.exception('Unable to create %s from parsed xml data', cls.__name__)
            raise MalformedConfigException

        return server_config


class MalformedConfigException(Exception):
    ...
