#!/usr/bin/env bash
# Kanban control TUI — gestiona backend (WSL) + frontend Vite (Windows) desde WSL.
# Lanzamientos fire-and-forget; status panel auto-refresca cada 2s.
# Lanzar: ./control.sh
set -u

BACKEND_PORT=8095
FRONTEND_PORT=5180
APP_DIR="/home/egutierrez/fn_registry/apps/kanban"
BACKEND_LOG="/tmp/kanban.log"
BUILD_LOG="/tmp/kanban_build.log"
MSG_FILE="/tmp/kanban_control.msg"
WIN_FRONT_DIR='C:\Users\egutierrez\fn_apps\kanban\frontend'

RED=$'\033[31m'; GRN=$'\033[32m'; YLW=$'\033[33m'; CYN=$'\033[36m'; BLD=$'\033[1m'; RST=$'\033[0m'

msg() { printf '%s\n' "$*" > "$MSG_FILE"; }

wsl_pid_on_port() {
    local port=$1
    ss -ltnp 2>/dev/null | awk -v p=":$port\$" '$4 ~ p {print $0}' \
        | grep -oP 'pid=\K[0-9]+' | head -1
}

win_pid_on_port() {
    local port=$1
    netstat.exe -ano 2>/dev/null | tr -d '\r' \
        | awk -v p=":$port\$" '$2 ~ p && $4 == "LISTENING" {print $5; exit}'
}

backend_building() {
    [[ -f /tmp/kanban_build.pid ]] && kill -0 "$(cat /tmp/kanban_build.pid 2>/dev/null)" 2>/dev/null
}

# Build + launch en background — retorna inmediatamente
start_backend() {
    if [[ -n $(wsl_pid_on_port "$BACKEND_PORT") ]]; then
        msg "${YLW}backend ya corriendo${RST}"; return 0
    fi
    if backend_building; then
        msg "${YLW}backend ya esta compilando, espera${RST}"; return 0
    fi
    local version
    version=$(awk -F': ' '/^version:/ {print $2; exit}' "$APP_DIR/app.md" 2>/dev/null || echo dev)
    msg "${CYN}lanzando backend en background (version=$version)...${RST}"
    (
        cd "$APP_DIR/backend" || exit 1
        # Rebuild si: binario no existe, .go/.sql mas nuevos, app.md mas nuevo (bump de version)
        if [[ ! -x kanban ]] \
           || [[ -n $(find . -maxdepth 3 \( -name '*.go' -o -name '*.sql' \) -newer kanban 2>/dev/null) ]] \
           || [[ "$APP_DIR/app.md" -nt kanban ]]; then
            CGO_ENABLED=1 go build -tags fts5 \
                -ldflags="-X main.Version=$version" \
                -o kanban . > "$BUILD_LOG" 2>&1 || {
                printf 'build failed — ver %s\n' "$BUILD_LOG" > "$MSG_FILE"
                exit 1
            }
        fi
        cd "$APP_DIR" || exit 1
        KANBAN_CLAUDE_BIN=/home/egutierrez/.local/bin/claude \
            setsid nohup ./backend/kanban --port "$BACKEND_PORT" --db ./operations.db \
            > "$BACKEND_LOG" 2>&1 < /dev/null &
        disown
    ) &
    echo $! > /tmp/kanban_build.pid
    disown
}

stop_backend() {
    local pid
    pid=$(wsl_pid_on_port "$BACKEND_PORT")
    if [[ -z $pid ]]; then
        msg "${YLW}backend ya parado${RST}"; return 0
    fi
    kill "$pid" 2>/dev/null
    ( sleep 1; kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null ) &
    disown
    msg "${GRN}backend stopped (pid $pid)${RST}"
}

wsl_ip() { hostname -I | awk '{print $1}'; }

