#
# bash autocomplete, that can work with:
# a) --help of program
#
# Also you may like:
# $ bind "set completion-ignore-case on"
# $ bind "set show-all-if-ambiguous on"
#
# It uses bash-completion dynamic loader.

# Known to work with bash 3.* with programmable completion and extended
# pattern matching enabled (use 'shopt -s extglob progcomp' to enable
# these if they are not already enabled).
shopt -s extglob

export _CLICKHOUSE_COMPLETION_LOADED=1

CLICKHOUSE_logs_level=(
    none
    fatal
    error
    warning
    information
    debug
    trace
    test
)

CLICKHOUSE_QueryProcessingStage=(
    complete
    fetch_columns
    with_mergeable_state
    with_mergeable_state_after_aggregation
    with_mergeable_state_after_aggregation_and_limit
)

CLICKHOUSE_QueryKind=(
    initial_query
    secondary_query
    no_query
)

# SELECT name FROM system.formats ORDER BY name FORMAT LineAsString
CLICKHOUSE_Format=(
    Arrow
    ArrowStream
    Avro
    AvroConfluent
    BSONEachRow
    CSV
    CSVWithNames
    CSVWithNamesAndTypes
    CapnProto
    CustomSeparated
    CustomSeparatedIgnoreSpaces
    CustomSeparatedIgnoreSpacesWithNames
    CustomSeparatedIgnoreSpacesWithNamesAndTypes
    CustomSeparatedWithNames
    CustomSeparatedWithNamesAndTypes
    DWARF
    HiveText
    JSON
    JSONAsObject
    JSONAsString
    JSONColumns
    JSONColumnsWithMetadata
    JSONCompact
    JSONCompactColumns
    JSONCompactEachRow
    JSONCompactEachRowWithNames
    JSONCompactEachRowWithNamesAndTypes
    JSONCompactStrings
    JSONCompactStringsEachRow
    JSONCompactStringsEachRowWithNames
    JSONCompactStringsEachRowWithNamesAndTypes
    JSONEachRow
    JSONEachRowWithProgress
    JSONLines
    JSONObjectEachRow
    JSONStrings
    JSONStringsEachRow
    JSONStringsEachRowWithProgress
    LineAsString
    LineAsStringWithNames
    LineAsStringWithNamesAndTypes
    Markdown
    MsgPack
    MySQLDump
    MySQLWire
    NDJSON
    Native
    Null
    ODBCDriver2
    ORC
    One
    Parquet
    ParquetMetadata
    PostgreSQLWire
    Pretty
    PrettyCompact
    PrettyCompactMonoBlock
    PrettyCompactNoEscapes
    PrettyCompactNoEscapesMonoBlock
    PrettyJSONEachRow
    PrettyJSONLines
    PrettyMonoBlock
    PrettyNDJSON
    PrettyNoEscapes
    PrettyNoEscapesMonoBlock
    PrettySpace
    PrettySpaceMonoBlock
    PrettySpaceNoEscapes
    PrettySpaceNoEscapesMonoBlock
    Prometheus
    Protobuf
    ProtobufList
    ProtobufSingle
    RawBLOB
    Regexp
    RowBinary
    RowBinaryWithDefaults
    RowBinaryWithNames
    RowBinaryWithNamesAndTypes
    SQLInsert
    TSKV
    TSV
    TSVRaw
    TSVRawWithNames
    TSVRawWithNamesAndTypes
    TSVWithNames
    TSVWithNamesAndTypes
    TabSeparated
    TabSeparatedRaw
    TabSeparatedRawWithNames
    TabSeparatedRawWithNamesAndTypes
    TabSeparatedWithNames
    TabSeparatedWithNamesAndTypes
    Template
    TemplateIgnoreSpaces
    Values
    Vertical
    XML
)

function _clickhouse_bin_exist()
{ [ -x "$1" ] || command -v "$1" >& /dev/null; }

function _clickhouse_quote()
{
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

# Extract every option (everything that starts with "-") from the --help dialog.
function _clickhouse_get_options()
{
    local extra_args=()

    # By default client/local/benchmark --help will not print all settings, this is done only under --verbose
    case "$1" in
        *client*) extra_args+=(--verbose) ;;
        *local*) extra_args+=(--verbose) ;;
        *benchmark*) extra_args+=(--verbose) ;;
    esac

    "$@" --help "${extra_args[@]}" 2>&1 | LANG=c awk -F '[ ,=<>.]' '{ for (i=1; i <= NF; ++i) { if (substr($i, 1, 1) == "-" && length($i) > 1) print $i; } }' | sort -u
}

function _complete_for_clickhouse_generic_bin_impl()
{
    local prev=$1 && shift

    case "$prev" in
        -C|--config-file|--config)
            return 1
            ;;
        --stage)
            COMPREPLY=( $(compgen -W "${CLICKHOUSE_QueryProcessingStage[*]}" -- "$cur") )
            return 1
            ;;
        --query_kind)
            COMPREPLY=( $(compgen -W "${CLICKHOUSE_QueryKind[*]}" -- "$cur") )
            return 1
            ;;
        --send_logs_level)
            COMPREPLY=( $(compgen -W "${CLICKHOUSE_logs_level[*]}" -- "$cur") )
            return 1
            ;;
        --format|--input-format|--output-format)
            COMPREPLY=( $(compgen -W "${CLICKHOUSE_Format[*]}" -- "$cur") )
            return 1
            ;;
        --host)
            COMPREPLY=( $(compgen -A hostname -- "$cur") )
            return 1
            ;;
        # Argh...  This looks like a bash bug...
        # Redirections are passed to the completion function
        # although it is managed by the shell directly...
        '<'|'>'|'>>'|[12]'>'|[12]'>>')
            return 1
            ;;
    esac

    return 0
}

function _complete_for_clickhouse_generic_bin()
{
    local cur prev
    eval local cmd="$( _clickhouse_quote "$1" )"
    _clickhouse_bin_exist "$cmd" || return 0

    COMPREPLY=()
    _get_comp_words_by_ref cur prev

    if _complete_for_clickhouse_generic_bin_impl "$prev"; then
        COMPREPLY=( $(compgen -W "$(_clickhouse_get_options "$cmd")" -- "$cur") )
    fi

    return 0
}

function _complete_clickhouse_generic()
{
    local bin=$1 && shift
    local f=${1:-_complete_for_clickhouse_generic_bin}
    local o=(
        -o default
        -o bashdefault
        -o nospace
        -F "$f"
        "$bin"
    )
    complete "${o[@]}"
}

function _complete_clickhouse_bootstrap_main()
{
    local runtime=/usr/share/bash-completion/bash_completion
    if ! type _get_comp_words_by_ref >& /dev/null && [[ -f $runtime ]]; then
        source $runtime
    fi
    type _get_comp_words_by_ref >& /dev/null || return 0
}
_complete_clickhouse_bootstrap_main "$@"
