#!/usr/bin/env bash
set -euo pipefail
# POS: share usb-server — USB Redirector server control (--ls, --share; prompts when args omitted)
# POS_FLAGS: --ls --ls-shared --share --unshare --auto-share --callback --close-callback --auto-connect --disconnect --nickname --timeout --port --info --version menu
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
source "$(dirname "$0")/../lib/share-lib.sh" 2>/dev/null || source "$(dirname "$0")/share-lib.sh"

usage() {
    cat <<EOF
Usage: pos share usb server [flag] [args]

Control the USB Redirector server (usbsrv) — share local USB devices
over the network and manage connected clients.

Flags:
  --ls                          List host USB devices and connected clients
  --ls-shared                   List shared or in-use devices only
  --share [dev-id] [client-id]  Share a device and connect it to a client
                                (interactive picker when IDs are omitted)
  --unshare [dev-id]            Stop sharing a device
  --auto-share on|off           Toggle automatic sharing of new devices
  --callback [addr:port]        Create a callback connection to a client
  --close-callback [target|all] Close a client callback
  --auto-connect on|off [client]  Toggle remote auto-connect for a client
  --disconnect [dev-id|all]     Disconnect a device from its clients
  --nickname [dev-id] [nick]    Set a device nickname (empty nick removes it)
  --timeout [dev-id] [sec]      Set device inactivity timeout (0 disables)
  --port [num]                  Set the TCP port (restart server to apply)
  --info                        Show server info
  --version                     Show server version
  -h, --help                    Show this help

Examples:
  pos share usb server --ls
  pos share usb server --share
  pos share usb server --share 0-1 3
  pos share usb server --auto-share on
  pos share usb server --port 32032
EOF
    exit 0
}

cmd_ls() {
    echo "==== HOST USB DEVICES ===="
    usbsrv -list-devices
    echo
    echo "==== CONNECTED CLIENTS ===="
    usbsrv -list-clients
}

cmd_ls_shared() {
    echo "==== SHARED OR IN USE DEVICES ===="
    usbsrv -list-devices | awk '
      BEGIN {RS=""; FS="\n"}
      {
        for(i=1; i<=NF; i++) {
          if ($i ~ /Status:.*(shared|in use)/) {
            print $0 "\n"
            break
          }
        }
      }
    ' || true
}

cmd_share() {
    local dev="${1:-}" client="${2:-}"
    if [ -z "$dev" ]; then
        echo "==== HOST USB DEVICES ===="
        usbsrv -list-devices
        echo
        echo "==== CONNECTED CLIENTS ===="
        usbsrv -list-clients
        echo
        read -rp "Enter device ID to share: " dev
        read -rp "Enter client ID to connect to: " client
    fi
    [ -n "$dev" ] || err "no device ID given"
    [ -n "$client" ] || err "no client ID given"
    log "Sharing device ID $dev..."
    usbsrv -share "$dev"
    log "Connecting device $dev to client $client..."
    usbsrv -connect-to "${client}-${dev}"
}

cmd_unshare() {
    local dev="${1:-}"
    if [ -z "$dev" ]; then
        cmd_ls_shared
        read -rp "Enter device ID to unshare: " dev
    fi
    [ -n "$dev" ] || err "no device ID given"
    log "Unsharing device ID $dev..."
    usbsrv -unshare "$dev"
}

cmd_auto_share() {
    local mode="${1:-}"
    if [ -z "$mode" ]; then
        read -rp "Turn auto-share on or off? (on/off): " mode
    fi
    case "$mode" in
        on|off) ;;
        *) err "Invalid option '$mode' — must be 'on' or 'off'" ;;
    esac
    usbsrv -auto-share "$mode"
    log "Auto-share set to $mode"
}

cmd_callback() {
    local addr="${1:-}"
    if [ -z "$addr" ]; then
        read -rp "Enter client address:port for callback (e.g. 192.168.1.100:32032): " addr
    fi
    [ -n "$addr" ] || err "no address given"
    usbsrv -create-callback "$addr"
}

cmd_close_callback() {
    local target="${1:-}"
    if [ -z "$target" ]; then
        usbsrv -list-clients
        read -rp "Enter client or clientid or 'all' to close callback: " target
    fi
    [ -n "$target" ] || err "no target given"
    usbsrv -close-callback "$target"
}

