#!/usr/bin/env bash
set -euo pipefail

# Pikobs Web workstation launcher.
# One command: starts/repairs the user's remote backend, creates the SSH
# tunnel, verifies the API through the tunnel, and opens the browser.

REMOTE_HOST="${PIKOBS_WEB_HOST:-ppp7login-02-ib}"
REMOTE_USER="${PIKOBS_WEB_USER:-$USER}"
REMOTE_APP_DIR="${PIKOBS_WEB_REMOTE_DIR:-}"
STATE_DIR="${PIKOBS_WEB_CLIENT_STATE_DIR:-$HOME/.pikobs_web_client}"
CONTROL_SOCKET="$STATE_DIR/ssh-control"
LOCAL_PORT_FILE="$STATE_DIR/local_port"
REMOTE_PORT_FILE="$STATE_DIR/remote_port"
REMOTE_HOST_FILE="$STATE_DIR/remote_host"

mkdir -p "$STATE_DIR"
chmod 700 "$STATE_DIR"

need_cmd() {
    command -v "$1" >/dev/null 2>&1 || {
        echo "ERROR: required command not found on this workstation: $1" >&2
        exit 1
    }
}

need_cmd ssh

choose_python() {
    command -v python3 2>/dev/null || command -v python 2>/dev/null || true
}

LOCAL_PYTHON="$(choose_python)"
[ -n "$LOCAL_PYTHON" ] || {
    echo "ERROR: python3 or python is required on the workstation." >&2
    exit 1
}

choose_local_port() {
    "$LOCAL_PYTHON" - <<'PY'
import socket
s = socket.socket()
s.bind(('127.0.0.1', 0))
print(s.getsockname()[1])
s.close()
PY
}

