#!/usr/bin/env python3

# This file is part of VM-Experiments.
# Licensed under the GPL-3.0-or-later. See LICENSE for details.

import subprocess
import sys
import os
import json
import shutil

downloads = "downloads/"
output = "output/"
chroot = "chroot/"
resources = "resources/"
installer_packages = "linux-image-amd64 grub-pc parted tar dosfstools util-linux e2fsprogs arch-install-scripts"
installer_amd64 = "http://deb.debian.org/debian/"
installer_amd64_name = "bookworm"
not_verbose = True
clean_tarballs = False


def command(command):
    result = subprocess.run(command, capture_output=not_verbose, text=True, shell=True)
    return result


# chroot associated functions
def prepare_chroot():
    command(f"sudo mount --bind /dev '{chroot}/dev'")
    command(f"sudo mount --bind /proc '{chroot}/proc'")
    command(f"sudo mount --bind /sys '{chroot}/sys'")
    command(f"sudo cp /etc/resolv.conf '{chroot}/etc/'")


def do_chroot_command(command_input):
    command(f"sudo chroot '{chroot}' /bin/bash -c '{command_input}'")


def close_chroot():
    command(f"sudo umount '{chroot}/dev'")
    command(f"sudo umount '{chroot}/proc'")
    command(f"sudo umount '{chroot}/sys'")


# handle rootfs image from internet
def rootfs_downloader(link, filename):
    os.chdir(downloads)
    command(f"wget -nc {link}")
    command(f"sudo tar -xzf {filename} -C '../{chroot}'")
    os.chdir("..")


def rootfs_creator(filename):
    os.chdir(output)
    command(f"sudo tar -czf {filename} -C '../{chroot}' .")
    os.chdir("..")


# packaging rootfs
def rootfs_package(identifier, scripts, extra_files):
    infile = f"{identifier}.tar.gz"
    outfile = f"{identifier}.iso"

    close_chroot()
    command(f"sudo rm -rf '{chroot}'")
    command(f"sudo mkdir '{chroot}'")

    command(
        f"sudo debootstrap --arch amd64 {installer_amd64_name} {chroot} {installer_amd64}"
    )
    command(f"sudo cp '{infile}' '{chroot}/rootfs.tar.gz'")
    if clean_tarballs:
        command(f"sudo rm '{infile}'")

    prepare_chroot()
    do_chroot_command("apt update")
    do_chroot_command(
        f"DEBIAN_FRONTEND=noninteractive apt install -y {installer_packages}"
    )
    do_chroot_command("mkdir -p /etc/systemd/system/getty@tty1.service.d/")
    do_chroot_command("touch /etc/systemd/system/getty@tty1.service.d/override.conf")
    do_chroot_command(
        'echo -e "[Service]\nExecStart=\nExecStart=/sbin/agetty --noclear --autologin root %I \\$TERM" | tee /etc/systemd/system/getty@tty1.service.d/override.conf'
    )
    do_chroot_command("systemctl daemon-reload")
    do_chroot_command("systemctl enable getty@tty1.service")
    do_chroot_command("echo 'localmachine' > /etc/hostname")
    close_chroot()

    command(f"sudo cp '{resources}/grub.cfg' '{chroot}/boot/grub/grub.cfg'")
    for script in scripts:
        result = script.split("/")[-1]
        command(f"sudo cp '{script}' '{chroot}/root/{result}'")
        command(f"echo './{result}' | sudo tee -a '{chroot}/root/.profile'")
        command(f"echo './{result}' | sudo tee -a '{chroot}/root/.bashrc'")

    command(f"echo 'umount -R /mnt' | sudo tee -a '{chroot}/root/.profile'")
    command(f"echo 'umount -R /mnt' | sudo tee -a '{chroot}/root/.bashrc'")
    command(f"echo 'reboot' | sudo tee -a '{chroot}/root/.profile'")
    command(f"echo 'reboot' | sudo tee -a '{chroot}/root/.bashrc'")

    if shutil.which("grub-mkrescue"):
        command(f"sudo grub-mkrescue -o '{outfile}' '{chroot}'")
    elif shutil.which("grub2-mkrescue"):
        command(f"sudo grub2-mkrescue -o '{outfile}' '{chroot}'")

    command(f"sudo chown $(logname):$(logname) {outfile}")


# distro specific
def download_rootfs_prepare(
    download_link,
    download_name,
    packages,
    repositories,
    replace_repositories,
    keyrings,
    identifier,
    create_ca,
    preinstall_scripts,
    scripts,
    package_manager,
    extra_files,
):
    rootfs_downloader(download_link, download_name)
    apt_rootfs_prepare(
        repositories,
        replace_repositories,
        packages,
        identifier,
        create_ca,
        preinstall_scripts,
        scripts,
        extra_files,
    )


