import shutil
import tempfile
import zipfile
from pathlib import Path

from dev_tools.build.licensing.common import Dependency
from dev_tools.build.licensing.resources import licensing_resource_path


def _parse_lib(lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url):
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_uvloop(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "MIT"  # dual licensed; choose Apache over MIT license
    assert (dist_info_dir / "LICENSE-APACHE").is_file()
    license_name = "Apache 2"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_setuptools(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "UNKNOWN"  # license metadata is not properly set-up
    license_name = "MIT"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_lxml(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_packaging(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD-2-Clause or Apache-2.0"  # choose Apache
    license_name = "Apache-2.0"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_zipp(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "UNKNOWN"  # license metadata is not properly set-up
    license_name = "MIT"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_importlib_metadata(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "UNKNOWN"  # license metadata is not properly set-up
    license_name = "Apache-2.0"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_idna(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD-3-Clause"
    assert license_text is None  # missing from distribution package
    license_text = licensing_resource_path("idna_license").read_text(
        encoding="utf-8"
    )  # copied from the project's repo
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_psutil(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_orjson(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "Apache-2.0 OR MIT"  # choose Apache
    license_name = "Apache-2.0"
    assert license_text is None  # missing from distribution package
    license_text = licensing_resource_path("orjson_license_apache_2").read_text(
        encoding="utf-8"
    )  # copied from the project's repo
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pep517(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name is None  # license metadata is not properly set-up
    license_name = "MIT"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_gcld3(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "UNKNOWN"  # license metadata is not properly set-up
    license_name = "Apache-2.0"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pycryptodome(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD, Public Domain"
    license_name = "BSD-2-Clause"  # simplify
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pycparser(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pyzmq(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "LGPL+BSD"  # license metadata is not exact
    license_name = "BSD-4-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pywin32(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "PSF"
    assert license_text is None
    license_text = (lib_path / "win32com/License.txt").read_text(encoding="utf-8")
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_clarabot_crypto(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "UNKNOWN"  # not yet finalized
    license_text = license_name = "Clarabot Limited Review License"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_numpy(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_passlib(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_zxcvbn(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "MIT"
    assert license_text is None  # missing from distribution package
    license_text = licensing_resource_path("zxcvbn_license").read_text(
        encoding="utf-8"
    )  # copied from the project's repo
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_colorama(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_pillow(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "HPND"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_babel(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name == "BSD"  # license metadata is not exact
    license_name = "BSD-3-Clause"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_tomli(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name is None  # license metadata is not exact
    license_name = "MIT"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_typing_extensions(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name is None  # license metadata is not properly set-up since version 4.0
    license_name = "PSF"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def _parse_lib_argon2_cffi(
    lib_path: Path, dist_info_dir: Path, name, license_name, license_text, author, author_email, home_url
):
    assert license_name is None  # license metadata is not exact
    license_name = "MIT"
    return Dependency(name, license_name, license_text, author, author_email, home_url)


def parse_dist_info_dependency(lib_path: Path, dist_info_dir: Path):
    if (dist_info_dir / "METADATA").is_file():
        meta = (dist_info_dir / "METADATA").read_text(encoding="utf-8")
    elif (dist_info_dir / "PKG-INFO").is_file():
        meta = (dist_info_dir / "PKG-INFO").read_text(encoding="utf-8")
    else:
        Exception(f"not meta {dist_info_dir}")
    dependency_init_arg_names = ["Name", "License", "Author", "Author-email", "Home-page"]
    dependency_init_arg_values = [None] * len(dependency_init_arg_names)
    for line in meta.replace("\r", "").split("\n"):
        for i, attr in enumerate(dependency_init_arg_names):
            if line.startswith(f"{attr}: "):
                assert dependency_init_arg_values[i] is None
                dependency_init_arg_values[i] = line[len(attr) + 2 :].strip()
                break
        if all(dependency_init_arg_values):
            break
    assert dependency_init_arg_values[0], "%s %s" % (dist_info_dir, dependency_init_arg_values)
    for name in [
        "LICENSE.txt",
        "LICENSE",
        "LICENSE.rst",
        "COPYING",
        "LICENSES.txt",
        "LICENSE-APACHE",
        "COPYING.BSD",
        "LICENSE-MIT",
    ]:
        try:
            license_text = (dist_info_dir / name).read_text(encoding="utf-8")
            break
        except FileNotFoundError:
            pass
    else:
        license_text = None
    dependency_init_arg_values.insert(2, license_text)
    parse_fn = globals().get(f"_parse_lib_{dependency_init_arg_values[0].lower().replace('-', '_')}", _parse_lib)
    return parse_fn(lib_path, dist_info_dir, *dependency_init_arg_values)


def get_dependencies_from_library_zip(lib_path):
    lib_zip_path = lib_path / "library.zip"
    deps = []
    d = tempfile.mkdtemp()
    try:
        with zipfile.ZipFile(lib_zip_path) as zf:
            zf.extractall(str(d))
        for item in Path(d).iterdir():
            if not item.is_dir():
                continue
            if item.name.endswith(".egg"):
                raise NotImplementedError()
            elif item.name.endswith(".dist-info"):
                deps.append(parse_dist_info_dependency(lib_path, item))
    finally:
        shutil.rmtree(d)
    return deps
