#compdef machinectl
# SPDX-License-Identifier: LGPL-2.1-or-later

(( $+functions[__machinectl_get_images] )) ||
    __machinectl_get_images () {
        local -a flags
        if [[ $PREFIX == .* ]]; then flags=( --all ); fi
        machinectl --no-legend list-images $flags 2>/dev/null | {while read -r a b; do
            # escape : and \; do not interpret existing escape sequences
            printf -- "%s\n" ${a//(#b)(\\|:)/\\$match}
        done;}
    }

(( $+functions[_machinectl_images] )) ||
    _machinectl_images() {
        local -a _machines
        _machines=("${(fo)$(__machinectl_get_images)}")
        typeset -U _machines
        if [[ -n "$_machines" ]]; then
            _describe 'images' _machines
        else
            _message 'no images'
        fi
    }

(( $+functions[_machinectl_commands] )) || _machinectl_commands()
{
    local -a _machinectl_cmds
    _machinectl_cmds=(
        "list:List currently running VMs/containers"
        "status:Show VM/container status"
        "show:Show properties of one or more VMs/containers"
        "start:Start container as a service"
        "stop:Stop container (equal to poweroff)"
        "login:Get a login prompt on a VM/container"
        "shell:Invoke a shell (or other command) in a container"
        "enable:Enable automatic container start at boot"
        "disable:Disable automatic container start at boot"
        "poweroff:Power off one or more VMs/containers"
        "reboot:Reboot one or more VMs/containers"
        "terminate:Terminate one or more VMs/containers"
        "kill:Send signal to process or a VM/container"
        "copy-to:Copy files from the host to a container"
        "copy-from:Copy files from a container to the host"
        "bind:Bind mount a path from the host into a container"

        "list-images:Show available container and VM images"
        "image-status:Show image details"
        "show-image:Show properties of image"
        "edit:Edit settings of one or more VMs/containers"
        "cat:Show settings of one or more VMs/containers"
        "clone:Clone an image"
        "rename:Rename an image"
        "read-only:Mark or unmark image read-only"
        "remove:Remove an image"
        "set-limits:Set image or pool size limit (disk quota)"
        "clean:Remove hidden (or all) images"

        "pull-tar:Download a TAR container image"
        "pull-raw:Download a RAW container or VM image"
        "import-tar:Import a local TAR container image"
        "import-raw:Import a local RAW container or VM image"
        "import-fs:Import a local directory container image"
        "export-tar:Export a TAR container image locally"
        "export-raw:Export a RAW container or VM image locally"
        "list-transfers:Show list of downloads in progress"
        "cancel-transfer:Cancel a download"
    )

    if (( CURRENT == 1 )); then
        _describe -t commands 'machinectl command' _machinectl_cmds || compadd "$@"
    else
        local curcontext="$curcontext"
        local stop=0
        cmd="${${_machinectl_cmds[(r)$words[1]:*]%%:*}}"
        case $cmd in
        start|enable|disable)
            _machinectl_images ;;

        status|show|poweroff|reboot|terminate|kill)
            _sd_machines ;;

        login|shell)
            if (( CURRENT == 2 )); then _sd_machines
            else stop=1
            fi ;;

        copy-to|bind)
            if (( CURRENT == 2 )); then _sd_machines
            elif (( CURRENT == 3 )); then _files
            elif (( CURRENT == 4 )); then _message "path on container"
            else stop=1
            fi ;;

        copy-from)
            if (( CURRENT == 2 )); then _sd_machines
            elif (( CURRENT == 3 )); then _message "path on container"
            elif (( CURRENT == 4 )); then _files
            else stop=1
            fi ;;

        image-status|show-image|remove)
            _machinectl_images ;;

        edit|cat)
            if (( CURRENT == 2 )); then _machinectl_images
            else stop=1
            fi ;;

        clone|rename)
            if (( CURRENT == 2 )); then _machinectl_images
            elif (( CURRENT == 3 )); then _message "target image"
            else stop=1
            fi ;;

        read-only)
            if (( CURRENT == 2 )); then _machinectl_images
            elif (( CURRENT == 3 )); then _values 'read-only flag' 'true' 'false'
            else stop=1
            fi ;;

        set-limit)
            if (( CURRENT == 2 )); then _machinectl_images
            elif (( CURRENT == 3 )); then _message "size limit"
            else stop=1
            fi ;;

        pull-tar|pull-raw)
            if (( CURRENT == 2 )); then _message "${cmd#pull-} file URL"
            elif (( CURRENT == 3 )); then _message "target image"
            else stop=1
            fi ;;

        import-tar)
            if (( CURRENT == 2 )); then _files -g "*.(tar(|.(gz|bz2|xz|zst))|tgz|tbz2|txz|tzst)(.)"
            elif (( CURRENT == 3 )); then _message "target image"
            else stop=1
            fi ;;
        import-raw)
            if (( CURRENT == 2 )); then _files -g "*(.)"
            elif (( CURRENT == 3 )); then _message "target image"
            else stop=1
            fi ;;
        import-fs)
            if (( CURRENT == 2 )); then _files -/
            elif (( CURRENT == 3 )); then _message "target image"
            else stop=1
            fi ;;

        export-tar|export-raw)
            if (( CURRENT == 2 )); then _machinectl_images
            elif (( CURRENT == 3 )); then _files
            else stop=1
            fi ;;

        list*|clean|cancel-transfer)
            stop=1 ;;

        '')
            stop=1 ;;
        esac

        if (( stop )); then
            _message "no more options"
            return 1
        fi
    fi
}

_arguments \
    '(- *)'{-h,--help}'[Prints a short help text and exits.]' \
    '(- *)--version[Prints a short version string and exits.]' \
    '--no-pager[Do not pipe output into a pager.]' \
    '--no-legend[Do not show the headers and footers.]' \
    '--no-ask-password[Do not ask for system passwords.]' \
    '(-H --host)'{-H+,--host=}'[Operate on remote host.]:userathost:_sd_hosts_or_user_at_host' \
    '(-M --machine)'{-M+,--machine=}'[Operate on local container.]:machine:_sd_machines' \
    '(-p --property)'{-p+,--property=}'[Limit output to specified property.]:property:(Name Id Timestamp TimestampMonotonic Service Scope Leader Class State RootDirectory)' \
    '(-a --all)'{-a,--all}'[Show all properties.]' \
    '(-q --quiet)'{-q,--quiet}'[Suppress output.]' \
    '(-l --full)'{-l,--full}'[Do not ellipsize cgroup members.]' \
    '--kill-whom=[Whom to send signal to.]:killwhom:(leader all)' \
    '(-s --signal)'{-s+,--signal=}'[Which signal to send.]:signal:_signals' \
    '--read-only[Create read-only bind mount.]' \
    '--mkdir[Create directory before bind mounting, if missing.]' \
    '(-n --lines)'{-n+,--lines=}'[Number of journal entries to show.]:integer' \
    '(-o --output)'{-o+,--output=}'[Change journal output mode.]:output modes:_sd_outputmodes' \
    '--verify=[Verification mode for downloaded images.]:verify:(no checksum signature)' \
    '--force[Download image even if already exists.]' \
    '*::machinectl command:_machinectl_commands'