def debootstrap_rootfs_prepare(
    download_link,
    download_name,
    packages,
    repositories,
    replace_repositories,
    keyrings,
    identifier,
    create_ca,
    preinstall_scripts,
    scripts,
    package_manager,
    extra_files,
):
    command(f"sudo debootstrap --arch amd64 {download_name} {chroot} {download_link}")
    apt_rootfs_prepare(
        repositories,
        replace_repositories,
        keyrings,
        packages,
        identifier,
        create_ca,
        preinstall_scripts,
        scripts,
        extra_files,
    )


def apt_rootfs_prepare(
    repositories,
    replace_repositories,
    keyrings,
    packages,
    identifier,
    create_ca,
    preinstall_scripts,
    scripts,
    extra_files,
):
    prepare_chroot()

    if replace_repositories:
        overwritten = False
    else:
        overwritten = True

    for repository in repositories:
        if overwritten:
            do_chroot_command(f"echo '{repository}' >>/etc/apt/sources.list")
        else:
            do_chroot_command(f"echo '{repository}' >/etc/apt/sources.list")
            overwritten + True

    for extra_file in extra_files:
        command(f"sudo cp '{extra_file}' '{chroot}/root'")

    do_chroot_command("apt update -y")
    do_chroot_command("apt full-upgrade -y")
    do_chroot_command(f"DEBIAN_FRONTEND=noninteractive apt install -y {packages}")
    do_chroot_command("echo 'localmachine' > /etc/hostname")

    for preinstall_script in preinstall_scripts:
        command(f"sudo cp {preinstall_script} {chroot}/root")
        file_name = preinstall_script.split("/")[-1]
        do_chroot_command(f"cd root && ./{file_name}")

    if create_ca:
        command(f"sudo cp {chroot}/etc/ssl/certs/ca.crt {output}")

    close_chroot()
    rootfs_creator(f"{identifier}.tar.gz")
    rootfs_package(f"{output}{identifier}", scripts, extra_files)


# main
def main():
    global not_verbose
    global clean_tarballs

    for index, arg in enumerate(sys.argv):
        match arg:
            case "-v":
                not_verbose = False
            case "--verbose":
                not_verbose = False
            case "-ct":
                clean_tarballs = True
            case "--clean-tarballs":
                clean_tarballs = True
            case "-h":
                print("")
                print("Help for Linux Deployment Scripts:")
                print("")
                print("-h / --help - Shows this menu.")
                print(
                    "-v / --verbose - Displays the outputs of the different commands."
                )
                print(
                    "-ct / --clean-tarballs - Delete the tar.gz leftovers from the iso generation."
                )
                print("")
                exit()
            case "--help":
                clean_tarballs = True
            case _:
                if index == 0:
                    continue

                command(f"mkdir -p '{downloads}' '{output}'")
                command(f"sudo chown -R $(logname):$(logname) {downloads}")
                command(f"sudo chown -R $(logname):$(logname) {output}")
                close_chroot()
                command(f"sudo rm -rf '{chroot}'")
                command(f"sudo mkdir '{chroot}'")

                filename = arg
                data = json.load(open(filename, "r"))

                rootfs_type = data["rootfs_type"]
                download_link = data["download_link"]
                download_name = data["download_name"]
                packages = data["packages"]
                repositories = data["repositories"]
                replace_repositories = bool(data["replace_repositories"])
                keyrings = data["keyrings"]
                identifier = data["identifier"]
                scripts = data["scripts"]
                package_manager = data["package_manager"]
                extra_files = data["extra_files"]
                create_ca = bool(data["create_ca"])
                preinstall_scripts = data["preinstall_scripts"]

                match rootfs_type:
                    case "download":
                        download_rootfs_prepare(
                            download_link,
                            download_name,
                            packages,
                            repositories,
                            replace_repositories,
                            keyrings,
                            identifier,
                            create_ca,
                            preinstall_scripts,
                            scripts,
                            package_manager,
                            extra_files,
                        )
                    case "debootstrap":
                        debootstrap_rootfs_prepare(
                            download_link,
                            download_name,
                            packages,
                            repositories,
                            replace_repositories,
                            keyrings,
                            identifier,
                            create_ca,
                            preinstall_scripts,
                            scripts,
                            package_manager,
                            extra_files,
                        )

    close_chroot()
    command(f"sudo rm -rf '{chroot}'")


main()