#!/usr/bin/env bash
# ── qpq Dev Shell ─────────────────────────────────────────────────────────────
#
# Builds qpq (if needed), starts a local server, registers Alice + Bob, then
# opens a tmux session with two side-by-side REPL panes and a server-log strip.
#
# Layout (window 0 — "chat"):
#
#   ┌──────────[ ALICE  user=alice pass=alice ]──┬──[ BOB  user=bob pass=bob ]──┐
#   │                                            │                              │
#   │   /dm bob          ← start a DM here      │   reply here                 │
#   │   /create-group g  ← or create a group    │   /join  ← to accept invite  │
#   │                                            │                              │
#   ├──────────[ SERVER LOG ]────────────────────┴──────────────────────────────┤
#   │   live qpq-server stdout / stderr                                         │
#   └───────────────────────────────────────────────────────────────────────────┘
#
# Window 1 — "ref": full slash-command cheatsheet (read-only)
#
# Usage:
#   ./scripts/dev-shell.sh             build if needed, fresh session
#   ./scripts/dev-shell.sh --rebuild   force cargo build first
#   ./scripts/dev-shell.sh --resume    reuse existing state files + server data
#   ./scripts/dev-shell.sh --help      show this message
#
# Stop:  Ctrl-C here  OR  tmux kill-session -t qpq-dev
# Ref:   Ctrl-B 1   (inside tmux → cheatsheet window)
# Nav:   Ctrl-B ←/→ (switch Alice ↔ Bob pane)
#        Ctrl-B z   (zoom current pane)

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BIN_DIR="$PROJECT_ROOT/target/debug"
SESSION="qpq-dev"
SERVER_PORT=7000
SERVER_ADDR="127.0.0.1:$SERVER_PORT"
SERVER_NAME="localhost"

# All runtime state lives in /tmp so the project tree stays clean
RUN_DIR="/tmp/qpq-devshell"
DATA_DIR="$RUN_DIR/server-data"   # server stores TLS cert + OPAQUE data here
CA_CERT="$DATA_DIR/server-cert.der"
LOG_FILE="$RUN_DIR/server.log"

QPQ="$BIN_DIR/qpq"
QPQS="$BIN_DIR/qpq-server"

# ── Colours ────────────────────────────────────────────────────────────────────
GRN='\033[0;32m'; CYN='\033[0;36m'; YLW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
step() { printf "\n${GRN}▶  %s${NC}\n" "$*"; }
info() { printf "   ${CYN}%s${NC}\n" "$*"; }
warn() { printf "   ${YLW}⚠  %s${NC}\n" "$*"; }
die()  { printf "${RED}✗  %s${NC}\n" "$*" >&2; exit 1; }

# ── Parse flags ────────────────────────────────────────────────────────────────
REBUILD=false
RESUME=false
for arg in "$@"; do
    case "$arg" in
        -r|--rebuild) REBUILD=true ;;
        --resume)     RESUME=true  ;;
        -h|--help)
            sed -n '2,/^[^#]/{ /^#/p }' "$0" | sed 's/^# \?//'
            exit 0
            ;;
        *) die "Unknown argument: $arg" ;;
    esac
done

# ── Preflight ──────────────────────────────────────────────────────────────────
step "Checking requirements..."
for cmd in cargo tmux; do
    command -v "$cmd" &>/dev/null || die "'$cmd' is required but not installed."
done
info "cargo $(cargo --version 2>&1 | head -1)"
info "tmux  $(tmux -V)"

# ── Decide whether to clean state ─────────────────────────────────────────────
# By default we start fresh (server is always restarted, state must match).
# Pass --resume to reuse an existing consistent state from a previous run.
if $RESUME; then
    info "Resume mode — keeping existing state in $RUN_DIR"
    [[ -d "$RUN_DIR" ]] || die "--resume requires a previous dev-shell run (no $RUN_DIR)"
else
    step "Cleaning previous run state..."
    rm -rf "$RUN_DIR"
    info "Cleared $RUN_DIR"
fi
mkdir -p "$RUN_DIR" "$DATA_DIR"

