import collections
import datetime
import json
from lxml.etree import Element, SubElement, tostring
import os.path
import re
from subprocess import Popen, PIPE
import shlex

import salt.ext.six as six

from oscap import untangle


def normalize_id(id,
                 xccdf_version='1.2',
                 typeof='profile',
                 vendor='mirantis'):

    if xccdf_version == '1.2':
        if not re.match('^xccdf_[^_]+_{}_.+'.format(typeof), id):
            return 'xccdf_org.{0}.content_{1}_{2}'.format(vendor, typeof, id)
    return id


def build_tailoring(data, id):
    xccdf_version = data.get('xccdf_version', '1.2')
    ns = {None: 'http://checklists.nist.gov/xccdf/{}'.format(xccdf_version)}
    tid = normalize_id(id, xccdf_version, typeof='tailoring')
    pid = normalize_id(data['profile'], xccdf_version, vendor='customer')
    ext = normalize_id(data['extends'], xccdf_version)
    tailoring = Element('Tailoring', nsmap=ns, id=tid)
    tailoring.append(Element('benchmark', {'href': ext}))

    now = datetime.datetime.now().isoformat()
    SubElement(tailoring, 'version', time=now).text = '1'

    profile = SubElement(tailoring, 'Profile', id=pid, extends=ext)

    SubElement(profile, 'title').text = 'Extends {}'.format(ext)

    for key, value in six.iteritems(data.get('values', {})):
        idref = normalize_id(key, xccdf_version, typeof='value')
        elem = SubElement(profile, 'set-value', idref=idref)
        elem.text = str(value)
    return tostring(tailoring, pretty_print=True)


def run(cmd, cwd=None):
    # The Popen used here because the __salt__['cmd.run'] returns only stdout
    proc = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE, cwd=cwd)
    (stdout, stderr) = proc.communicate()
    return stdout, stderr, proc.returncode


def _get_flatten_groups(document, groups=None):
    groups = groups if groups else []
    if hasattr(document, 'Group'):
        for group in document.Group:
            groups.append(group)
            groups = _get_flatten_groups(group, groups)
    return groups


def _get_rules(groups):
    rules = {}
    for group in groups:
        if hasattr(group, 'Rule'):
            for rule in group.Rule:
                rules[rule['id']] = {
                    'title': rule.title.cdata,
                    'severity': rule['severity'],
                    'ident': rule.ident.cdata,
                    'description': rule.description.cdata}
    return rules


def _parse_xccdf_doc(document):
    groups = _get_flatten_groups(document.Benchmark)
    rules = _get_rules(groups)

    results = []
    for result in document.Benchmark.TestResult.rule_result:
        results.append({
            'rule': result['idref'],
            'result': result.result.cdata,
            'severity': result['severity'],
            'weight': result['weight'],
            'title': rules[result['idref']]['title'],
            'cis_code': rules[result['idref']]['ident'],
            'description': rules[result['idref']]['title']
        })

    return results


def _sanitize_xccdf_xml(data):
    data = data.replace(
        '<html:code xmlns:html="http://www.w3.org/1999/xhtml">', '')
    data = data.replace('</html:code>', '')
    data = data.replace(
        '<html:pre xmlns:html="http://www.w3.org/1999/xhtml">', '')
    data = data.replace('<html:pre>', '')
    data = data.replace('</html:pre>', '')
    data = data.replace('<html:code>', '')
    data = data.replace('<html:li>', '')
    data = data.replace('</html:li>', '')
    data = data.replace(
        '<html:pre xmlns:html="http://www.w3.org/1999/xhtml" '
        'xmlns:ns0="http://checklists.nist.gov/xccdf/1.1">',
        '')
    data = data.replace(
        '<html:br xmlns:html="http://www.w3.org/1999/xhtml"/>', '')
    data = data.replace(
        '<html:code xmlns:html="http://www.w3.org/1999/xhtml" '
        'xmlns:ns0="http://checklists.nist.gov/xccdf/1.1">',
        '')
    return data


def xccdf_xml_to_json(xml_file):
    with open(xml_file) as in_file:
        raw_xml = in_file.read()
    doc = untangle.parse(_sanitize_xccdf_xml(raw_xml))
    results = _parse_xccdf_doc(doc)
    with open(os.path.splitext(xml_file)[0] + '.json', 'w') as json_file:
        # NOTE(pas-ha) the src/com/mirantis/mk.Common.parseJSON method
        # from mk/pipeline-library that is used in our Jenkins pipelines
        # can not parse the string representation of a list!
        # only dict structure is supported as a top-level one there
        json.dump({"results": results}, json_file)


def _parse_oval_definitions(document):
    definitions = {}
    def_list = document.oval_results.oval_definitions.definitions.definition
    for definition in def_list:
        try:
            definitions[definition['id']] = {'class': definition['class']}
            def_dict = definitions[definition['id']]
            def_dict['title'] = definition.metadata.title.cdata
            def_dict['description'] = definition.metadata.description.cdata
            def_dict['ref_id'] = definition.metadata.reference['ref_id']
            def_dict['link'] = definition.metadata.reference['ref_url']
            def_dict['severity'] = definition.metadata.advisory.severity.cdata
        except (AttributeError, IndexError):
            # NOTE(e0ne): inventory  does't have some element
            pass

    return definitions


def oval_xml_to_json(xml_file):
    document = untangle.parse(xml_file)
    definitions = _parse_oval_definitions(document)
    results = []
    for defn in document.oval_results.results.system.definitions.definition:
        res = collections.defaultdict(lambda: None)
        res['id'] = defn['definition_id']
        res['result'] = defn['result']
        res.update(definitions[defn['definition_id']])
        results.append(res)
    with open(os.path.splitext(xml_file)[0] + '.json', 'w') as json_file:
        # NOTE(pas-ha) the src/com/mirantis/mk.Common.parseJSON method
        # from mk/pipeline-library that is used in our Jenkins pipelines
        # can not parse the string representation of a list!
        # only dict structure is supported as a top-level one there
        json.dump({"results": results}, json_file)