# WSL frontend → Windows frontend (excluye node_modules, dist, .vite)
sync_frontend() {
    local src="$APP_DIR/frontend/"
    local dst="/mnt/c/Users/egutierrez/fn_apps/kanban/frontend/"
    if [[ ! -d $dst ]]; then
        msg "${RED}no existe $dst${RST}"; return 1
    fi
    rsync -a --delete \
        --exclude node_modules --exclude dist --exclude .vite \
        --exclude .cache --exclude tsconfig.tsbuildinfo \
        "$src" "$dst" 2>&1 | tail -3
    # pnpm install si package.json cambio
    if ! cmp -s "$src/package.json" "$dst/package.json" 2>/dev/null \
       || [[ ! -d "$dst/node_modules" ]]; then
        msg "${CYN}deps cambiaron, lanza pnpm install en Windows...${RST}"
        cmd.exe /c start "" cmd /c "cd /d $WIN_FRONT_DIR && pnpm install" >/dev/null 2>&1 &
        disown
    fi
}

# Lanza ventana cmd Windows con pnpm dev — no bloquea
# Inyecta VITE_API_TARGET con IP WSL real porque localhost forwarding Win→WSL no es fiable
start_vite() {
    if [[ -n $(win_pid_on_port "$FRONTEND_PORT") ]]; then
        msg "${YLW}vite ya corriendo${RST}"; return 0
    fi
    sync_frontend
    local ip target
    ip=$(wsl_ip)
    target="http://${ip}:${BACKEND_PORT}"
    cmd.exe /c start "" cmd /c "cd /d $WIN_FRONT_DIR && set VITE_API_TARGET=$target && pnpm dev --port $FRONTEND_PORT --strictPort --host" >/dev/null 2>&1 &
    disown
    msg "${CYN}vite lanzado, proxy → $target${RST}"
}

stop_vite() {
    local pid
    pid=$(win_pid_on_port "$FRONTEND_PORT")
    if [[ -z $pid ]]; then
        msg "${YLW}vite ya parado${RST}"; return 0
    fi
    taskkill.exe /F /T /PID "$pid" >/dev/null 2>&1 &
    disown
    msg "${GRN}taskkill enviado a vite pid $pid${RST}"
}

kill_stale() {
    local found=0 out=""
    for pid in $(pgrep -f "backend/kanban --port" 2>/dev/null); do
        local cmdl
        cmdl=$(tr '\0' ' ' < /proc/$pid/cmdline 2>/dev/null)
        if ! grep -q -- "--port $BACKEND_PORT" <<<"$cmdl"; then
            kill -9 "$pid" 2>/dev/null
            out+="killed wsl pid $pid ($cmdl); "
            found=1
        fi
    done
    [[ $found -eq 0 ]] && msg "${GRN}sin huerfanos WSL${RST}" || msg "${GRN}${out}${RST}"
}