remote_launcher_command() {
    if [ -n "$REMOTE_APP_DIR" ]; then
        # For overrides, require an absolute remote path. This avoids confusing
        # local-vs-remote ~/$HOME expansion.
        case "$REMOTE_APP_DIR" in
            /*) ;;
            *) echo "ERROR: PIKOBS_WEB_REMOTE_DIR must be an absolute path on the remote host." >&2; return 1 ;;
        esac
        printf 'cd %q && ./pikobs-web connection' "$REMOTE_APP_DIR"
    else
        # Default installation made by setup_pikobs.sh. $HOME expands remotely.
        printf '%s' 'cd "$HOME/pikobs_install/pikobs_web" && ./pikobs-web connection'
    fi
}

remote_info() {
    local cmd out line
    cmd="$(remote_launcher_command)"
    out="$(ssh -4 -T "${REMOTE_USER}@${REMOTE_HOST}" "$cmd")"
    line="$(printf '%s\n' "$out" | awk -F '\t' '$1=="PIKOBS_WEB_CONNECTION" {line=$0} END {print line}')"
    if [ -z "$line" ]; then
        echo "ERROR: remote Pikobs Web did not return connection information." >&2
        printf '%s\n' "$out" >&2
        return 1
    fi
    printf '%s\n' "$line"
}

tunnel_target() {
    if [ -s "$REMOTE_HOST_FILE" ]; then
        printf '%s\n' "${REMOTE_USER}@$(cat "$REMOTE_HOST_FILE")"
    else
        printf '%s\n' "${REMOTE_USER}@${REMOTE_HOST}"
    fi
}

control_alive() {
    local target
    target="$(tunnel_target)"
    [ -S "$CONTROL_SOCKET" ] && \
        ssh -S "$CONTROL_SOCKET" -O check "$target" >/dev/null 2>&1
}

close_tunnel() {
    local target
    target="$(tunnel_target)"
    if control_alive; then
        ssh -S "$CONTROL_SOCKET" -O exit "$target" >/dev/null 2>&1 || true
    fi
    rm -f "$CONTROL_SOCKET" "$LOCAL_PORT_FILE" "$REMOTE_PORT_FILE" "$REMOTE_HOST_FILE"
}

wait_local_api() {
    local local_port="$1" token="$2"
    "$LOCAL_PYTHON" - "$local_port" "$token" <<'PY'
import json
import sys
import time
import urllib.request

port, token = sys.argv[1], sys.argv[2]
url = f"http://127.0.0.1:{port}/api/config"
last = None
for _ in range(60):
    try:
        req = urllib.request.Request(url, headers={"X-Pikobs-Token": token})
        with urllib.request.urlopen(req, timeout=0.5) as r:
            data = json.load(r)
            if (r.status == 200 and isinstance(data, dict) and "families" in data
                    and str(data.get("session", {}).get("version", "")) == "17"):
                raise SystemExit(0)
    except Exception as exc:
        last = exc
    time.sleep(0.1)
print(f"Pikobs Web tunnel/API is not ready: {last}", file=sys.stderr)
raise SystemExit(1)
PY
}

open_url() {
    local url="$1"
    if command -v xdg-open >/dev/null 2>&1; then
        nohup xdg-open "$url" >/dev/null 2>&1 &
    elif command -v gio >/dev/null 2>&1; then
        nohup gio open "$url" >/dev/null 2>&1 &
    elif command -v open >/dev/null 2>&1; then
        nohup open "$url" >/dev/null 2>&1 &
    elif command -v cmd.exe >/dev/null 2>&1; then
        cmd.exe /c start "" "$url" >/dev/null 2>&1 &
    elif command -v powershell.exe >/dev/null 2>&1; then
        powershell.exe -NoProfile -Command "Start-Process '$url'" >/dev/null 2>&1 &
    else
        echo
        echo "Open this URL in your browser:"
        echo "  $url"
        return 0
    fi
    echo "Opening Pikobs Web in your browser..."
}

create_tunnel() {
    local actual_host="$1" remote_port="$2" local_port="$3"
    rm -f "$CONTROL_SOCKET"
    ssh -4 -M -S "$CONTROL_SOCKET" -fNT \
        -o ExitOnForwardFailure=yes \
        -o ServerAliveInterval=60 \
        -o ServerAliveCountMax=3 \
        -L "${local_port}:127.0.0.1:${remote_port}" \
        "${REMOTE_USER}@${actual_host}"
    printf '%s\n' "$local_port" > "$LOCAL_PORT_FILE"
    printf '%s\n' "$remote_port" > "$REMOTE_PORT_FILE"
    printf '%s\n' "$actual_host" > "$REMOTE_HOST_FILE"
    chmod 600 "$LOCAL_PORT_FILE" "$REMOTE_PORT_FILE" "$REMOTE_HOST_FILE"
}

start_client() {
    echo "Connecting to Pikobs Web..."

    local line marker actual_host remote_port token remote_pid local_port url
    line="$(remote_info)"
    IFS=$'\t' read -r marker actual_host remote_port token remote_pid <<< "$line"

    if [ "$marker" != "PIKOBS_WEB_CONNECTION" ] || \
       [ -z "$actual_host" ] || ! [[ "$remote_port" =~ ^[0-9]+$ ]] || [ -z "$token" ]; then
        echo "ERROR: invalid connection information returned by remote Pikobs Web." >&2
        echo "$line" >&2
        exit 1
    fi

    # Reuse a tunnel only if it points to the exact same healthy remote
    # instance. Otherwise replace it automatically.
    if control_alive; then
        local old_remote="" old_host=""
        [ -f "$REMOTE_PORT_FILE" ] && old_remote="$(cat "$REMOTE_PORT_FILE")"
        [ -f "$REMOTE_HOST_FILE" ] && old_host="$(cat "$REMOTE_HOST_FILE")"
        if [ "$old_remote" != "$remote_port" ] || [ "$old_host" != "$actual_host" ]; then
            close_tunnel
        fi
    fi

    if control_alive; then
        local_port="$(cat "$LOCAL_PORT_FILE")"
    else
        close_tunnel
        local_port="$(choose_local_port)"
        create_tunnel "$actual_host" "$remote_port" "$local_port"
    fi

    # Never open a browser until the authenticated API works through the
    # tunnel. If a reused tunnel is broken, rebuild it once automatically.
    if ! wait_local_api "$local_port" "$token"; then
        echo "Tunnel was stale; rebuilding it automatically..."
        close_tunnel
        local_port="$(choose_local_port)"
        create_tunnel "$actual_host" "$remote_port" "$local_port"
        wait_local_api "$local_port" "$token"
    fi

    url="http://127.0.0.1:${local_port}/?v=17#token=${token}"
    echo "Pikobs Web ready: ${REMOTE_USER}@${actual_host} (remote PID ${remote_pid})"
    open_url "$url"
}

remote_stop() {
    local cmd
    if [ -n "$REMOTE_APP_DIR" ]; then
        case "$REMOTE_APP_DIR" in /*) ;; *) return 0 ;; esac
        printf -v cmd 'cd %q && ./pikobs-web stop' "$REMOTE_APP_DIR"
    else
        cmd='cd "$HOME/pikobs_install/pikobs_web" && ./pikobs-web stop'
    fi
    ssh -4 -T "${REMOTE_USER}@${REMOTE_HOST}" "$cmd" || true
}

status_client() {
    if control_alive; then
        echo "Pikobs Web tunnel is running"
        echo "  Remote : $(tunnel_target)"
        [ -f "$LOCAL_PORT_FILE" ] && echo "  Local  : 127.0.0.1:$(cat "$LOCAL_PORT_FILE")"
        [ -f "$REMOTE_PORT_FILE" ] && echo "  Remote port: $(cat "$REMOTE_PORT_FILE")"
    else
        echo "Pikobs Web tunnel is not running."
    fi

    echo
    echo "Remote server:"
    if line="$(remote_info 2>/dev/null)"; then
        IFS=$'\t' read -r _ h p _ pid <<< "$line"
        echo "  RUNNING on ${h}:${p} (PID ${pid})"
    else
        echo "  NOT AVAILABLE"
        return 1
    fi
}

stop_client() {
    close_tunnel
    remote_stop
    echo "Pikobs Web stopped."
}

case "${1:-open}" in
    open|start) start_client ;;
    status) status_client ;;
    stop) stop_client ;;
    restart) stop_client; start_client ;;
    *)
        cat >&2 <<USAGE
Usage: pikobs-web [open|start|status|stop|restart]

Environment overrides (normally configured once):
  PIKOBS_WEB_HOST        remote login host (default: ppp7login-02-ib)
  PIKOBS_WEB_USER        remote Unix user (default: local username)
  PIKOBS_WEB_REMOTE_DIR  absolute remote shared Pikobs Web directory
USAGE
        exit 2
        ;;
esac
