#!/usr/bin/python3

import os
import click
import toml
from moat.util import yprint, attrdict, to_attrdict
from pathlib import Path
from dparse.parser import RequirementsTXTLineParser as Parser
from dparse.dependencies import Dependency
import git
import datetime

def dep_str(dep, prefix="python3-"):
    if not isinstance(dep, Dependency):
        dep = Parser.parse(dep)
    r = f"\n  {prefix}{dep.name.replace('.','-').lower()}"
    if dep.specs:
        rr = ""
        for spec in dep.specs:
            op = spec.operator
            if op in {'<', '>'}:
                op += op
            elif op == "~=":
                op = ">="
            rr += r+f" ({op} {spec.version}),"
        return rr

    else:
        return r+","

@click.command()
@click.option("--no-deb",is_flag=True,help="use the current branch")
@click.option("-o","--overwrite",is_flag=True,help="ignore files in existing debian/ subdir")
def main(no_deb, overwrite):
    """
    Create a Debian subdirectory for a Python module described via
    a 'pyproject.toml' file.
    """
    repo=git.Repo(".")
    main = repo.active_branch.name
    if not no_deb and main not in {"deb", "debian"}:
        print("Creating 'deb' branch")
        repo.git.checkout("HEAD", b="deb")

    tag=repo.git.describe(tags=True)
    i = tag.find("-")
    if i > -1:
        tag = tag[:i]
        print("Warning: not a pristine tagged version! Using", tag)
    now = datetime.datetime.now().astimezone().strftime("%a, %d %b %Y %T %z")

    try:
        with open("pyproject.toml","r") as tf:
            d = to_attrdict(toml.load(tf))
    except FileNotFoundError:
        raise UsageError("This is not a Python module, or it doesn't have a 'pyproject.toml' file.")
    # yprint(d)
    try:
        name = d.project.name
    except AttributeError:
        try:
            name = d.tool.poetry.name
        except AttributeError:
            name = d.tool.flit.metadata["dist-name"]

    named = name.replace(".","-").lower()

    try:
        maint = d.project.maintainers
    except AttributeError:
        maint = None
    if not maint:
        maint = [attrdict(name=os.environ["DEBFULLNAME"],email=os.environ["DEBEMAIL"])]

    try:
        depends = "".join(dep_str(x) for x in d.project["dependencies"])
    except (AttributeError,KeyError):
        depends = ""  # TODO
    try:
        dev_depends = d.project["optional-dependencies"]["dev"]
    except (AttributeError,KeyError):
        dev_depends = ""
    else:
        dev_depends = "".join(dep_str(x) for x in dev_depends)

    build_depends = ""
    try:
        deps = d["build-system"].requires
    except (AttributeError,KeyError):
        pass
    else:
        for dep in deps:
            dep = Parser.parse(dep)
            if dep.name == "flit_core":
                dep.name = "flit"
                build_depends += dep_str(dep, prefix="")
                build_depends += dep_str("flit-scm")
                continue
            elif dep.name == "setuptools-git-versioning":
                dep.name = "setuptools-scm"
            build_depends += dep_str(dep)

    deb=Path("debian")
    if deb.exists():
        if not overwrite:
            raise click.UsageError("'debian' subdirectory already exists. Exiting.")
    else:
        deb.mkdir()

    # TODO process .md and .rst files?
    readme = ""
    try:
        rmf = d.project.readme
    except AttributeError:
        try:
            rmf = d.tool.poetry.readme
        except AttributeError:
            try:
                rmf = d.tool.flit.metadata["description-file"]
            except AttributeError:
                for f in ("README.txt","README.md","README.rst"):
                    if os.path.exists(f):
                        rmf = f
                        break
                else:
                    raise RuntimeError("no README found") from None
    with open(rmf,"r") as rm:
        for n,l in enumerate(rm):
            readme += f"  {l.rstrip() or '.'}\n"
            if n>5 and not l.strip():
                break
    with open(deb/"rules","w") as f:
        f.write(f"""\
#!/usr/bin/make -f

# This file was automatically generated by toml2deb
# Thu, 16 Jul 2020 13:15:17 +0200
export PYBUILD_NAME={named}
%:
	dh $@ --with python3 --buildsystem=pybuild

override_dh_usrlocal:
	if test -d debian/python3-{named}/usr/local/bin/ ; then \\
	    mkdir -p debian/python3-{named}/usr/bin; \\
	    mv debian/python3-{named}/usr/local/bin/* debian/python3-{named}/usr/bin; \\
	fi

""")
    (deb/"rules").chmod(0o755)

    with open(deb/"compat","w") as f:
        f.write(f"""\
13
""")

    try:
        hp = d.project.urls.homepage
    except AttributeError:
        try:
            hp = d.tool.poetry.homepage
        except AttributeError:
            try:
                hp = d.tool.flit.metadata["home-page"]
            except AttributeError:
                try:
                    hp = d.project.urls["Source code"]
                except (AttributeError,KeyError):
                    hp = ""

    try:
        desc = d.project.description
    except AttributeError:
        try:
            desc = d.tool.poetry.description
        except AttributeError:
            desc,readme = readme.split("\n",1)
            desc = desc.strip()
    with open(deb/"control","w") as f:
        f.write(f"""\
Source: {named}
Maintainer: "{maint[0].name}" <{maint[0].email}>
Section: python
Priority: optional
Build-Depends: dh-python, python3-setuptools, python3-all, debhelper (>= 13),{dev_depends}{build_depends}
Standards-Version: 3.9.6
Homepage: {hp}

Package: python3-{named}
Architecture: all
Depends: ${{misc:Depends}}, ${{python3:Depends}},{depends}
Description: {desc}
{readme}
""")

    with open(deb/"changelog","w") as f:
        f.write(f"""\
{named} ({tag}-1) unstable; urgency=medium

  * Initial Debianization.

 -- {maint[0].name} <{maint[0].email}>  {now}
""")

    with open(deb/".gitignore","w") as f:
        f.write(f"""\
/files
/*.log
/*.debhelper
/*.debhelper-build-stamp
/*.substvars
/debhelper-build-stamp
/python3-{named}
""")
    repo.index.add(deb/"changelog")
    repo.index.add(deb/"compat")
    repo.index.add(deb/"rules")
    repo.index.add(deb/"control")
    repo.index.add(deb/".gitignore")
    if repo.is_dirty(index=True, working_tree=False, untracked_files=False, submodules=False):
        repo.index.commit("Debianized.")

    ign = Path(".gitignore")

    if not no_deb:
        repo.refs["main"].checkout()
        with ign.open("a") as f:
            f.write("\n# Debian packaging\n/debian/\n")
        repo.index.add(ign)
        repo.index.commit("Ignore Debian subdir")
        repo.refs["deb"].checkout()
        repo.index.commit("Debian ignore", parent_commits=(repo.heads.deb.commit, repo.heads.main.commit))
        repo.heads.main.checkout()

if __name__ == "__main__":
    main()