_prev_frame=""
build_frame() {
    local bpid vpid hc others
    bpid=$(wsl_pid_on_port "$BACKEND_PORT")
    vpid=$(win_pid_on_port "$FRONTEND_PORT")
    local out=""
    out+=$(printf '%s=== Kanban control ===%s' "$BLD" "$RST")$'\n\n'
    if [[ -n $bpid ]]; then
        local rv av
        rv=$(curl -s -m 1 "http://127.0.0.1:$BACKEND_PORT/api/version" | grep -oP '"version":"\K[^"]+' || echo "?")
        av=$(awk -F': ' '/^version:/ {print $2; exit}' "$APP_DIR/app.md" 2>/dev/null || echo "?")
        if [[ "$rv" == "$av" ]]; then
            hc="${GRN}v$rv${RST}"
        else
            hc="${YLW}running=v$rv app.md=v$av (rebuild)${RST}"
        fi
        out+=$(printf '  backend (WSL :%s)   %sUP%s   pid %s   %s' \
            "$BACKEND_PORT" "$GRN" "$RST" "$bpid" "$hc")$'\n'
    elif backend_building; then
        out+=$(printf '  backend (WSL :%s)   %sBUILDING/STARTING%s   tail %s' \
            "$BACKEND_PORT" "$YLW" "$RST" "$BUILD_LOG")$'\n'
    else
        out+=$(printf '  backend (WSL :%s)   %sDOWN%s' "$BACKEND_PORT" "$RED" "$RST")$'\n'
    fi
    # frontend version + drift WSL↔Win
    local fv drift
    fv=$(grep -oP '"version":\s*"\K[^"]+' "$APP_DIR/frontend/package.json" 2>/dev/null || echo "?")
    drift=$(diff -rq "$APP_DIR/frontend/src" "/mnt/c/Users/egutierrez/fn_apps/kanban/frontend/src" 2>/dev/null \
        | grep -c -E "^(Files|Only)" || true)
    local dlbl
    if [[ ${drift:-0} -eq 0 ]]; then
        dlbl="${GRN}sync${RST}"
    else
        dlbl="${YLW}drift=$drift (sync al start)${RST}"
    fi
    if [[ -n $vpid ]]; then
        out+=$(printf '  vite    (WIN :%s)  %sUP%s   pid %s   v%s   %s' "$FRONTEND_PORT" "$GRN" "$RST" "$vpid" "$fv" "$dlbl")$'\n'
    else
        out+=$(printf '  vite    (WIN :%s)  %sDOWN%s   v%s   %s' "$FRONTEND_PORT" "$RED" "$RST" "$fv" "$dlbl")$'\n'
    fi
    others=$(pgrep -af "backend/kanban --port" 2>/dev/null | grep -v -- "--port $BACKEND_PORT" || true)
    if [[ -n $others ]]; then
        out+=$(printf '  %sOTROS kanban backends WSL:%s' "$YLW" "$RST")$'\n'
        out+=$(echo "$others" | sed 's/^/    /')$'\n'
    fi
    out+=$'\n'
    out+=$(printf '%sUltimo evento:%s %s' "$CYN" "$RST" "$(tail -1 "$MSG_FILE" 2>/dev/null || echo '-')")$'\n\n'
    out+="${BLD}Acciones${RST} (auto-refresh 2s, tecla suelta):"$'\n'
    out+="  1) Start backend             5) Start TODO"$'\n'
    out+="  2) Stop backend              6) Stop TODO"$'\n'
    out+="  3) Start vite                7) Mata kanban huerfanos"$'\n'
    out+="  4) Stop vite                 8) Tail backend log"$'\n'
    out+="                               9) Refrescar     0) Salir"$'\n'
    out+="> "
    printf '%s' "$out"
}

draw_status() {
    local frame
    frame=$(build_frame)
    if [[ $frame == "$_prev_frame" ]]; then
        return 0
    fi
    _prev_frame=$frame
    # cursor home + frame + erase-to-end-of-display (limpia lineas residuales)
    printf '\033[H%s\033[J' "$frame"
}

tail_log() {
    clear
    printf '%stail -f %s (Ctrl-C vuelve al menu)%s\n' "$CYN" "$BACKEND_LOG" "$RST"
    trap 'trap - INT; return 0' INT
    tail -f "$BACKEND_LOG" 2>/dev/null
    trap - INT
}

menu() {
    : > "$MSG_FILE"
    # limpia pantalla una sola vez; redraw posterior usa cursor-home
    printf '\033[2J\033[H'
    trap 'printf "\033[?25h\n"; exit 0' EXIT INT TERM
    printf '\033[?25l'  # oculta cursor mientras dibujamos
    while true; do
        draw_status
        # read con timeout 2s — refresco automatico si no hay tecla
        local choice=""
        if read -rsn1 -t 2 choice; then
            case "$choice" in
                1) start_backend ;;
                2) stop_backend ;;
                3) start_vite ;;
                4) stop_vite ;;
                5) start_backend; start_vite ;;
                6) stop_vite; stop_backend ;;
                7) kill_stale ;;
                8) printf '\033[?25h'; tail_log; printf '\033[?25l'; _prev_frame=""; printf '\033[2J\033[H' ;;
                9) : ;;
                0|q|Q) printf '\033[?25h'; clear; exit 0 ;;
                $'\n'|"") : ;;
                *) msg "${RED}opcion invalida: $choice${RST}" ;;
            esac
        fi
    done
}

menu
