#!/usr/bin/python3

import os
import click
import tomllib
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")
@click.option("-m","--main",type=str,default="main",help="Branch to base the .deb on")
@click.option("-d","--debian","--deb",type=str,help="Name of the debian branch")
def main(no_deb, overwrite, main,debian):
    """
    Create a Debian subdirectory for a Python module described via
    a 'pyproject.toml' file.
    """
    if debian and no_deb:
        raise click.UsageError("To Deb or not to Deb, that is the question")
    if not no_deb and not debian:
        debian="deb"
    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","rb") as tf:
            d = to_attrdict(tomllib.load(tf))
    except FileNotFoundError:
        raise click.UsageError("This is not a Python module, or it doesn't have a 'pyproject.toml' file.")
    # yprint(d)
    names = [
            lambda d: d.project.name,
            lambda d: d.tool.poetry.name,
            lambda d: d.tool.flit.metadata["dist-name"],
            lambda d: d.tool.flit.metadata["module"],
            ]
    for la in names:
        try:
            name = la(d)
        except (KeyError, AttributeError):
            pass
        else:
            break
    else:
        name = Path(".").absolute().name


    named = name.replace(".","-").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
    if isinstance(rmf,dict):
        rmf=rmf["file"]
    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)

    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()
    ntag = tag
    if ntag.startswith("v"):
        ntag = ntag[1:]
    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),
  debhelper-compat (= 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} ({ntag}-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/"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.", skip_hooks=True)

    ign = Path(".gitignore")

    if not no_deb:
        try:
            repo.refs[main].checkout()
        except IndexError:
            raise click.UsageError(f"There is no {main!r} branch.") from None
        with ign.open("a") as f:
            f.write("\n# Debian packaging\n/debian/\n")
        repo.index.add(ign)
        repo.index.commit("Ignore Debian subdir", skip_hooks=True)
        repo.refs[debian].checkout()
        repo.index.commit("Debian ignore", parent_commits=(repo.heads[debian].commit, repo.heads[main].commit), skip_hooks=True)
        repo.heads[main].checkout()

if __name__ == "__main__":
    main()

