#! /usr/bin/env python3

import re
import sys
import argparse
import datetime
import tempfile
from pathlib import Path
from subprocess import run


def create_changelog(args) -> str:
    plugins_root = f"{args.root}/plugins"
    modules_root = f"{args.root}/plugins/python/share/modules"

    latest     = run(["git", "describe", "--tags", "--abbrev=0"], capture_output=True).stdout.decode().strip()

    albert_log = run(["git", "log", "--pretty=format:* %B", f"{latest}..dev"], capture_output=True).stdout.decode().strip()

    begin      = run(["git", "ls-tree", latest, plugins_root], capture_output=True).stdout.decode().strip().split()[2]
    plugin_log = run(["git", "-C", plugins_root, "log", "--pretty=format:* %B", f"{begin}..master"], capture_output=True).stdout.decode().strip()

    begin      = run(["git", "-C", plugins_root, "ls-tree", begin, modules_root], capture_output=True).stdout.decode().strip().split()[2]
    python_log = run(["git", "-C", modules_root, "log", "--pretty=format:* %B", f"{begin}..master"], capture_output=True).stdout.decode().strip()

    return f"[albert]\n{albert_log}\n\n[plugins]\n{plugin_log}\n\n[python]\n{python_log}"


def test_build(args):
    files = list((Path(args.root) / ".docker").iterdir())
    for i, f in enumerate(files):
        print(f"{i}: {f.name}")

    default = list(range(len(files)))
    indices = input(f"Which to build? [{' '.join(str(i) for i in default)}] ")
    indices = [int(s) for s in filter(None, indices.split())]
    indices = indices if indices else default
    for index in indices:
        tag = files[index].name.replace("Dockerfile", "albert")
        run(["docker", "build", "-t", tag, "-f", files[index], "."], cwd=args.root).check_returncode()


def release(args):

    root = Path(args.root)

    if args.version[0] == 'v':
        args.version = args.version[1:]

    import re
    if not re.match(r"^[0-9]+\.[0-9]+\.[0-9]+$", args.version):
        print("Expected version number as parameter: major.minor.patch")
        sys.exit(1)

    print("Don't forget to merge ready PRs.")
    print("Don't forget to updated the 'python' submodule in the Python plugin.")
    print("Don't forget to updated the 'plugins' submodule.")

    if "y".startswith(input("Shall I run a test build in docker? [Y/n] ").lower()):
        test_build(args)

    v = input("Confirm the version number: ")
    if args.version != (v[1:] if v[0] == 'v' else v):
        print("Version mismatch.")
        sys.exit(1)

    atomic_changelog = root/f"changelog_v{args.version}"

    with open(atomic_changelog, 'w') as file:
        file.write(create_changelog(args))

    print("Changelog created from git logs. Edit it to be meaningful to humans.")
    input("Press Enter to continue...")
    run(["vim", atomic_changelog]).check_returncode()

    with open(atomic_changelog, 'r') as file:
        changelog = file.read().strip()

    if "y".startswith(input("Create news post? [Y/n] ").lower()):
        if (root/"documentation").exists():
            run(["git", "pull"], cwd=root/"documentation").check_returncode()
        else:
            run(["git", "clone", "git://github.com/albertlauncher/documentation.git"], cwd=root).check_returncode()

        with open(f"documentation/src/_posts/{datetime.date.today().strftime('%Y-%m-%d')}-albert-v{args.version}-released.md", 'w') as file:
            file.write(f"""---
layout: page
title:  "Albert v{args.version} released"
date: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M%z")}
---

{changelog.strip()}

Check the GitHub repositories for details.
https://github.com/albertlauncher/albert/commits/v{args.version}
""")
        if "y".startswith(input("News post created. Build/Test/Publish it? [Y/n] ").lower()):
            run("./build_check_deploy.sh", cwd=root/"documentation").check_returncode()

    if "y".startswith(input("Update the changelog? [Y/n] ").lower()):
        with open(root/"CHANGELOG.md", 'r') as file:
            old_changelog = file.read()

        with open(root/"CHANGELOG.md", 'w') as file:
            file.write(f"v{args.version} ({datetime.date.today().strftime('%Y-%m-%d')})\n\n{changelog}\n\n{old_changelog}")

        print("Changelog updated.")

    run(["sed", "-i.bak", f"s/^project.*$/project(albert VERSION {args.version})/", root/"CMakeLists.txt"], cwd=root).check_returncode()
    print("Project version updated.")

    if "yes".startswith(input("Stage, commit, tag, rebase master and push? [yes/NO]").lower()):
        run(["git", "add", root/"CHANGELOG.md", root/"CMakeLists.txt"], cwd=root).check_returncode()
        run(["git", "commit", "-m", f"v{args.version}"], cwd=root).check_returncode()
        run(["git", "tag", f"v{args.version}"], cwd=root).check_returncode()
        run(["git", "rebase", "dev", "master"], cwd=root).check_returncode()
        run(["git", "push", "--tags", "--atomic", "origin", "dev", "master"], cwd=root).check_returncode()
    
    print("Clean up…")
    run(["rm", atomic_changelog])
    run(["rm", "CMakeLists.txt.bak"])



def main():
    p = argparse.ArgumentParser()
    sps = p.add_subparsers()

    sp = sps.add_parser('changelog', help='Create raw changelog.')
    sp.set_defaults(func=lambda args: print(create_changelog(args)))

    sp = sps.add_parser('test', help='Test build using docker.')
    sp.set_defaults(func=test_build)

    sp = sps.add_parser('release', help="Release a new version.")
    sp.add_argument('version', type=str, help="The sematic version.")
    sp.set_defaults(func=release)

    args = p.parse_args()
    if not hasattr(args, "func"):
        p.print_help()
        sys.exit(1)

    sha = run(["git", "rev-list", "--parents", "HEAD"], capture_output=True).stdout.decode().strip().split("\n")[-1]
    if sha != '4d409110b9771e688acbb995422541f03ef0d8a7':
        print("Working dir is not the albert repository")
        sys.exit(1)

    args.root = run(["git", "rev-parse", "--show-toplevel"], capture_output=True).stdout.decode().strip()

    try:
        args.func(args)
    except KeyboardInterrupt:
        print("\nBye.")


if __name__ == "__main__":
    main()
