# Copyright (C) 2018-2019  The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information

import os
import xml.parsers.expat

import xmltodict

from swh.indexer.codemeta import CROSSWALK_TABLE, SCHEMA_URI

from .base import DictMapping, SingleFileMapping


class MavenMapping(DictMapping, SingleFileMapping):
    """
    dedicated class for Maven (pom.xml) mapping and translation
    """

    name = "maven"
    filename = b"pom.xml"
    mapping = CROSSWALK_TABLE["Java (Maven)"]
    string_fields = ["name", "version", "description", "email"]

    def translate(self, content):
        try:
            d = xmltodict.parse(content).get("project") or {}
        except xml.parsers.expat.ExpatError:
            self.log.warning("Error parsing XML from %s", self.log_suffix)
            return None
        except UnicodeDecodeError:
            self.log.warning("Error unidecoding XML from %s", self.log_suffix)
            return None
        except (LookupError, ValueError):
            # unknown encoding or multi-byte encoding
            self.log.warning("Error detecting XML encoding from %s", self.log_suffix)
            return None
        metadata = self._translate_dict(d, normalize=False)
        metadata[SCHEMA_URI + "codeRepository"] = self.parse_repositories(d)
        metadata[SCHEMA_URI + "license"] = self.parse_licenses(d)
        return self.normalize_translation(metadata)

    _default_repository = {"url": "https://repo.maven.apache.org/maven2/"}

    def parse_repositories(self, d):
        """https://maven.apache.org/pom.html#Repositories

        >>> import xmltodict
        >>> from pprint import pprint
        >>> d = xmltodict.parse('''
        ... <repositories>
        ...   <repository>
        ...     <id>codehausSnapshots</id>
        ...     <name>Codehaus Snapshots</name>
        ...     <url>http://snapshots.maven.codehaus.org/maven2</url>
        ...     <layout>default</layout>
        ...   </repository>
        ... </repositories>
        ... ''')
        >>> MavenMapping().parse_repositories(d)
        """
        repositories = d.get("repositories")
        if not repositories:
            results = [self.parse_repository(d, self._default_repository)]
        elif isinstance(repositories, dict):
            repositories = repositories.get("repository") or []
            if not isinstance(repositories, list):
                repositories = [repositories]
            results = [self.parse_repository(d, repo) for repo in repositories]
        else:
            results = []
        return [res for res in results if res] or None

    def parse_repository(self, d, repo):
        if not isinstance(repo, dict):
            return
        if repo.get("layout", "default") != "default":
            return  # TODO ?
        url = repo.get("url")
        group_id = d.get("groupId")
        artifact_id = d.get("artifactId")
        if (
            isinstance(url, str)
            and isinstance(group_id, str)
            and isinstance(artifact_id, str)
        ):
            repo = os.path.join(url, *group_id.split("."), artifact_id)
            return {"@id": repo}

    def normalize_groupId(self, id_):
        """https://maven.apache.org/pom.html#Maven_Coordinates

        >>> MavenMapping().normalize_groupId('org.example')
        {'@id': 'org.example'}
        """
        if isinstance(id_, str):
            return {"@id": id_}

    def parse_licenses(self, d):
        """https://maven.apache.org/pom.html#Licenses

        >>> import xmltodict
        >>> import json
        >>> d = xmltodict.parse('''
        ... <licenses>
        ...   <license>
        ...     <name>Apache License, Version 2.0</name>
        ...     <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        ...   </license>
        ... </licenses>
        ... ''')
        >>> print(json.dumps(d, indent=4))
        {
            "licenses": {
                "license": {
                    "name": "Apache License, Version 2.0",
                    "url": "https://www.apache.org/licenses/LICENSE-2.0.txt"
                }
            }
        }
        >>> MavenMapping().parse_licenses(d)
        [{'@id': 'https://www.apache.org/licenses/LICENSE-2.0.txt'}]

        or, if there are more than one license:

        >>> import xmltodict
        >>> from pprint import pprint
        >>> d = xmltodict.parse('''
        ... <licenses>
        ...   <license>
        ...     <name>Apache License, Version 2.0</name>
        ...     <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
        ...   </license>
        ...   <license>
        ...     <name>MIT License</name>
        ...     <url>https://opensource.org/licenses/MIT</url>
        ...   </license>
        ... </licenses>
        ... ''')
        >>> pprint(MavenMapping().parse_licenses(d))
        [{'@id': 'https://www.apache.org/licenses/LICENSE-2.0.txt'},
         {'@id': 'https://opensource.org/licenses/MIT'}]
        """

        licenses = d.get("licenses")
        if not isinstance(licenses, dict):
            return
        licenses = licenses.get("license")
        if isinstance(licenses, dict):
            licenses = [licenses]
        elif not isinstance(licenses, list):
            return
        return [
            {"@id": license["url"]}
            for license in licenses
            if isinstance(license, dict) and isinstance(license.get("url"), str)
        ] or None
