import re

from jnpr.junos.facts.swver import version_info


def _get_swver(dev, facts):
    # See if we're VC Capable
    if facts["vc_capable"] is True:
        try:
            return dev.rpc.cli("show version all-members", format="xml")
        except:
            pass
    try:
        return dev.rpc.cli("show version invoke-on all-routing-engines", format="xml")
    except:
        return dev.rpc.get_software_information()


def facts_software_version(junos, facts):
    """
    The following facts are required:
        facts['master']

    The following facts are assigned:
        facts['hostname']
        facts['version']
        facts['version_<RE#>'] for each RE in dual-RE, cluster or VC system
        facts['version_info'] for master RE
    """

    x_swver = _get_swver(junos, facts)

    if not facts.get("model"):
        # try to extract the model from the version information
        facts["model"] = x_swver.findtext(".//product-model")

    # ------------------------------------------------------------------------
    # extract the version information out of the RPC response
    # ------------------------------------------------------------------------

    f_master = facts.get("master", "RE0")

    if x_swver.tag == "multi-routing-engine-results":
        # we need to find/identify each of the routing-engine (CPU) versions.
        if len(x_swver.xpath("./multi-routing-engine-item")) > 1:
            facts["2RE"] = True
        versions = []

        if isinstance(f_master, list):
            xpath = (
                './multi-routing-engine-item[re-name="{}"]/software-'
                "information/host-name".format(f_master[0].lower())
            )
        else:
            xpath = (
                './multi-routing-engine-item[re-name="{}"'
                "]/software-information/host-name".format(f_master.lower())
            )

        facts["hostname"] = x_swver.findtext(xpath)
        if facts["hostname"] is None:
            # then there the re-name is not what we are expecting; we should
            # handle this better, eh?  For now, just assume there is one
            # software-information element and take that host-name. @@@ hack.
            facts["hostname"] = x_swver.findtext(".//software-information/host-name")

        for re_sw in x_swver.xpath(".//software-information"):
            re_name = re_sw.xpath("preceding-sibling::re-name")[0].text

            # handle the cases where the "RE name" could be things like
            # "FPC<n>" or "ndoe<n>", and normalize to "RE<n>".
            re_name = re.sub(r"(\w+)(\d+)", "RE\\2", re_name)

            # First try the <junos-version> tag present in >= 15.1
            swinfo = re_sw.findtext("junos-version", default=None)
            if not swinfo:
                # For < 15.1, get version from the "junos" package.
                pkginfo = re_sw.xpath(
                    'package-information[normalize-space(name)="junos"]/comment'
                )[0].text
                try:
                    swinfo = re.findall(r"\[(.*)\]", pkginfo)[0]
                except:
                    swinfo = "0.0I0.0"
            versions.append((re_name.upper(), swinfo))

        # now add the versions to the facts <dict>
        for re_ver in versions:
            facts["version_" + re_ver[0]] = re_ver[1]

        if f_master is not None:
            master = f_master[0] if isinstance(f_master, list) else f_master
            if "version_" + master in facts:
                facts["version"] = facts["version_" + master]
            else:
                facts["version"] = versions[0][1]
        else:
            facts["version"] = versions[0][1]

    else:
        # single-RE
        facts["hostname"] = x_swver.findtext("host-name")

        # First try the <junos-version> tag present in >= 15.1
        swinfo = x_swver.findtext(".//junos-version", default=None)
        if not swinfo:
            # For < 15.1, get version from the "junos" package.
            pkginfo = x_swver.xpath(
                './/package-information[normalize-space(name)="junos"]/comment'
            )[0].text
            try:
                swinfo = re.findall(r"\[(.*)\]", pkginfo)[0]
            except:
                swinfo = "0.0I0.0"
        facts["version"] = swinfo

    # ------------------------------------------------------------------------
    # create a 'version_info' object based on the master version
    # ------------------------------------------------------------------------

    facts["version_info"] = version_info(facts["version"])
