#!/bin/bash

DEPLOY_STATE_DIR=/tmp/deploy-node-exporter
ADB=/usr/bin/bmc_adb

die() {
    echo "error: $*"
    exit 1
} >&2

msg() {
    echo "    $*"
}

usage() {
    cat <<EOF
Usage:

    bmc list [--offline] [<pattern>]
        List all the active nodes usable with adb, optionally matched by pattern

    bmc state
        List the state of all the boards.

    bmc serials
        List all the active nodes with coresponding adb serial.

    bmc <node> {reset|poweron|poweroff}
        Invoke reset, poweron or power off on <node>

    bmc <node> loader
        Forced to Rockchip loader mode by hardware.

    bmc <node> state
        Show node state

    bmc <node> shell [<command>...]
        Invoke shell with command.

    bmc <node> reboot
        Reboot device.

    bmc forall <command> %{node}
EOF
} >&2

api_get() {
    curl -s http://127.0.0.1:7070/api/$1
}

adb_shell() {
    local serial=$1
    shift
    if [[ $serial = main ]]; then
        eval "$*"
    else
        $ADB -s $serial shell "$@" | tr -d $'\r'
    fi
}

list_command() {
    local status="device"
    case "${1:-}" in
        --offline)
            status="offline"
            shift
            ;;
    esac
    $ADB devices | grep sub | awk '$2 == "'$status'" { print $1 }' | sort | grep "${1:-}"
}

state_command() {
    api_get nodes | jq -c -r '.[]|.node+": "+.state' | sort
}

versions_command() {
  api_get nodes | jq -c -r '.[]|.node+"\t"+.state+"\tOS:"+.software_version+"\tHW:"+.hardware_version' | sort
}

node_command() {
    local node=$1 resp
    case "${2:-}" in
        shell)
            shift 2
            $ADB -s $node shell "$@"
            ;;
        wait)
            $ADB -s $node wait-for-device
            ;;
        state)
            api_get state/$node | jq -r .
            ;;

        '')
            echo "node: $node"
            echo "state: $(api_get state/$node | jq -r .)"
            echo "adb_state: $($ADB -s $node get-state)"
            if [[ $($ADB -s $node get-state) = "device" ]]; then
                echo "ifconfig:"
                adb_shell $node ifconfig
            fi
            ;;
        reboot)
            resp=$(api_get reboot/$node)
            if [[ -n "$resp" ]]; then
                die "Reset $node failed: $resp"
            else
                msg okay
            fi
            ;;
        reset)
            resp=$(api_get reset/$node)
            if [[ -n "$resp" ]]; then
                die "Reset $node failed: $resp"
            else
                msg okay
            fi
            ;;
        loader)
            resp=$(api_get loader/$node)
            if [[ -n "$resp" ]]; then
                die "Reset $node to loader failed: $resp"
            else
                msg okay
            fi
            ;;
        poweron)
            resp=$(api_get poweron/$node)
            if [[ -n "$resp" ]]; then
                die "Poweron $node failed: $resp"
            else
                msg okay
            fi
            ;;
        poweroff)
            resp=$(api_get poweroff/$node)
            if [[ -n "$resp" ]]; then
                die "Poweroff $node failed: $resp"
            else
                msg okay
            fi
            ;;
        metrics)
            metrics_subcmd "${3:-}"
            ;;

        vendor)
            shift 2
            vendor_subcmd "$@"
            ;;

        *)
            die "Invalid command"
            ;;
    esac
}

main_command() {
    node=main
    case "${2:-}" in
        metrics)
            metrics_subcmd "${3:-}"
            ;;

        vendor)
            shift 2
            vendor_subcmd "$@"
            ;;

        *)
            die "Invalid command"
            ;;
    esac
}

