#!/bin/bash
#
# Copyright(C) 2024 @ ZENETYS
# This script is licensed under MIT License (http://opensource.org/licenses/MIT)
#

for ES_CONFIG in ~/.es "${ES_CONFIG:-/etc/logcenter/es.conf}"; do
    if [[ -r $ES_CONFIG ]]; then
        source "$ES_CONFIG"
        break
    fi
done

# Wrapper to simulate curl --fail-with-body for old versions of curl.
# Note: stderr error message get printed after curl output otherwise we
# would have to use a buffer or a temporary file to store output.
function curl_fail_body() {
    local retval status_code
    exec 99>&1 || { echo "$FUNCNAME: cannot open fd" >&2; return 1; }
    status_code=$(curl "$@" -w '%{http_code}\n' -o /proc/self/fd/99)
    retval=$?
    exec 99>&-
    if (( status_code >= 400 )); then
        echo "$FUNCNAME: (22) The requested URL returned error: $status_code" >&2
        return 22
    fi
    return "$retval"
}

# Usage: es-curl [URI] [CURLOPTS]...
#
# URI logic:
#   - if URI does not include ://, $ES_BASE is used (eg: https://es-vip:9200)
#   - if $ES_BASE is not set, it is constructed with the following logic:
#     - protocol https is used, unless $ES_PROTO is set
#     - host 127.0.0.1 is used, unless $ES_HOST is set
#     - port 9200 is used, unless ES_PORT is set
#   - if the first parameter begins with - (dash), we assume it is a curl
#     option and URI / is used as default
#
# netrc logic:
#   - if $ES_NETRC is set, pass --netrc-file $ES_NETRC to curl if not empty
#   - otherwise if ~/.netrc.es exists, pass --netrc-file ~/.netrc.es to curl
#   - otherwise if ~/.netrc exists, pass --netrc and --netrc-optional to curl
#
# curl insecure logic
#   - if $ES_CACERT is set, pass --cacert $ES_CACERT to curl if not empty
#   - otherwise if $ES_INSECURE is not set or set to 1, pass -k to curl
#
function es-curl() {
    local i curl_bin= curl_opts url cmd

    # allow overriding of ES_* config variables by their ES_LOCAL_* counterparts
    for i in ${!ES_LOCAL_*}; do declare -a "${i/_LOCAL}=( \"\${$i[@]}\" )"; done

    curl_opts=(
        -sS --connect-timeout "${ES_CURL_CONNECT_TIMEOUT:-10}"
        ${ES_API_KEY:+-H "Authorization: ApiKey $ES_API_KEY"}
    )

    if [[ -z "${ES_CURL_FAIL_WITH_BODY+defined}" || "$ES_CURL_FAIL_WITH_BODY" == '1' ]]; then
        curl_opts+=( --fail-with-body )
    elif [[ -z "${ES_CURL_FAIL+defined}" || "$ES_CURL_FAIL" == '1' ]]; then
        curl_opts+=( -f )
    elif [[ "$ES_CURL_FAIL" == '2' ]]; then
        curl_bin=curl_fail_body
    fi

    if [[ -n "${ES_CACERT+defined}" ]]; then
        [[ -n $ES_CACERT ]] && curl_opts+=( --cacert "$ES_CACERT" )
    elif [[ -z "${ES_INSECURE+defined}" || "$ES_INSECURE" == '1' ]]; then
        curl_opts+=( -k )
    fi

    if [[ -n "${ES_NETRC+defined}" ]]; then
        [[ -n $ES_NETRC ]] && curl_opts+=( --netrc-file "$ES_NETRC" )
    elif [[ -r ~/.netrc.es ]]; then
        curl_opts+=( --netrc-file ~/.netrc.es )
    elif [[ -r ~/.netrc ]]; then
        curl_opts+=( --netrc --netrc-optional )
    fi

    # Cheap workaound to call curl with -H 'Content-Type: application/json' by
    # default, but allowing callers to pass a custom Content-Type header in
    # arguments, eg: application/x-ndjson for bulk requests on some versions.
    [[ "${@,,}" == *content-type:* ]] ||
        curl_opts+=( -H 'Content-Type: application/json' )

    if [[ $1 == *://* ]]; then
        url=$1
        shift
    else
        if [[ -n $ES_BASE ]]; then
            url=$ES_BASE
        else
            url="${ES_PROTO:-https}://${ES_HOST:-127.0.0.1}:${ES_PORT:-9200}"
        fi
        [[ ${1:0:1} != '/' ]] && url+='/'
        [[ ${1:0:1} != '-' ]] && { url+=$1; shift; }
    fi

    cmd=( "${curl_bin:-curl}" "${curl_opts[@]}" "${ES_CURL_OPTS[@]}" "$@" "$url" )
    [[ -n $ES_DEBUG ]] && echo "DEBUG: es-curl: ${cmd[*]@Q}" >&2
    "${cmd[@]}"
}

function kbn-curl() {
    [[ -z $KBN_PORT ]] && local KBN_PORT=5601
    local KBN_CURL_OPTS+=( "${KBN_CURL_OPTS[@]}" -H 'kbn-xsrf: true' )
    # Kibana mode: KBN_* variables override ES_* ones
    for i in ${!KBN_*}; do declare -a "${i/KBN_/ES_}=( \"\${$i[@]}\" )"; done
    es-curl "$@"
}

# done when sourced
(return 0 2>/dev/null) && return 0
# also skip when piped to bash
PROGNAME=${0##*/}
if declare -F -f "$PROGNAME" >/dev/null; then
    if [[ -z $ES_BASH_CMD ]]; then
        "$PROGNAME" "$@"
    else
        # custom bash / run on remote host
        declare -a "ES_BASH_CMD=( $ES_BASH_CMD )"
        {   cat "$0"
            if [[ -n $ES_SEND_ENV ]]; then
                ES_ENV_FORWARDED=1
                declare -p ${!ES_*} ${!KBN_*} |grep -v ES_BASH_CMD
            fi
            cmd=( "$PROGNAME" "$@" )
            declare -p cmd
            echo '"${cmd[@]}"'
            [[ -t 0 ]] || cat
        } | "${ES_BASH_CMD[@]}"
    fi
elif [[ ! $PROGNAME =~ ^-?bash$ ]]; then
    echo "FATAL: es-curl: Unsupported function $PROGNAME" >&2
    exit 2
fi
