#!/usr/bin/env python3

import json
import re
import subprocess
from os import environ
from pathlib import Path


def run(command, **kwargs):
    return subprocess.run(command, shell=True, check=True, **kwargs)


def cap_run(command, **kwargs):
    return run(
        command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, **kwargs
    ).stdout.strip()


def rpm_ostree_packages(output_dir):
    out = cap_run("rpm-ostree status --json")
    json_out = json.loads(out)

    deployments = json_out["deployments"]
    booted_deployment = deployments[0]

    if not booted_deployment["booted"]:
        for depl in deployments:
            if depl["booted"]:
                booted_deployment = depl
                break

    removals = booted_deployment["requested-base-removals"]
    additions = booted_deployment["requested-packages"]

    file = output_dir / "rpm-ostree.sh"
    with file.open("w") as f:
        f.write("rpm-ostree override remove")
        for removal in removals:
            f.write(" " + removal)

        f.write("\nrpm-ostree install")
        for addition in additions:
            f.write(" " + addition)


def flatpak_packages(output_dir):
    out = cap_run("flatpak list --app --columns=application")
    apps = out.split()

    file = output_dir / "flatpak.sh"
    with file.open("w") as f:
        f.write("flatpak install")
        for app in apps:
            f.write(" " + app)


def cargo_packages(output_dir):
    out = cap_run("cargo install --list")

    pattern = r"(.+) .+:.*"
    crates = re.findall(pattern, out)

    file = output_dir / "cargo.sh"
    with file.open("w") as f:
        f.write("cargo install")
        for crate in crates:
            f.write(" " + crate)


def npm_packages(output_dir):
    out = cap_run("npm list --json --location=global")
    json_out = json.loads(out)
    deps = json_out["dependencies"].keys()
    deps = [dep for dep in deps if dep != "npm"]

    file = output_dir / "npm.sh"
    with file.open("w") as f:
        f.write("npm config set prefix '~/.npm-global'\n")
        f.write("npm install --location=global npm\n")
        f.write("~/.npm-global/bin/npm install --location=global")
        for dep in deps:
            f.write(" " + dep)


def pipx_packages(output_dir):
    out = cap_run("pipx list --json")
    json_out = json.loads(out)

    venvs = json_out["venvs"]

    packages = []
    injections = {}
    for ind, venv_key in enumerate(venvs.keys()):
        metadata = venvs[venv_key]["metadata"]
        package = metadata["main_package"]["package_or_url"]
        packages.append(package)

        package_injections = metadata["injected_packages"].keys()
        if len(package_injections) > 0:
            injections[package] = package_injections

    file = output_dir / "pipx.sh"
    with file.open("w") as f:
        for package in packages:
            f.write(f"pipx install {package}\n")

        f.write("\n")

        for package in injections.keys():
            for injection in injections[package]:
                f.write(f"pipx inject {package} {injection}\n")


def main():
    output_dir = Path(f"{environ['HOME']}/bk/installed_packages_info")
    output_dir.mkdir(parents=True, exist_ok=True)

    rpm_ostree_packages(output_dir)

    flatpak_packages(output_dir)

    pipx_packages(output_dir)

    cargo_packages(output_dir)

    # npm_packages(output_dir)


if __name__ == "__main__":
    main()