forall_command() {
    local -a args nodes
    local node
    if [[ $# = 0 ]]; then
        die "No command specified"
    elif [[ $# = 1 ]]; then
        case "$1" in
            reset)
                set -- bmc %{node} reset
                ;;
            poweron)
                set -- bmc %{node} poweron
                ;;
            poweroff)
                set -- bmc %{node} poweroff
                ;;
        esac
    else
        case "$1" in
            shell)
                shift 1
                set -- bmc %{node} shell "$@"
                ;;
        esac
    fi

    read -a nodes < <(tr '\n' ' ')
    for node in "${nodes[@]}"; do
        args=()
        for arg; do
            arg=${arg//"%{node}"/$node}
            args+=($arg)
        done
        echo ">>> ${args[@]}"
        bash -c "${args[*]}"
    done
}

metrics_subcmd() {
    case "${1-}" in
        log)
            sudo journalctl -f -u prometheus-node-exporter-deploy-worker@${node}.service
            ;;
        reload)
            sudo rm -f ${DEPLOY_STATE_DIR}/${node}.* &>/dev/null
            sudo systemctl restart prometheus-node-exporter-deploy-worker@${node}.service
            ;;
        restart)
            sudo systemctl restart prometheus-node-exporter-deploy-worker@${node}.service
            ;;
        '')
            local port
            if [[ $node = "main" ]]; then
                port=9100
            else
                port=$($ADB forward --list | grep $node | awk '{print $2}')
                if [[ $port = "tcp:"* ]]; then
                    port=${port#tcp:}
                else
                    die "No port forward found for $node"
                fi
            fi
            curl -s http://127.0.0.1:${port}/metrics

            ;;
        *)
            die "Invalid subcommand"
            ;;
    esac
}

vendor_subcmd() {
    case "${1-}" in
        VENDOR_*) vendor_id="$1" ;;
        wifi|lan|bt) vendor_id="VENDOR_${1^^}_MAC_ID" ;;
        sn|imei|custom) vendor_id="VENDOR_${1^^}_ID" ;;
        '') die "vendor_id needed, specify one of:
VENDOR_SN_ID                   VENDOR_WIFI_MAC_ID
VENDOR_LAN_MAC_ID              VENDOR_BT_MAC_ID
VENDOR_HDCP_14_HDMI_ID         VENDOR_HDCP_14_DP_ID
VENDOR_HDCP_2x_ID              VENDOR_DRM_KEY_ID
VENDOR_PLAYREADY_Cert_ID       VENDOR_ATTENTION_KEY_ID
VENDOR_PLAYREADY_ROOT_KEY_0_ID VENDOR_PLAYREADY_ROOT_KEY_1_ID
VENDOR_SENSOR_CALIBRATION_ID   VENODR_RESERVE_ID_14
VENDOR_IMEI_ID                 VENDOR_CUSTOM_ID
"
            ;;
    esac

    if [[ "$node" == "main" ]]; then
        state=linux
        vendor_tool=/usr/share/bmc/vendor_storage_linux
    else
        # prepare upload tool
        state=$(api_get state/$node | jq -r .)
        case "$state" in
            linux) vendor_tool=/tmp/vendor_storage_linux ;;
            android) vendor_tool=/data/local/tmp/vendor_storage_android ;;
            *) die "$node is in state $state, not supported" ;;
        esac
        if [[ "$(adb_shell $node "test -x $vendor_tool && echo okay")" != "okay" ]]; then
            bmc_adb -s $node push /usr/share/bmc/$(basename $vendor_tool) $vendor_tool &>/dev/null
        fi
    fi

    if [ -z "${2-}" ]; then
        # read
        case "$state" in
            linux)
                adb_shell $node "sudo $vendor_tool -r $vendor_id -t string -i /dev/null"
                ;;
            android)
                adb_shell $node "su -c \"$vendor_tool -r $vendor_id -t string -i /dev/null\""
                ;;
        esac
    else
        # write
        case "$state" in
            linux)
                adb_shell $node "sudo $vendor_tool -w $vendor_id -t string -i $2"
                ;;
            android)
                adb_shell $node "su -c \"$vendor_tool -w $vendor_id -t string -i $2\""
                ;;
        esac
    fi
}

case "${1:-}" in
    list)
        shift
        list_command "$@"
        ;;
    state)
        shift
        state_command "$@"
        ;;
    versions)
      shift
      versions_command "$@"
      ;;
    serials)
        $ADB serials
  ;;
    sub*)
        node_command "$@"
        ;;
    main)
        main_command "$@"
        ;;
    forall)
        shift
        forall_command "$@"
        ;;
    redeploy)
        sudo rm -f ${DEPLOY_STATE_DIR}/* &>/dev/null
        sudo /usr/bin/deploy-node-exporter.sh -f
        ;;
    query)
        shift
        if [[ $# -eq 0 ]]; then
            set -- node_cluster_up
        fi
        promtool query instant http://127.0.0.1:9090 "$@"
        ;;
    ''|-h|--help|*)
        usage
        exit 1
        ;;
esac
