#!/usr/bin/python3
import glob
import os
import re
import subprocess
import sys
from collections import defaultdict

JUST_DIR = "/usr/share/blossomos"
JUSTFILE = "/tmp/adjust"

group_re = re.compile(r'\[group\("(.+?)"\)\]')
recipe_re = re.compile(r"^([a-zA-Z0-9_\-]+)(.*):\s*$")
comment_re = re.compile(r"^#(?!!)(.*)$")

# colors
BLUE = "\033[1;34m"
CYAN = "\033[1;36m"
GREEN = "\033[1;32m"
YELLOW = "\033[1;33m"
DIM = "\033[2m"
BOLD = "\033[1m"
RESET = "\033[0m"


def setup_scripts(parts):
    dst = "/tmp/scripts"
    os.makedirs(dst, exist_ok=True)
    for path in parts:
        src = os.path.join(os.path.dirname(path), "scripts")
        if not os.path.isdir(src):
            continue
        for name in os.listdir(src):
            link = os.path.join(dst, name)
            target = os.path.join(src, name)
            if os.path.islink(link):
                os.unlink(link)
            if not os.path.exists(link):
                os.symlink(target, link)


def assemble():
    parts = sorted(glob.glob(f"{JUST_DIR}/**/*.just", recursive=True))
    setup_scripts(parts)
    with open(JUSTFILE, "w") as out:
        for path in parts:
            with open(path) as f:
                out.write(f.read())
            out.write("\n")
    return parts


def parse_all(parts):
    all_groups = defaultdict(list)
    for path in parts:
        default_group = os.path.splitext(os.path.basename(path))[0]
        current_group = default_group
        last_comment = ""

        with open(path) as f:
            for line in f:
                line = line.rstrip()

                g = group_re.search(line)
                if g:
                    current_group = g.group(1)
                    continue

                c = comment_re.search(line)
                if c:
                    last_comment = c.group(1).strip()
                    continue

                r = recipe_re.match(line)
                if r:
                    name = r.group(1)
                    params = r.group(2).strip()
                    all_groups[current_group].append(
                        {
                            "name": name,
                            "params": params,
                            "desc": last_comment,
                            "private": name.startswith("_"),
                        }
                    )
                    last_comment = ""

    return all_groups


def print_table(groups):
    print(f"{BLUE}{BOLD}adjust system commands{RESET}\n")

    for group, items in groups.items():
        print(f"{CYAN}{BOLD}{group}{RESET}")
        print(f"{DIM}{'-' * len(group)}{RESET}")
        print(f"{BOLD}{'Command':28} {'Params':20} Description{RESET}")

        for i in items:
            if i["private"] or i["name"] == "default":
                continue
            print(
                f"{GREEN}{i['name']:28}{RESET} "
                f"{YELLOW}{i['params'] or '':20}{RESET} "
                f"{i['desc'] or ''}"
            )

        print()


def run(args, namespaces):
    if args and args[0] in namespaces:
        args = args[1:]
    subprocess.run(["just", "--justfile", JUSTFILE, *args])


if __name__ == "__main__":
    parts = assemble()
    namespaces = {os.path.splitext(os.path.basename(p))[0] for p in parts}
    if len(sys.argv) == 1:
        print_table(parse_all(parts))
    else:
        run(sys.argv[1:], namespaces)