# ── Build ──────────────────────────────────────────────────────────────────────
if $REBUILD || [[ ! -x "$QPQ" ]] || [[ ! -x "$QPQS" ]]; then
    step "Building workspace (cargo build)..."
    cd "$PROJECT_ROOT"
    cargo build
    info "Build complete."
else
    info "Using cached binaries in $BIN_DIR"
    info "(pass --rebuild to recompile)"
fi
[[ -x "$QPQ"  ]] || die "Client binary not found: $QPQ"
[[ -x "$QPQS" ]] || die "Server binary not found: $QPQS"

# ── Free the port ──────────────────────────────────────────────────────────────
step "Ensuring port $SERVER_PORT is free..."
SERVER_PID=""

free_port() {
    if command -v fuser &>/dev/null; then
        fuser -k "${SERVER_PORT}/tcp" 2>/dev/null || true
    elif command -v lsof &>/dev/null; then
        local pids
        pids=$(lsof -ti "tcp:${SERVER_PORT}" 2>/dev/null || true)
        [[ -n "$pids" ]] && kill $pids 2>/dev/null || true
    fi
}
free_port
sleep 0.3

# ── Cleanup on exit ────────────────────────────────────────────────────────────
cleanup() {
    printf "\n"
    step "Shutting down..."
    tmux kill-session -t "$SESSION" 2>/dev/null || true
    if [[ -n "$SERVER_PID" ]] && kill -0 "$SERVER_PID" 2>/dev/null; then
        info "Stopping qpq-server (PID $SERVER_PID)..."
        kill "$SERVER_PID" 2>/dev/null || true
        wait "$SERVER_PID" 2>/dev/null || true
    fi
    free_port
    info "Done."
}
trap cleanup EXIT INT TERM

# ── Start server ───────────────────────────────────────────────────────────────
step "Starting qpq-server on $SERVER_ADDR..."
"$QPQS" \
    --listen       "$SERVER_ADDR"              \
    --data-dir     "$DATA_DIR"                 \
    --tls-cert     "$DATA_DIR/server-cert.der" \
    --tls-key      "$DATA_DIR/server-key.der"  \
    --allow-insecure-auth                       \
    >"$LOG_FILE" 2>&1 &
SERVER_PID=$!
info "PID $SERVER_PID   log → $LOG_FILE"

# ── Wait for TLS cert (written by server on first boot) ────────────────────────
step "Waiting for server to initialise..."
for i in $(seq 1 20); do
    if [[ -f "$CA_CERT" ]]; then
        info "Server ready after ${i}s (cert present)."
        break
    fi
    if ! kill -0 "$SERVER_PID" 2>/dev/null; then
        warn "Server exited early. Last log output:"
        tail -30 "$LOG_FILE" >&2
        die "Server failed to start."
    fi
    sleep 1
    if [[ $i -eq 20 ]]; then
        tail -30 "$LOG_FILE" >&2
        die "Server did not produce TLS cert within 20s."
    fi
done
sleep 0.5   # brief pause for the QUIC listener to open

QPQ_GLOBAL=(--ca-cert "$CA_CERT" --server-name "$SERVER_NAME")

# ── Build REPL command strings ─────────────────────────────────────────────────
# Registration is handled automatically by the REPL on first launch:
#   1. load_or_init_state creates state file + identity key (if missing)
#   2. opaque_register sends the identity key → server binds username→identity_key
#   3. opaque_login returns a session token → cached for future runs
# Pre-registering here (without an identity key) would break /dm by preventing
# the identity key from ever being bound on a subsequent REPL launch.
repl_cmd() {
    local user="$1" pass="$2"
    echo "$QPQ ${QPQ_GLOBAL[*]} repl \
--state  $RUN_DIR/${user}.bin \
--server $SERVER_ADDR          \
--username $user               \
--password $pass"
}

ALICE_CMD=$(repl_cmd alice alice)
BOB_CMD=$(repl_cmd bob bob)

# ── Build tmux session ─────────────────────────────────────────────────────────
step "Creating tmux session '$SESSION'..."
tmux kill-session -t "$SESSION" 2>/dev/null || true

