# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json, logging, lxml.etree as ET, re
from typing import Any, Dict, Optional
from jinja2 import Environment, PackageLoader, select_autoescape
from device.service.driver_api._Driver import (
    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL)
from .EndPoints import parse as parse_endpoints
from .Interfaces import parse as parse_interfaces, parse_counters
from .NetworkInstances import parse as parse_network_instances
from .RoutingPolicy import parse as parse_routing_policy
from .Acl import parse as parse_acl

ALL_RESOURCE_KEYS = [
    RESOURCE_ENDPOINTS,
    RESOURCE_INTERFACES,
    RESOURCE_ROUTING_POLICIES,      # routing policies should come before network instances
    RESOURCE_NETWORK_INSTANCES,
    RESOURCE_ACL,
]

RESOURCE_KEY_MAPPINGS = {
    RESOURCE_ENDPOINTS        : 'component',
    RESOURCE_INTERFACES       : 'interface',
    RESOURCE_NETWORK_INSTANCES: 'network_instance',
    RESOURCE_ROUTING_POLICIES : 'routing_policy',
    RESOURCE_ACL              : 'acl',
}

RESOURCE_PARSERS = {
    'component'       : parse_endpoints,
    'interface'       : parse_interfaces,
    'network_instance': parse_network_instances,
    'routing_policy'  : parse_routing_policy,
    'interfaces/interface/state/counters': parse_counters,
    'acl'             : parse_acl,
}

LOGGER = logging.getLogger(__name__)
RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]')
RE_REMOVE_FILTERS_2 = re.compile(r'\/[a-z]+:')
EMPTY_CONFIG = '<config></config>'
EMPTY_FILTER = '<filter></filter>'
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)
    resource_key = RE_REMOVE_FILTERS.sub('', resource_key)
    resource_key = RE_REMOVE_FILTERS_2.sub('/', resource_key)
    resource_key = resource_key.replace('//', '')
    template_name = '{:s}/get.xml'.format(resource_key)
    template = JINJA_ENV.get_template(template_name)
    return '<filter>{:s}</filter>'.format(template.render().strip())

def parse(resource_key : str, xml_data : ET.Element):
    resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key)
    resource_key = RE_REMOVE_FILTERS.sub('', resource_key)
    resource_key = RE_REMOVE_FILTERS_2.sub('/', resource_key)
    resource_key = resource_key.replace('//', '')
    #resource_key_parts = resource_key.split('/')
    #if len(resource_key_parts) > 1: resource_key_parts = resource_key_parts[:-1]
    #resource_key = '/'.join(resource_key_parts)
    #resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key)
    parser = RESOURCE_PARSERS.get(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, vendor : Optional[str] = None
) -> 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, vendor=vendor).strip())
