#!/usr/bin/env python3

import configparser
import os
import pathlib
import subprocess
import time

import click

_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"


def _read_config() -> dict[str, str]:
    cp = configparser.ConfigParser()
    cp.read(_CONFIG_FILE)
    return dict(cp["defaults"]) if "defaults" in cp else {}


@click.command(
    context_settings={"ignore_unknown_options": True, "allow_extra_args": True}
)
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
@click.option(
    "--vm-name",
    default=None,
    help="LXD VM name (default: livefs-builder-{suite})",
)
@click.option(
    "--http-proxy",
    default=None,
    help="HTTP proxy URL for apt inside the VM (also read from build-livefs.conf)",
)
@click.option(
    "--output",
    "output_dir",
    default=None,
    type=click.Path(file_okay=False, path_type=pathlib.Path),
    help="Directory to copy build artifacts (livecd.*) into after the build",
)
@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
def main(suite, vm_name, http_proxy, output_dir, extra_args):
    livecd_rootfs_root = pathlib.Path(__file__).resolve().parent.parent
    vm_name = vm_name or f"livefs-builder-{suite}"
    host_conf = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"

    if http_proxy is None:
        http_proxy = _read_config().get("http-proxy")

    result = subprocess.run(["lxc", "info", vm_name], capture_output=True)
    if result.returncode != 0:
        launch_cmd = [
            "lxc",
            "launch",
            f"ubuntu-daily:{suite}",
            vm_name,
            "--vm",
            "--config",
            "limits.cpu=4",
            "--config",
            "limits.memory=8GiB",
            "--device",
            "root,size=100GiB",
        ]
        user_data = "#cloud-config\npackage_update: true\n"
        if http_proxy is not None:
            user_data += (
                "apt:\n"
                f"  http_proxy: {http_proxy}\n"
                f"  https_proxy: {http_proxy}\n"
            )
        launch_cmd += ["--config", f"user.user-data={user_data}"]
        subprocess.run(launch_cmd, check=True)

    device_info = subprocess.run(
        ["lxc", "config", "device", "show", vm_name],
        capture_output=True,
        text=True,
        check=True,
    ).stdout
    if "livecd-rootfs" not in device_info:
        subprocess.run(
            [
                "lxc",
                "config",
                "device",
                "add",
                vm_name,
                "livecd-rootfs",
                "disk",
                f"source={livecd_rootfs_root}",
                "path=/srv/livecd-rootfs",
            ],
            check=True,
        )

    info = subprocess.run(
        ["lxc", "info", vm_name], capture_output=True, text=True, check=True
    ).stdout
    if "Status: STOPPED" in info:
        subprocess.run(["lxc", "start", vm_name], check=True)

    for _ in range(30):
        result = subprocess.run(
            ["lxc", "exec", vm_name, "--", "true"], capture_output=True
        )
        if result.returncode == 0:
            break
        time.sleep(2)
    else:
        raise click.ClickException(f"VM {vm_name!r} did not become ready in time")

    subprocess.run(
        ["lxc", "exec", vm_name, "--", "cloud-init", "status", "--wait"], check=True
    )

    subprocess.run(
        ["lxc", "exec", vm_name, "--", "apt-get", "install", "-y", "livecd-rootfs"],
        check=True,
    )

    if host_conf.exists():
        subprocess.run(
            [
                "lxc",
                "exec",
                vm_name,
                "--",
                "mkdir",
                "-p",
                "/root/.config/livecd-rootfs",
            ],
            check=True,
        )
        subprocess.run(
            [
                "lxc",
                "file",
                "push",
                str(host_conf),
                f"{vm_name}/root/.config/livecd-rootfs/build-livefs.conf",
            ],
            check=True,
        )

    subprocess.run(
        ["lxc", "exec", vm_name, "--", "mkdir", "-p", "/build"],
        check=True,
    )

    subprocess.run(
        [
            "lxc",
            "exec",
            vm_name,
            "--cwd",
            "/build",
            "--",
            "/srv/livecd-rootfs/live-build/build-livefs",
            "--suite",
            suite,
            *extra_args,
        ],
        check=True,
    )

    if output_dir is not None:
        output_dir.mkdir(parents=True, exist_ok=True)
        # Match launchpad-buildd's gatherResults: files starting with "livecd."
        # in the build directory, excluding symlinks.
        listing = subprocess.run(
            [
                "lxc",
                "exec",
                vm_name,
                "--",
                "find",
                "/build",
                "-maxdepth",
                "1",
                "-type",
                "f",
                "-name",
                "livecd.*",
            ],
            capture_output=True,
            text=True,
            check=True,
        ).stdout
        for path in listing.splitlines():
            subprocess.run(
                [
                    "lxc",
                    "file",
                    "pull",
                    f"{vm_name}{path}",
                    output_dir / os.path.basename(path),
                ],
                check=True,
            )


if __name__ == "__main__":
    main()