# ─ Window 0 "chat" layout:
#   top-left  → Alice REPL
#   top-right → Bob REPL
#   bottom    → server log (full width, 30% height)
#
# tmux 3.x renumbers pane indices after each split, so we capture pane IDs
# with -P -F '#{pane_id}' instead of relying on 0.0 / 0.1 / 0.2 arithmetic.

tmux new-session -d -s "$SESSION" -n "chat" -x 220 -y 55

# The initial pane is always %0 / pane 0 — that's Alice.
PANE_ALICE="${SESSION}:0.0"

# Split bottom strip for server log; capture the new pane's stable ID.
PANE_LOG=$(tmux split-window -v -t "$PANE_ALICE" -p 30 -P -F '#{pane_id}')

# Split top-right for Bob from Alice's pane; capture ID.
tmux select-pane -t "$PANE_ALICE"
PANE_BOB=$(tmux split-window -h -t "$PANE_ALICE" -P -F '#{pane_id}')

# Send commands to each pane by stable ID — immune to index renumbering.
tmux send-keys -t "$PANE_LOG" \
    "printf '\\033[0;36m[server log]\\033[0m\\n' && tail -F '$LOG_FILE'" \
    Enter

tmux send-keys -t "$PANE_BOB" \
    "sleep 1.5 && $BOB_CMD" \
    Enter

tmux send-keys -t "$PANE_ALICE" \
    "sleep 0.8 && $ALICE_CMD" \
    Enter

# Pane border labels (tmux ≥ 2.6)
tmux select-pane -t "$PANE_ALICE" -T " ✉  ALICE  │ user=alice  pass=alice "
tmux select-pane -t "$PANE_LOG"   -T " ⚙  SERVER LOG "
tmux select-pane -t "$PANE_BOB"   -T " ✉  BOB    │ user=bob    pass=bob   "

tmux set-option -t "$SESSION" pane-border-status top 2>/dev/null || true
tmux set-option -t "$SESSION" \
    pane-border-format \
    "#{?pane_active,#[bold fg=colour226],#[fg=colour244]} #{pane_title} " \
    2>/dev/null || true

# Focus Alice to start
tmux select-pane -t "$PANE_ALICE"

