# bash completion for composer-cli

__composer_cli_flags="-h --help -j --json -s --socket --log -a --api --test -V"

declare -A __composer_cli_cmds=(
  [compose]="list start start-ostree types status log cancel delete info metadata logs results image"
  [blueprints]="list show changes diff save delete depsolve push freeze tag undo workspace"
  [modules]="list"
  [projects]="list info"
  [sources]="list info add change delete"
  [help]=""
)

__composer_socket_ok() {
    [ -w "${COMPOSER_SOCKET:-/run/weldr/api.socket}" ]
}

__composer_blueprints() {
    __composer_socket_ok && composer-cli blueprints list
}

__composer_sources() {
    __composer_socket_ok && composer-cli sources list
}

__composer_compose_types() {
    __composer_socket_ok && composer-cli compose types
}

__composer_composes() {
    __composer_socket_ok && composer-cli compose list $@ | while read id rest; do echo $id; done
}

__word_in_list() {
    local w word=$1; shift
    for w in "$@"; do
        [ "$w" == "$word" ] && return 0
    done
    return 1
}

_composer_cli() {
    local cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
    local w="" wi=0 cmd="__NONE__" subcmd="__NONE__" cmd_cword=0

    # find the command and its subcommand
    for (( wi=0; wi < ${#COMP_WORDS[*]}; wi++ )); do
        if __word_in_list "${COMP_WORDS[wi]}" "${!__composer_cli_cmds[@]}"; then
            cmd="${COMP_WORDS[wi]}"
            subcmd="${COMP_WORDS[wi+1]}"
            cmd_cword=$((COMP_CWORD-wi))
            break
        fi
    done

    COMPREPLY=()

    if [ "$cmd_cword" -le 0 ]; then
        # No command yet, complete flags or commands
        case "$prev" in
            -s|--socket|--log)
                # If it's a flag that takes a filename, suggest filenames
                compopt -o filenames
                COMPREPLY=($(compgen -f -- "${cur}"))
            ;;
            -a|--api|--test)
                # If it's a flag that takes an arg we can't guess, don't suggest anything
                COMPREPLY=()
            ;;
            *)
                if [ "${cur:0:1}" == "-" ]; then
                    # Suggest flags if cur starts with '-'
                    COMPREPLY=($(compgen -W "${__composer_cli_flags}" -- "${cur}"))
                else
                    # Suggest commands if there isn't one already
                    COMPREPLY=($(compgen -W "${!__composer_cli_cmds[*]}" -- "${cur}"))
                fi
            ;;
        esac
    elif [ $cmd_cword == 1 ]; then
        # Complete the word after the command
        COMPREPLY=($(compgen -W "${__composer_cli_cmds[$cmd]} help" -- "${cur}"))
    elif [ $cmd_cword == 2 ]; then
        # Complete word(s) after subcommand
        case "$cmd:$subcmd" in
            compose:list)
                COMPREPLY=($(compgen -W "waiting running finish failed" -- "${cur}"))
            ;;
            *:list|*:help|compose:types)
                COMPREPLY=()
            ;;
            sources:info|sources:delete)
                COMPREPLY=($(compgen -W "$(__composer_sources)" -- "${cur}"))
            ;;
            sources:add|sources:change|blueprints:workspace|blueprints:push)
                compopt -o filenames
                COMPREPLY=($(compgen -f -- "${cur}"))
            ;;
            blueprints:freeze)
                COMPREPLY=($(compgen -W "$(__composer_blueprints) show save" -- "${cur}"))
            ;;
            compose:start|compose:start-ostree|blueprints:*)
                COMPREPLY=($(compgen -W "$(__composer_blueprints)" -- "${cur}"))
            ;;
            compose:cancel)
                COMPREPLY=($(compgen -W "$(__composer_composes running waiting)" -- "${cur}"))
            ;;
            compose:delete|compose:results|compose:metadata)
                COMPREPLY=($(compgen -W "$(__composer_composes finished failed)" -- "${cur}"))
            ;;
            compose:log*)
                COMPREPLY=($(compgen -W "$(__composer_composes running finished failed)" -- "${cur}"))
            ;;
            compose:image)
                COMPREPLY=($(compgen -W "$(__composer_composes finished)" -- "${cur}"))
            ;;
            compose:*)
                COMPREPLY=($(compgen -W "$(__composer_composes)" -- "${cur}"))
            ;;
        esac
    else
        # Complete words past the subcommand's argument (if appropriate)
        case "$cmd:$subcmd" in
            compose:delete)
                COMPREPLY=($(compgen -W "$(__composer_composes finished failed)" -- "${cur}"))
            ;;
            compose:start|compose:start-ostree)
                subpos="$subcmd:$cmd_cword"
                if [ "$cmd_cword" == 3 ]; then
                    COMPREPLY=($(compgen -W "$(__composer_compose_types)" -- "${cur}"))
                elif [ "$subpos" == "start:5" ] || [ "$subpos" == "start-ostree:7" ]; then
                    # If they have typed something looking like a path, use file completion
                    # otherwise suggest providers.
                    case "${cur}" in
                        */*)
                            compopt -o filenames
                            COMPREPLY=($(compgen -f -- "${cur}"))
                        ;;
                        *)
                            COMPREPLY=($(compgen -W "$(__composer_provider_list)" -- "${cur}"))
                        ;;
                    esac
                elif [ "$subpos" == "start:6" ] || [ "$subpos" == "start-ostree:8" ]; then
                    COMPREPLY=($(compgen -W "$(__composer_profile_list ${prev})" -- "${cur}"))
                fi
            ;;
            # TODO: blueprints:diff and blueprints:undo want commits
            blueprints:freeze|blueprints:save|blueprints:depsolve|blueprints:changes|blueprints:show)
                COMPREPLY=($(compgen -W "$(__composer_blueprints)" -- "${cur}"))
            ;;
            sources:info)
                COMPREPLY=($(compgen -W "$(__composer_sources)" -- "${cur}"))
            ;;
        esac
    fi
}

complete -F _composer_cli composer-cli
