#!/usr/bin/env bash
# =============================================================================
#  voxl-rc-config  – interactive configurator for /etc/modalai/voxl-rc-server.json
#  Modes: DGCS-tower, DGCS-pilot, LTE Joystick, Custom
#  Requires: gum (https://github.com/charmbracelet/gum), jq
# =============================================================================
set -euo pipefail

export PATH="/usr/local/share/modalai/voxl-rc-server/bin:${PATH}"

# ----------------------------- Command-line argument parsing
MODE_ARG=""
LTE_IP="" LTE_PORT=""

print_usage() {
    echo "Usage: voxl-configure-rc-server [COMMAND]"
    echo ""
    echo "Commands:"
    echo "  disable                              Disable and stop the service"
    echo "  factory_enable_fiber                 Configure for fiber operation"
    echo "  factory_enable_dgcs_tower            Configure for DGCS tower mode"
    echo "  factory_enable_dgcs_pilot            Configure for DGCS pilot mode"
    echo "  factory_enable_lte_joystick IP PORT  Configure for LTE joystick mode"
    echo "  help                                 Show this help message"
    echo ""
    echo "If no command provided, interactive menu is shown."
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        disable)
            systemctl disable voxl-rc-server 2>/dev/null || true
            systemctl stop voxl-rc-server 2>/dev/null || true
            echo "voxl-rc-server service disabled and stopped"
            exit 0 ;;
        factory_enable_fiber) MODE_ARG="fiber"; shift ;;
        factory_enable_dgcs_tower) MODE_ARG="tower"; shift ;;
        factory_enable_dgcs_pilot) MODE_ARG="pilot"; shift ;;
        factory_enable_lte_joystick)
            MODE_ARG="lte"
            LTE_IP="${2:-}"; LTE_PORT="${3:-}"
            [[ -z $LTE_IP || -z $LTE_PORT ]] && { echo "Error: factory_enable_lte_joystick requires IP and PORT"; exit 1; }
            shift 3 ;;
        help) print_usage; exit 0 ;;
        *) echo "Unknown command: $1"; print_usage; exit 1 ;;
    esac
done

CFG_OUT="/etc/modalai/voxl-rc-server.json"
PRESET_DIR="/usr/local/share/modalai/voxl-rc-server/presets"    # e.g. /presets/<module>/*.json
HEADER_FILE="/usr/local/share/modalai/voxl-rc-server/include/config.h"

json_merge() { jq -s 'reduce .[] as $item ({}; . * $item)' "$@"; }

get_default_labels() {
    grep 'VRS_DEFAULT_LABELS' "$HEADER_FILE" | grep -oP '"[^"]*"' | tr -d '"' | tr '\n' ' '
}

ask()    { gum input  --prompt "› " --placeholder "$1" ${2:+--value "$2"}; }
pick()   { gum choose --cursor "➜" --header "$1" "${@:2}"; }
confirm(){ gum confirm --selected.background "#00af5f" "$1"; }
note()   { gum format -- "$1"; }

# Write config and enable service (non-interactive)
write_config() {
    local cfg="$1"
    sudo mkdir -p "$(dirname "$CFG_OUT")"
    echo "$cfg" | sudo tee "$CFG_OUT" >/dev/null
    echo "Configuration written to $CFG_OUT"
    sudo systemctl enable voxl-rc-server
    echo "voxl-rc-server service enabled"
}