# ─ Window 1 "ref" — slash-command cheatsheet ──────────────────────────────────
tmux new-window -t "${SESSION}:1" -n "ref"
tmux send-keys  -t "${SESSION}:1" "clear" Enter
# Heredoc piped through cat so it renders immediately and stays visible
tmux send-keys  -t "${SESSION}:1" "cat << 'CHEAT'
╔══════════════════════════════════════════════════════════════════════════╗
║             qpq REPL  ─  Slash Command Cheatsheet                       ║
╠══════════════════════════════════════════════════════════════════════════╣
║  GENERAL                                                                 ║
║    /help                      show all commands in the REPL              ║
║    /whoami                    identity key + hybrid key fingerprint      ║
║    /quit   /q   /exit         exit the REPL                             ║
║                                                                          ║
║  CONVERSATIONS                                                           ║
║    /list    /ls               list all open conversations               ║
║    /switch  @username         make a DM the active conversation         ║
║    /switch  #groupname        make a group the active conversation      ║
║    /history [N]               print last N messages (default: 20)       ║
║    /members                   list all members of the current conv.     ║
║                                                                          ║
║  DIRECT MESSAGES                                                         ║
║    /dm <username>             open or create an encrypted 1:1 DM        ║
║                                                                          ║
║  MLS GROUPS                                                              ║
║    /create-group <name>       create a new MLS group (you are admin)    ║
║    /cg <name>                 alias for /create-group                   ║
║    /invite <username>         invite someone into the current group      ║
║    /join                      accept a pending group Welcome message     ║
║    /leave                     leave the currently active group           ║
║    /remove <username>         remove (kick) a member from the group      ║
║    /kick   <username>         alias for /remove                         ║
║                                                                          ║
╠══════════════════════════════════════════════════════════════════════════╣
║  QUICK START — 1:1 DM TEST                                              ║
║                                                                          ║
║    [Alice]  /dm bob            creates encrypted DM channel             ║
║    [Bob]    (Welcome arrives)  background poller picks it up auto       ║
║    [Alice]  Hello Bob!         send your first message                  ║
║    [Bob]    Hey Alice!         reply                                     ║
║    [Alice]  /history           verify messages are stored               ║
║    [Alice]  /whoami            check identity + hybrid key status       ║
║                                                                          ║
║  QUICK START — GROUP CHAT TEST                                           ║
║                                                                          ║
║    [Alice]  /create-group devtest    create an MLS group               ║
║    [Alice]  /invite bob              send a Welcome to Bob              ║
║    [Bob]    /join                    accept the Welcome                 ║
║    [Alice]  Hello everyone!          send to group                      ║
║    [Bob]    Hi Alice!                reply in group                     ║
║    [Alice]  /members                 verify both Alice + Bob listed     ║
║    [Alice]  /history 50              dump full message log              ║
║    [Alice]  /remove bob              kick Bob (test admin ops)          ║
║    [Bob]    (removed from group)                                         ║
║                                                                          ║
╠══════════════════════════════════════════════════════════════════════════╣
║  TMUX NAVIGATION                                                         ║
║    Ctrl-B  0          window 0 — chat panes (Alice / Bob / log)         ║
║    Ctrl-B  1          window 1 — this cheatsheet                        ║
║    Ctrl-B  ←  →       move between panes in the chat window            ║
║    Ctrl-B  z          zoom current pane to fullscreen (toggle)          ║
║    Ctrl-B  [          scroll mode — use arrows / PgUp/PgDn  (q exits)  ║
║    Ctrl-B  d          detach (session stays alive in background)        ║
║                                                                          ║
║  EXIT / STOP                                                             ║
║    Ctrl-B  :kill-session Enter    kill tmux + triggers script cleanup   ║
║    tmux kill-session -t qpq-dev   from any other terminal               ║
║    /quit  (in Alice or Bob pane)  exit that REPL only                   ║
╚══════════════════════════════════════════════════════════════════════════╝
CHEAT" Enter

# Return focus to the chat window, Alice pane
tmux select-window -t "${SESSION}:0"
tmux select-pane   -t "${SESSION}:0.0"

# ── Print startup summary ──────────────────────────────────────────────────────
printf "\n"
printf "${GRN}╔══════════════════════════════════════════════════════╗${NC}\n"
printf "${GRN}║${NC}  ${GRN}qpq dev shell — ready${NC}                              ${GRN}║${NC}\n"
printf "${GRN}╠══════════════════════════════════════════════════════╣${NC}\n"
printf "${GRN}║${NC}  Session   ${CYN}%s${NC}\n" "$SESSION                                     ${GRN}║${NC}"
printf "${GRN}║${NC}  Server    ${CYN}%s${NC}\n" "$SERVER_ADDR  (log → $LOG_FILE)     ${GRN}║${NC}"
printf "${GRN}║${NC}  Alice     user=${CYN}alice${NC}  pass=${CYN}alice${NC}                   ${GRN}║${NC}\n"
printf "${GRN}║${NC}  Bob       user=${CYN}bob${NC}    pass=${CYN}bob${NC}                     ${GRN}║${NC}\n"
printf "${GRN}║${NC}                                                      ${GRN}║${NC}\n"
printf "${GRN}║${NC}  Quick DM:  ${CYN}[Alice pane]${NC} type:  /dm bob            ${GRN}║${NC}\n"
printf "${GRN}║${NC}  Cheatsheet: Ctrl-B 1 (inside tmux)                  ${GRN}║${NC}\n"
printf "${GRN}║${NC}  Exit:       Ctrl-B :kill-session Enter               ${GRN}║${NC}\n"
printf "${GRN}║${NC}              or from another terminal:                ${GRN}║${NC}\n"
printf "${GRN}║${NC}              tmux kill-session -t qpq-dev             ${GRN}║${NC}\n"
printf "${GRN}╚══════════════════════════════════════════════════════╝${NC}\n"
printf "\n"

# ── Attach ─────────────────────────────────────────────────────────────────────
tmux attach-session -t "$SESSION"

step "Dev shell exited."
