import json, logging, lxml.etree as ET, re
from typing import Any, Dict
from jinja2 import Environment, PackageLoader, select_autoescape
from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
from .EndPoints import parse as parse_endpoints
from .Interfaces import parse as parse_interfaces
from .NetworkInstances import parse as parse_network_instances

ALL_RESOURCE_KEYS = [
    RESOURCE_ENDPOINTS,
    RESOURCE_INTERFACES,
    RESOURCE_NETWORK_INSTANCES,
]

RESOURCE_KEY_MAPPINGS = {
    RESOURCE_ENDPOINTS        : 'component',
    RESOURCE_INTERFACES       : 'interface',
    RESOURCE_NETWORK_INSTANCES: 'network_instance',
}

RESOURCE_PARSERS = {
    'component'       : parse_endpoints,
    'interface'       : parse_interfaces,
    'network_instance': parse_network_instances,
}

LOGGER = logging.getLogger(__name__)
RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]')
JINJA_ENV = Environment(loader=PackageLoader('device.service.drivers.openconfig'), autoescape=select_autoescape())

def get_filter(resource_key : str):
    resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key)
    template_name = '{:s}/get.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key))
    template = JINJA_ENV.get_template(template_name)
    return '<filter>{:s}</filter>'.format(template.render())

def parse(resource_key : str, xml_data : ET.Element):
    parser = RESOURCE_PARSERS.get(RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key))
    if parser is None: return [(resource_key, xml_data)]
    return parser(xml_data)

def compose_config(resource_key : str, resource_value : str, delete : bool = False) -> str:
    template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key))
    template = JINJA_ENV.get_template(template_name)
    data : Dict[str, Any] = json.loads(resource_value)
    operation = 'delete' if delete else 'merge'
    return '<config>{:s}</config>'.format(template.render(**data, operation=operation))