cmd_auto_connect() {
    local mode="${1:-}" client="${2:-}"
    if [ -z "$mode" ]; then
        read -rp "Enable or disable remote auto-connect? (on/off): " mode
    fi
    case "$mode" in
        on|off) ;;
        *) err "Invalid option '$mode' — must be 'on' or 'off'" ;;
    esac
    if [ -z "$client" ]; then
        usbsrv -list-clients
        read -rp "Enter client or clientid: " client
    fi
    [ -n "$client" ] || err "no client given"
    usbsrv -remote-auto-connect "$mode" "$client"
}

cmd_disconnect() {
    local dev="${1:-}"
    if [ -z "$dev" ]; then
        cmd_ls_shared
        read -rp "Enter device ID or 'all' to disconnect from clients: " dev
    fi
    [ -n "$dev" ] || err "no device ID given"
    usbsrv -disconnect-from "$dev"
}

cmd_nickname() {
    local dev="${1:-}" nick="${2:-}"
    if [ -z "$dev" ]; then
        usbsrv -list-devices
        read -rp "Enter device ID to set nickname (empty to remove): " dev
        read -rp "Enter nickname (or leave empty to remove): " nick
    fi
    [ -n "$dev" ] || err "no device ID given"
    usbsrv -set-nickname "$nick" "$dev"
}

cmd_timeout() {
    local dev="${1:-}" sec="${2:-}"
    if [ -z "$dev" ]; then
        usbsrv -list-devices
        read -rp "Enter device ID to set timeout for: " dev
        read -rp "Enter timeout in seconds (0 to disable): " sec
    fi
    [ -n "$dev" ] || err "no device ID given"
    [[ "$sec" =~ ^[0-9]+$ ]] || err "Invalid timeout '$sec' — must be a number"
    usbsrv -set-timeout "$sec" "$dev"
}

cmd_port() {
    local port="${1:-}"
    if [ -z "$port" ]; then
        read -rp "Enter new TCP port: " port
    fi
    [[ "$port" =~ ^[0-9]+$ ]] || err "Invalid port number '$port'"
    usbsrv -set-tcp-port "$port"
    warn "Restart your server for port changes to take effect."
}

command -v usbsrv &>/dev/null \
    || err "usbsrv not found — install the USB Redirector server (https://www.incentivespro.com/usb-server.html)"

# ── Interactive menu flows ─────────────────────────────────────
# Picker-first prompting: parsed listings feed the filtered picker; when the
# server is unreachable or nothing parses, fall back to the same raw-listing +
# manual-entry prompts the explicit commands have always used.
menu_pick_from_records() { # <prompt> <records-cmd...> — stdout: chosen ID · rc 1 cancel/fallback
    local prompt="$1"; shift
    local idx rec
    local -a ids=()
    if recs="$("$@")" && [ -n "$recs" ]; then
        while IFS= read -r rec; do
            [ -n "$rec" ] || continue
            ids+=("${rec%%|*}")
        done <<<"$recs"
        if [ "${#ids[@]}" -gt 0 ]; then
            if idx="$(share_pick "$prompt" "${ids[@]}")"; then
                echo "${ids[$((idx - 1))]}"
                return 0
            fi
        fi
    fi
    return 1
}

menu_share() {
    local dev client
    if ! dev="$(menu_pick_from_records "Share which USB device?" share_usb_devices)"; then
        cmd_ls >/dev/null 2>&1 || true
        read -rp "Enter device ID to share: " dev
        [ -n "$dev" ] || { warn "Cancelled"; return 1; }
    fi
    if ! client="$(menu_pick_from_records "Connect to which client?" share_usb_clients)"; then
        read -rp "Enter client ID to connect to: " client
        [ -n "$client" ] || { warn "Cancelled"; return 1; }
    fi
    cmd_share "$dev" "$client"
}

menu_unshare() {
    local dev
    if ! dev="$(menu_pick_from_records "Stop sharing which device?" share_usb_devices)"; then
        cmd_ls_shared >/dev/null 2>&1 || true
        read -rp "Enter device ID to unshare: " dev
        [ -n "$dev" ] || { warn "Cancelled"; return 1; }
    fi
    cmd_unshare "$dev"
}

menu_callback() {
    local addr
    addr="$(share_ask_value "Client address:port for callback (e.g. 192.168.1.100:32032)")" || return 1
    [ -n "$addr" ] || { warn "Cancelled"; return 1; }
    cmd_callback "$addr"
}