# Emit only the inner module object (ignore preset_name)
select_preset () {
    local module="$1"                        # e.g. tx_mavlink / rx_joystick / rx_manual_control
    local dir="$PRESET_DIR/$module"
    [[ -d $dir ]] || { echo "{}"; return; }
    compgen -G "$dir"/*.json >/dev/null || { echo "{}"; return; }

    local -a labels files
    while IFS= read -r -d '' f; do
        files+=("$f")
        local lbl
        lbl=$(jq -r '.preset_name // empty' "$f")
        [[ -z $lbl ]] && lbl=$(basename "$f")
        labels+=("$lbl")
    done < <(find "$dir" -maxdepth 1 -name '*.json' -print0 | sort -z)

    local choice
    choice=$(printf '%s\n' "${labels[@]}" | gum choose --cursor "➜" \
                        --header "Select a **$module** preset:")
    [[ -z $choice ]] && { echo "{}"; return; }

    # Map choice → file
    local idx
    for ((idx=0; idx<${#labels[@]}; idx++)); do
        [[ ${labels[$idx]} == "$choice" ]] && break
    done
    local file="${files[$idx]}"

    jq ".${module}" "$file"
}

# ----------------------------- DGCS-tower flow
flow_dgcs_tower () {
    local CFG_JSON
    CFG_JSON=$(build_dgcs_tower_config)

    note "--- Proposed configuration (DGCS-tower) ---"
    echo "$CFG_JSON" | jq .

    if confirm "Write changes to $CFG_OUT?"; then
        sudo mkdir -p "$(dirname "$CFG_OUT")"
        echo "$CFG_JSON" | sudo tee "$CFG_OUT" >/dev/null
        note "✅  Saved."
    else
        note "❌  Aborted. Existing file left untouched."
    fi
}

# ----------------------------- DGCS-pilot flow
flow_dgcs_pilot () {
    local CFG_JSON
    CFG_JSON=$(build_dgcs_pilot_config)

    note "--- Proposed configuration (DGCS-pilot) ---"
    echo "$CFG_JSON" | jq .

    if confirm "Write changes to $CFG_OUT?"; then
        sudo mkdir -p "$(dirname "$CFG_OUT")"
        echo "$CFG_JSON" | sudo tee "$CFG_OUT" >/dev/null
        note "✅  Saved."
    else
        note "❌  Aborted. Existing file left untouched."
    fi
}

# ----------------------------- Fiber mode flow
flow_fiber () {
    local CFG_JSON
    CFG_JSON=$(build_fiber_config)

    note "--- Proposed configuration (Fiber mode) ---"
    echo "$CFG_JSON" | jq .

    if confirm "Write changes to $CFG_OUT?"; then
        sudo mkdir -p "$(dirname "$CFG_OUT")"
        echo "$CFG_JSON" | sudo tee "$CFG_OUT" >/dev/null
        note "✅  Saved."
        if confirm "Enable voxl-rc-server service?"; then
            sudo systemctl enable voxl-rc-server
            note "✅  Service enabled."
        fi
    else
        note "❌  Aborted. Existing file left untouched."
    fi
}

# ----------------------------- LTE Joystick flow
flow_lte_joystick () {
    # Orchestrator rx=['joystick'], tx=['mavlink']
    local ORCH_JSON
    ORCH_JSON=$(jq -n '{orchestrator:{rx:["joystick"], tx:["mavlink"]}}')

    note "Select a tx_mavlink preset (e.g., VOXL-FPV)…"
    local PRE_TXM
    PRE_TXM=$(select_preset tx_mavlink)   # inner object or {}

    # Destination IP/port for unicast
    local IP PORT
    IP=$(ask "Destination IP for MAVLink (unicast IPv4)" "127.0.0.1")
    PORT=$(ask "Destination UDP port" "14550")

    # Build tx_mavlink config; force unicast (mcast=false) when IP provided
    local TXM_DEST
    TXM_DEST=$(jq -n --arg ip "$IP" --argjson p "${PORT:-14550}" \
        '{modules:{tx_mavlink:{ip:$ip, port:$p, mcast:false}}}')

    # If a preset was chosen, wrap and merge it *before* applying IP/port overrides
    local TXM_PRESET_WRAPPED='{}'
    if [[ "$PRE_TXM" != "{}" ]]; then
        TXM_PRESET_WRAPPED=$(jq -n --argjson pre "$PRE_TXM" '{modules:{tx_mavlink:$pre}}')
    fi

    local BASE_JSON='{}'
    [[ -f $CFG_OUT ]] && BASE_JSON=$(cat "$CFG_OUT")
    BASE_JSON=$(jq 'del(.rx, .tx)' <<<"$BASE_JSON")

    local CFG_JSON
    CFG_JSON=$(json_merge \
        <(echo "$BASE_JSON") \
        <(echo "$ORCH_JSON") \
        <(echo "$TXM_PRESET_WRAPPED") \
        <(echo "$TXM_DEST"))

    # Optional: custom channel labels
    if confirm "Use custom channel labels? (defaults: $(get_default_labels))"; then
        local LABEL_JSON='{"channel_labels":["ch1","ch2","ch3","ch4","ch5","ch6","ch7","ch8","ch9","ch10","ch11","ch12","ch13","ch14","ch15","ch16"]}'
        CFG_JSON=$(json_merge <(echo "$CFG_JSON") <(echo "$LABEL_JSON"))
        note "Custom labels added. Edit channel_labels in $CFG_OUT after saving."
    fi

    note "--- Proposed configuration (LTE Joystick) ---"
    echo "$CFG_JSON" | jq .

    if confirm "Write changes to $CFG_OUT?"; then
        sudo mkdir -p "$(dirname "$CFG_OUT")"
        echo "$CFG_JSON" | sudo tee "$CFG_OUT" >/dev/null
        note "✅  Saved."
    else
        note "❌  Aborted. Existing file left untouched."
    fi
}

# ----------------------------- Custom (updated legacy flow → new schema)
flow_custom () {
    # ------------------------------------------- RX select
    local RX_TYPE
    RX_TYPE=$(pick "Select **input / receiver** type:" "joystick" "mavlink")

    local MOD_RX='{}'
    if [[ $RX_TYPE == joystick ]]; then
        # Optional joystick preset
        if confirm "Use a preset for rx_joystick?"; then
            local PRE
            PRE=$(select_preset rx_joystick)
            MOD_RX=$(jq -n --argjson p "$PRE" '{modules:{rx_joystick:$p}}')
        fi
    else
        # RX over MAVLink: ask UDP port + optional iface/mcast flag
        local RPORT
        RPORT=$(ask "UDP port to listen on (RX mavlink)" "14550")
        # default to multicast (your defaults already do), but allow toggle
        local USE_MCAST
        if confirm "Use IPv6 multicast for RX MAVLink?"; then
            USE_MCAST=true
        else
            USE_MCAST=false
        fi
        MOD_RX=$(jq -n --argjson p "$RPORT" --argjson mc "$USE_MCAST" \
                 '{modules:{rx_mavlink:{port:$p, mcast:$mc}}}')

        # Optional rx_manual_control preset (if you use it)
        if confirm "Apply an rx_manual_control preset (buttons/axes)?"; then
            local PRE
            PRE=$(select_preset rx_manual_control)
            # Merge into MOD_RX
            MOD_RX=$(json_merge \
                <(echo "$MOD_RX") \
                <(jq -n --argjson p "$PRE" '{modules:{rx_manual_control:$p}}'))
        fi
    fi

    # ------------------------------------------- TX select
    local TX_TYPE
    TX_TYPE=$(pick "Select **output / transmitter** type:" "crsf" "mavlink")

    local MOD_TX='{}'
    if [[ $TX_TYPE == crsf ]]; then
        local DEV BAUD
        DEV=$(ask "Serial device" "/dev/ttyUSB0")
        BAUD=$(ask "Baud rate" "921600")
        MOD_TX=$(jq -n --arg dev "$DEV" --argjson b "$BAUD" \
                 '{modules:{tx_crsf:{device:$dev, baud:$b}}}')
    else
        # MAVLink TX: ask unicast/multicast first
        local MODE
        MODE=$(pick "TX transport" "unicast (IPv4)" "multicast (IPv6)")
        if [[ "$MODE" == "unicast (IPv4)" ]]; then
            local IP PORT
            IP=$(ask "Destination IP" "127.0.0.1")
            PORT=$(ask "Destination UDP port" "14550")
            MOD_TX=$(jq -n --arg ip "$IP" --argjson p "$PORT" \
                     '{modules:{tx_mavlink:{ip:$ip, port:$p, mcast:false}}}')
        else
            local PORT IFACE
            PORT=$(ask "Multicast UDP port" "14550")
            IFACE=$(ask "Outgoing interface (blank for auto)" "")
            if [[ -n "$IFACE" ]]; then
                MOD_TX=$(jq -n --argjson p "$PORT" --arg iface "$IFACE" \
                         '{modules:{tx_mavlink:{mcast:true, port:$p, iface:$iface}}}')
            else
                MOD_TX=$(jq -n --argjson p "$PORT" \
                         '{modules:{tx_mavlink:{mcast:true, port:$p}}}')
            fi
        fi

        # Optional tx_mavlink preset (e.g., VOXL-FPV)
        if confirm "Apply a tx_mavlink preset (e.g., VOXL-FPV)?"; then
            local PRE
            PRE=$(select_preset tx_mavlink)
            MOD_TX=$(json_merge <(echo "$MOD_TX") \
                               <(jq -n --argjson p "$PRE" '{modules:{tx_mavlink:$p}}'))
        fi
    fi

    # ------------------------------------------- Orchestrator arrays
    local ORCH_RX ORCH_TX
    if [[ $RX_TYPE == joystick ]]; then ORCH_RX='["joystick"]'; else ORCH_RX='["mavlink"]'; fi
    if [[ $TX_TYPE == crsf     ]]; then ORCH_TX='["crsf"]';     else ORCH_TX='["mavlink"]'; fi

    local ORCH_JSON
    ORCH_JSON=$(jq -n --argjson rx "$ORCH_RX" --argjson tx "$ORCH_TX" \
        '{orchestrator:{rx:$rx, tx:$tx}}')

    # ------------------------------------------- Compose & write
    local BASE_JSON='{}'
    [[ -f $CFG_OUT ]] && BASE_JSON=$(cat "$CFG_OUT")
    BASE_JSON=$(jq 'del(.rx, .tx)' <<<"$BASE_JSON")

    local CFG_JSON
    CFG_JSON=$(json_merge \
        <(echo "$BASE_JSON") \
        <(echo "$ORCH_JSON") \
        <(echo "$MOD_RX") \
        <(echo "$MOD_TX"))

    # Optional: custom channel labels
    if confirm "Use custom channel labels? (defaults: $(get_default_labels))"; then
        local LABEL_JSON='{"channel_labels":["ch1","ch2","ch3","ch4","ch5","ch6","ch7","ch8","ch9","ch10","ch11","ch12","ch13","ch14","ch15","ch16"]}'
        CFG_JSON=$(json_merge <(echo "$CFG_JSON") <(echo "$LABEL_JSON"))
        note "Custom labels added. Edit channel_labels in $CFG_OUT after saving."
    fi

    note "--- Proposed configuration (Custom) ---"
    echo "$CFG_JSON" | jq .

    if confirm "Write changes to $CFG_OUT?"; then
        sudo mkdir -p "$(dirname "$CFG_OUT")"
        echo "$CFG_JSON" | sudo tee "$CFG_OUT" >/dev/null
        note "✅  Saved."
    else
        note "❌  Aborted. Existing file left untouched."
    fi
}

# ----------------------------- Non-interactive handlers
build_dgcs_tower_config() {
    jq -n '{
        orchestrator: { rx: ["mavlink"], tx: ["crsf"] },
        modules: {
            rx_mavlink: { port: 14551, mcast: false },
            tx_crsf: { device: "/dev/ttyHS1", baud: 921600 }
        }
    }'
}

build_dgcs_pilot_config() {
    local PRE_RXJ
    PRE_RXJ=$(jq '.rx_joystick' "$PRESET_DIR/rx_joystick/zorro.json")
    jq -n --argjson rxj "$PRE_RXJ" '{
        orchestrator: { rx: ["joystick"], tx: ["mavlink"] },
        modules: {
            rx_joystick: $rxj,
            tx_mavlink: { ip: "10.0.0.10", port: 14551, mcast: false }
        }
    }'
}

build_fiber_config() {
    local PRE_RXJ PRE_TXM
    PRE_RXJ=$(jq '.rx_joystick' "$PRESET_DIR/rx_joystick/zorro.json")
    PRE_TXM=$(jq '.tx_mavlink' "$PRESET_DIR/tx_mavlink/voxl-fpv.json")
    jq -n --argjson rxj "$PRE_RXJ" --argjson txm "$PRE_TXM" '{
        orchestrator: { rx: ["joystick"], tx: ["mavlink"] },
        modules: {
            rx_joystick: $rxj,
            tx_mavlink: ({ip: "10.0.0.10", port: 14550, mcast: false} + $txm)
        }
    }'
}

build_lte_config() {
    local IP="$1" PORT="$2"
    local PRE_TXM
    PRE_TXM=$(jq '.tx_mavlink' "$PRESET_DIR/tx_mavlink/voxl-fpv.json")
    jq -n --arg ip "$IP" --argjson port "$PORT" --argjson txm "$PRE_TXM" '{
        orchestrator: { rx: ["joystick"], tx: ["mavlink"] },
        modules: {
            tx_mavlink: ({ip: $ip, port: $port, mcast: false} + $txm)
        }
    }'
}

# ----------------------------- Command-line mode dispatch
if [[ -n $MODE_ARG ]]; then
    case "$MODE_ARG" in
        fiber) write_config "$(build_fiber_config)" ;;
        tower) write_config "$(build_dgcs_tower_config)" ;;
        pilot) write_config "$(build_dgcs_pilot_config)" ;;
        lte)   write_config "$(build_lte_config "$LTE_IP" "$LTE_PORT")" ;;
    esac
    exit 0
fi

# ----------------------------- Entry menu
MODE=$(pick "Select setup mode:" \
            "DGCS-tower" \
            "DGCS-pilot" \
            "Fiber mode" \
            "LTE Joystick mode" \
            "Custom")

case "$MODE" in
  "DGCS-tower")        flow_dgcs_tower ;;
  "DGCS-pilot")        flow_dgcs_pilot ;;
  "Fiber mode")        flow_fiber ;;
  "LTE Joystick mode") flow_lte_joystick ;;
  "Custom")            flow_custom ;;
esac
