#!/bin/bash -e

show_help() {
    echo "usage: lxd-state undo-mount-changes"
    echo "       lxd-state prepare-snap"
    echo "       lxd-state setup-proxy <INSTANCE-NAME>"
}

prepare_snap(){
    echo "lxd-state: installing lxd snap"
    snap install lxd --channel="$LXD_SNAP_CHANNEL"

    if tests.pkgs is-installed lxd; then
        echo "lxd-state: remove the lxd pkg (some images carry them) to ensure we use the snap"
        tests.pkgs remove lxd
    fi
    if tests.pkgs is-installed lxd-client; then
        echo "lxd-state: remove the lxd-client pkg (some images carry them) to ensure we use the snap"
        tests.pkgs remove lxd-client
    fi

    echo "lxd-state: initializing lxd"
    snap set lxd waitready.timeout=240
    lxd waitready
    lxd init --auto

    echo "lxd-state: setting up proxy for lxc"
    if [ -n "${http_proxy:-}" ]; then
        lxd.lxc config set core.proxy_http "$http_proxy"
        lxd.lxc profile set default environment.http_proxy "$http_proxy"
    fi
    if [ -n "${https_proxy:-}" ]; then
        lxd.lxc config set core.proxy_https "$https_proxy"
        lxd.lxc profile set default environment.https_proxy "$https_proxy"
    fi
    if [ -n "${no_proxy:-}" ]; then
        lxd.lxc profile set default environment.no_proxy "$no_proxy"
    fi

    # Set the default proxy configuration to the default profile
    write_default_proxy_config lxd_default_proxy.yaml
    lxd.lxc profile set default user.user-data "$(cat lxd_default_proxy.yaml)"
}

launch() {
    local name params remote image
    while [ $# -gt 0 ]; do
        case "$1" in
            --name)
                name=$2
                shift 2
                ;;
            --remote)
                remote=$2
                shift 2
                ;;
            --image)
                image=$2
                shift 2
                ;;
            --params)
                params=$2
                shift 2
                ;;
            *)
                "lxd-state: parameter \"$1\" not supported"
                exit 1
                ;;
        esac
    done

    if [ -z "$name" ]; then
        "lxd-state: instance name is required"
        exit 1
    fi

    if [ -z "$remote" ]; then
        remote="$(default_remote)"
    fi
    if [ -z "$image" ]; then
        image="$(default_image)"
    fi

    # shellcheck disable=SC2086
    lxc launch --quiet "${remote}:${image}" "$name" $params

    # wait for cloud-init to finish before doing any apt operations
    local ret=0
    cloud-init status --wait || ret=$?
    if [ "$ret" -ne 0 ] && [ "$ret" -ne 2 ]; then
        echo "cloud-init finished with error $ret"
        exit 1
    fi
}

default_remote() {
    # There isn't an official image for noble yet, let's use the community one
    remote=ubuntu
    # There isn't an official image for 25.10 yet, let's use the daily one
    if os.query is-ubuntu 25.10; then
        remote=ubuntu-daily
    fi
    echo "$remote"
}

default_image() {
    # shellcheck disable=SC1091
    . /etc/os-release && echo "$VERSION_ID"
}

write_default_proxy_config() {
    local proxy_file="${1:-lxd_default_proxy.yaml}"
    local snapd_https_proxy snapd_http_proxy snapd_no_proxy
    snapd_https_proxy="$https_proxy"
    snapd_http_proxy="$http_proxy"
    snapd_no_proxy="$no_proxy"

    if [ "${SNAPD_USE_PROXY:-}" = true ]; then
       snapd_https_proxy="$https_proxy"
       snapd_http_proxy="$http_proxy"
       snapd_no_proxy="$no_proxy"
    fi

    cat <<EOF > "$proxy_file"
#cloud-config
write_files:
- path: /etc/environment
  append: true
  content: |    
    HTTPS_PROXY="$snapd_https_proxy"
    HTTP_PROXY="$snapd_http_proxy"
    NO_PROXY="$snapd_no_proxy"
    https_proxy="$snapd_https_proxy"
    http_proxy="$snapd_http_proxy"
    no_proxy="$snapd_no_proxy"
EOF
}

main() {
    if [ $# -eq 0 ]; then
        show_help
        exit 0
    fi

    case "${1:-}" in
        -h|--help)
            show_help
            exit 0
            ;;
        undo-mount-changes)
            # Vanilla systems have /sys/fs/cgroup/cpuset without clone_children option.
            # Using LXD to create a container enables this option, as can be seen here:
            #
            # -37 32 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,cpuset
            # +37 32 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,cpuset,clone_children
            #
            # To restore vanilla state, disable the option now.
            if [ "$(mountinfo.query /sys/fs/cgroup/cpuset .fs_type)" = cgroup ]; then
                echo 0 > /sys/fs/cgroup/cpuset/cgroup.clone_children
            fi

            # Vanilla system have /sys/fs/cgroup/unified mounted with the nsdelegate
            # option which is available since kernel 4.13 Using LXD to create a
            # container disables this options, as can be seen here:
            #
            # -32 31 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup rw,nsdelegate
            # +32 31 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup rw
            #
            # To restore vanilla state, enable the option now, but only if the kernel supports that.
            # https://lore.kernel.org/patchwork/patch/803265/
            # https://github.com/systemd/systemd/commit/4095205ecccdfddb822ee8fdc44d11f2ded9be24
            # The kernel version must be made compatible with the strict version
            # comparison. I chose to cut at the "-" and take the stuff before it.
            if [ "$(mountinfo.query /sys/fs/cgroup/unified .fs_type)" = cgroup2 ] && "$TESTSTOOLS"/version-compare --strict "$(uname -r | cut -d- -f 1)" -ge 4.13; then
                mount -o remount,nsdelegate /sys/fs/cgroup/unified
            fi
            ;;
        prepare-snap)
                shift
                prepare_snap "$@"
            ;;
        launch)
                shift
                launch "$@"
            ;;
        default-remote)
                shift
                default_remote
            ;;
        default-image)
                shift
                default_image
            ;;
        *)
            echo "lxd-state: unknown command $*" >&2
            exit 1
            ;;
    esac
}

main "$@"