menu_close_callback() {
    local target
    if ! target="$(menu_pick_from_records "Close callback of which client?" share_usb_clients)"; then
        target="$(share_ask_value "Client, client id or 'all' to close callback")" || return 1
        [ -n "$target" ] || { warn "Cancelled"; return 1; }
    fi
    cmd_close_callback "$target"
}

menu_auto_connect() {
    local mode client
    mode="$(share_ask_value "Remote auto-connect on or off?" "on")" || return 1
    case "$mode" in on|off) ;; *) warn "must be on/off"; return 1 ;; esac
    if ! client="$(menu_pick_from_records "Toggle auto-connect for which client?" share_usb_clients)"; then
        client="$(share_ask_value "Client or client id")" || return 1
        [ -n "$client" ] || { warn "Cancelled"; return 1; }
    fi
    cmd_auto_connect "$mode" "$client"
}

menu_disconnect() {
    local dev
    if ! dev="$(menu_pick_from_records "Disconnect which device?" share_usb_devices)"; then
        dev="$(share_ask_value "Device ID or 'all' to disconnect from clients")" || return 1
        [ -n "$dev" ] || { warn "Cancelled"; return 1; }
    fi
    cmd_disconnect "$dev"
}

menu_nickname() {
    local dev nick
    if ! dev="$(menu_pick_from_records "Nickname which device?" share_usb_devices)"; then
        dev="$(share_ask_value "Device ID")" || return 1
        [ -n "$dev" ] || { warn "Cancelled"; return 1; }
    fi
    nick="$(share_ask_value "Nickname (empty removes it)")" || return 1
    cmd_nickname "$dev" "$nick"
}

menu_timeout() {
    local dev sec
    if ! dev="$(menu_pick_from_records "Set inactivity timeout for which device?" share_usb_devices)"; then
        dev="$(share_ask_value "Device ID")" || return 1
        [ -n "$dev" ] || { warn "Cancelled"; return 1; }
    fi
    sec="$(share_ask_value "Timeout in seconds (0 disables)" "0")" || return 1
    cmd_timeout "$dev" "$sec"
}

menu_port() {
    local port
    port="$(share_ask_value "New TCP port")" || return 1
    [ -n "$port" ] || { warn "Cancelled"; return 1; }
    cmd_port "$port"
}

run_menu() {
    share_menu_guard || exit 1
    while true; do
        local choice
        choice="$(share_menu_run "USB Redirector server" \
            "List host devices and connected clients" \
            "Share a device with a client" \
            "Stop sharing a device" \
            "Disconnect device(s) from clients" \
            "Auto-share on/off" \
            "Create a callback connection" \
            "Close a client callback" \
            "Client remote auto-connect on/off" \
            "Set a device nickname" \
            "Set a device inactivity timeout" \
            "Set the TCP port")" || return 0
        case "$choice" in
            1) cmd_ls ;;
            2) menu_share ;;
            3) menu_unshare ;;
            4) menu_disconnect ;;
            5) cmd_auto_share ;;
            6) menu_callback ;;
            7) menu_close_callback ;;
            8) menu_auto_connect ;;
            9) menu_nickname ;;
            10) menu_timeout ;;
            11) menu_port ;;
        esac
    done
}

cmd="${1:-}"

case "$cmd" in
    -h|--help) usage ;;
esac

case "$cmd" in
    ""|menu|--ls|--ls-shared|--share|--unshare|--auto-share|--callback|--close-callback|--auto-connect|--disconnect|--nickname|--timeout|--port|--info|--version) ;;
    *) err "Unknown flag '$cmd'" ;;
esac

case "$cmd" in
    ""|menu)        run_menu ;;
    --ls)           cmd_ls ;;
    --ls-shared)    cmd_ls_shared ;;
    --share)        shift; cmd_share "$@" ;;
    --unshare)      shift; cmd_unshare "$@" ;;
    --auto-share)   shift; cmd_auto_share "$@" ;;
    --callback)     shift; cmd_callback "$@" ;;
    --close-callback) shift; cmd_close_callback "$@" ;;
    --auto-connect) shift; cmd_auto_connect "$@" ;;
    --disconnect)   shift; cmd_disconnect "$@" ;;
    --nickname)     shift; cmd_nickname "$@" ;;
    --timeout)      shift; cmd_timeout "$@" ;;
    --port)         shift; cmd_port "$@" ;;
    --info)         usbsrv -info ;;
    --version)      usbsrv -version ;;
    *)              err "Unknown flag '$cmd'"; usage ;;
esac
