#!/usr/bin/env bash
# launch_fleetclaude — Entrypoint MVP de FleetView.
#
# Abre UNA ventana kitty corriendo una sesion tmux de dos panes:
#   - pane izquierdo: la TUI 'fleetview' (la flota de Claudes centralizada).
#   - pane derecho:   'claude --dangerously-skip-permissions'.
#
# Objetivo: dejar de tener N ventanas kitty dispersas y centralizar el control
# de los Claudes en una sola ventana.
#
# Funcion IMPURA: lanza procesos (tmux + kitty) con efectos secundarios.
#   - Crea/reusa una sesion tmux detached llamada <session> (idempotente).
#   - Lanza una ventana kitty desacoplada del shell padre (setsid) para que
#     sobreviva al cierre de la terminal que la invoco.
#   - No toca atajos de teclado ni kitty.conf.
set -euo pipefail
IFS=$' \t\n'

launch_fleetclaude() {
    local cwd=""
    local bin=""
    local session="fleet"
    local cols=52
    local explicit_session=0   # 1 si el usuario pasó --session <name> a mano
    local reuse=0              # 1 si el usuario pidió --reuse (reattach al perfil principal)
    local want_new=0          # 1 si el usuario pidió --new (forzar flota+ventana nueva)
    local T=""                # socket tmux aislado; se fija al resolver el perfil

    # -----------------------------------------------------------------------
    # Parseo de argumentos
    # -----------------------------------------------------------------------
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --cwd)
                shift
                cwd="${1:-}"
                ;;
            --bin)
                shift
                bin="${1:-}"
                ;;
            --session)
                shift
                session="${1:-}"
                explicit_session=1
                ;;
            --reuse)
                reuse=1
                ;;
            --new)
                want_new=1
                ;;
            --cols)
                shift
                cols="${1:-40}"
                ;;
            -h|--help)
                cat <<'USAGE'
Uso: launch_fleetclaude [opciones]

Abre una ventana kitty con una sesion tmux de dos panes: la TUI fleetview a la
izquierda y 'claude --dangerously-skip-permissions' a la derecha.

Cada PERFIL de FleetView es un socket+sesion tmux aislados (su propia flota de
Claudes). Sin --session ni --reuse, cada invocacion abre un perfil NUEVO: usa
el primer nombre libre de la secuencia fleet, fleet2, fleet3, ... Asi puedes
tener varias FleetView abiertas a la vez, cada una con su flota independiente.

REUSO DE CONTEXTO: si ya estas DENTRO de una flota tmux viva (p. ej. en el pane
del orquestador), 'fleetclaude' sin args NO abre una ventana ni crea un perfil
nuevo: trae la TUI al contexto/pane actual (equivale a 'fleetview show'). Para
abrir explicitamente una flota aparte en una ventana nueva, usa --new.

Opciones:
  --cwd <dir>       Directorio de trabajo de los panes.
                    Default: raiz del repo fn_registry (derivada dinamicamente).
  --bin <path>      Ruta al binario de la TUI fleetview.
                    Default: <repo>/apps/fleetview/fleetview
  --session <name>  Fija el perfil (socket+sesion) por nombre exacto; reutiliza
                    el existente si ya esta vivo. Sin esta opcion, perfil auto.
                    Si se invoca DENTRO de tmux con un nombre DISTINTO al de la
                    flota actual, equivale a --new (pides otra flota).
  --reuse           Reattach al perfil principal 'fleet' en vez de abrir uno
                    nuevo (vuelve al comportamiento idempotente clasico).
  --new             Fuerza una flota NUEVA en una ventana NUEVA (kitty/wt.exe),
                    incluso dentro de tmux. Es la via explicita para tener una
                    FleetView aparte; sin este flag, dentro de tmux se reusa el
                    contexto actual.
  --cols <n>        Ancho (columnas) del pane izquierdo. Default: 40.
  -h, --help        Muestra esta ayuda.

Ejemplos:
  launch_fleetclaude                      # dentro de la flota: reusa el contexto;
                                          # fuera de tmux: perfil nuevo (fleet, ...)
  launch_fleetclaude --new                # flota+ventana nueva aunque estes en tmux
  launch_fleetclaude --reuse              # reattach a la flota principal 'fleet'
  launch_fleetclaude --session trabajo    # perfil con nombre fijo 'trabajo'
  launch_fleetclaude --cwd ~/fn_registry --cols 50
USAGE
                return 0
                ;;
            *)
                echo "launch_fleetclaude: opcion desconocida: '$1' (usa -h)" >&2
                return 2
                ;;
        esac
        shift
    done

    # -----------------------------------------------------------------------
    # Derivar la raiz del repo fn_registry dinamicamente (NO hardcodear paths
    # de usuario). Estrategia: subir desde la ubicacion del script con
    # 'git rev-parse --show-toplevel'; fallbacks razonables si no aplica.
    # -----------------------------------------------------------------------
    local script_dir repo_root=""
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    # El script vive en <repo>/bash/functions/infra/, asi que la raiz son 3
    # niveles arriba; pero preferimos git para robustez.
    repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || true)"
    if [[ -z "$repo_root" ]]; then
        # Fallback 1: navegacion relativa desde la ubicacion del script.
        repo_root="$(cd "$script_dir/../../.." 2>/dev/null && pwd || true)"
    fi
    if [[ -z "$repo_root" ]]; then
        # Fallback 2: variable de entorno del registry o el cwd actual.
        repo_root="${FN_REGISTRY_ROOT:-$PWD}"
    fi

    # Defaults derivados de la raiz del repo.
    [[ -z "$cwd" ]] && cwd="$repo_root"
    [[ -z "$bin" ]] && bin="$repo_root/apps/fleetview/fleetview"

    # Validar cwd: si no existe, caer al repo_root.
    if [[ ! -d "$cwd" ]]; then
        echo "launch_fleetclaude: --cwd '$cwd' no existe; usando '$repo_root'." >&2
        cwd="$repo_root"
    fi

    # -----------------------------------------------------------------------
    # Comprobar herramientas necesarias.
    # -----------------------------------------------------------------------
    if ! command -v tmux >/dev/null 2>&1; then
        echo "launch_fleetclaude: tmux no esta instalado." >&2
        return 1
    fi

    # -----------------------------------------------------------------------
    # REUSO DE CONTEXTO (sin --new): si ya estamos DENTRO de una flota tmux
    # viva, 'fleetclaude' sin args NO abre una ventana/terminal nueva ni crea
    # un perfil fleetN+1 — trae la TUI al contexto/pane actual, igual que
    # 'fleetview show'. El flag --new fuerza el comportamiento clasico (flota
    # nueva en ventana nueva); --reuse mantiene su semantica historica.
    #
    # El perfil de la flota actual se deriva de $TMUX (el basename del socket
    # es el nombre -L; senal fiable aunque $FLEET_SOCKET venga vacio, ver
    # detect_fleet_context). Si se paso --session con un nombre DISTINTO al
    # actual, es pedir OTRA flota -> se trata como --new implicito (no reusa).
    # "Flota viva" = el socket tiene una sesion homonima con una window
    # 'console' (la firma de una FleetView), no un tmux cualquiera.
    # -----------------------------------------------------------------------
    if [[ "$want_new" -eq 0 && "$reuse" -eq 0 && -n "${TMUX:-}" ]]; then
        local current_socket target_socket
        current_socket="$(basename "${TMUX%%,*}")"
        target_socket="$current_socket"
        [[ "$explicit_session" -eq 1 ]] && target_socket="$session"

        if [[ "$target_socket" == "$current_socket" ]] \
           && tmux -L "$current_socket" has-session -t "$current_socket" 2>/dev/null \
           && tmux -L "$current_socket" list-windows -t "$current_socket" \
                   -F '#{window_name}' 2>/dev/null | grep -qx console; then
            # Traer la TUI al contexto actual sin abrir nada nuevo. Preferimos
            # el binario (centraliza la politica en la app: 'fleetview show');
            # si no esta compilado, caemos a 'select-window' directo, que es lo
            # que 'show' hace por dentro dentro de tmux (cero dependencia).
            if [[ -x "$bin" ]] \
               && FLEET_SOCKET="$current_socket" FLEET_SESSION="$current_socket" \
                  "$bin" show 2>/dev/null; then
                return 0
            fi
            tmux -L "$current_socket" select-window -t "$current_socket":console
            echo "launch_fleetclaude: flota '$current_socket' viva; TUI traida al contexto actual (sin ventana nueva)."
            return 0
        fi
    fi

    # -----------------------------------------------------------------------
    # Resolver el PERFIL (socket+sesion tmux comparten nombre).
    #
    #   - --session <name>  -> usa ese nombre exacto (reutiliza si ya vive).
    #   - --reuse           -> usa 'fleet' (el perfil principal), idempotente.
    #   - sin nada          -> perfil NUEVO: primer nombre libre de la secuencia
    #                          fleet, fleet2, fleet3, ... Asi abrir FleetView con
    #                          uno ya abierto arranca otra flota, no la reusa.
    #
    # "Libre" = no hay un server tmux con esa sesion (has-session falla). Un
    # perfil cerrado libera su nombre, asi que tras cerrar 'fleet' el siguiente
    # lanzamiento vuelve a 'fleet'.
    # -----------------------------------------------------------------------
    if [[ "$explicit_session" -eq 0 && "$reuse" -eq 0 ]]; then
        local base="$session" n=1 cand
        while :; do
            if [[ "$n" -eq 1 ]]; then cand="$base"; else cand="${base}${n}"; fi
            if ! tmux -L "$cand" has-session -t "$cand" 2>/dev/null; then
                session="$cand"
                break
            fi
            n=$((n + 1))
        done
        echo "launch_fleetclaude: perfil nuevo '$session'."
    fi
    # A partir de aqui el socket aislado es el del perfil resuelto.
    T="tmux -L $session"
    # Nota: kitty NO se exige aqui. La ruta interactiva (TTY) reutiliza la
    # terminal actual con `exec tmux attach` y no necesita kitty. Solo la
    # ruta sin-TTY (abrir ventana nueva con setsid kitty) lo requiere, y ahi
    # se comprueba justo antes de usarlo.

    # -----------------------------------------------------------------------
    # Comando para el pane izquierdo:
    #   - Si el binario fleetview existe -> ejecutarlo (exec, sin shell colgado).
    #   - Si NO existe -> mensaje claro + shell interactiva (no falla en silencio).
    # -----------------------------------------------------------------------
    # La TUI necesita saber a qué perfil pertenece: se lo pasamos por entorno
    # (FLEET_SOCKET/FLEET_SESSION), que main.go lee con fallback a "fleet".
    local envpfx
    envpfx="FLEET_SOCKET=$(printf '%q' "$session") FLEET_SESSION=$(printf '%q' "$session")"
    local left_cmd
    if [[ -x "$bin" ]]; then
        # NO un `exec fleetview` de una sola vida: lo envolvemos en el bucle
        # supervisor supervise_fleetview_tui, que relanza la TUI si muere (crash,
        # panic, kill de su proceso o de su pane). Asi el panel de control de la
        # flota NUNCA se pierde por un fallo puntual. El supervisor para limpio
        # con su sentinel (touch ~/.claude/fleet/tui_stop_<perfil>) o se rinde si
        # la TUI entra en crash-loop; en ambos casos cae a una shell viva.
        local sup="$repo_root/bash/functions/infra/supervise_fleetview_tui.sh"
        if [[ -f "$sup" ]]; then
            # bash <sup> (no exec): al volver el supervisor (sentinel o crash-loop)
            # caemos a una shell viva para que el mensaje siga visible y se pueda
            # inspeccionar/relanzar. El env aplica al supervisor y a su hijo TUI.
            left_cmd="$envpfx bash $(printf '%q' "$sup") --bin $(printf '%q' "$bin") --socket $(printf '%q' "$session"); exec \"\$SHELL\""
        else
            # Fallback si falta el supervisor en disco: comportamiento clasico.
            left_cmd="$envpfx exec $(printf '%q' "$bin")"
        fi
    else
        # Fallback claro: instruye como compilar la TUI y deja una shell viva.
        left_cmd="echo 'fleetview no compilado: cd apps/fleetview && go build -o fleetview .'; exec \"\$SHELL\""
    fi

    # -----------------------------------------------------------------------
    # Montar la sesion tmux SOLO si no existe (idempotencia). Socket aislado $T.
    #
    # Targeting por PANE ID (%0/%1), no por indice (console.0). El socket
    # -L fleet sigue leyendo ~/.tmux.conf; si el usuario tiene
    # `base-index 1` / `pane-base-index 1` (muy comun), el primer pane es el
    # indice 1 y cualquier referencia a console.0 falla con
    # "can't find pane: 0". Los pane ID son estables e inmunes al base-index.
    # -----------------------------------------------------------------------
    # Inicializadas a "" (no solo declaradas): bajo `set -u` una `local x` sin
    # valor queda *unbound*, y al reutilizar una sesion existente el `[[ -z
    # "$left_pane" ]]` de mas abajo reventaba con "unbound variable".
    local left_pane="" right_pane=""
    if $T has-session -t "$session" 2>/dev/null; then
        echo "launch_fleetclaude: la sesion tmux '$session' ya existe; reutilizandola."
    else
        echo "launch_fleetclaude: creando sesion tmux '$session' en '$cwd'."

        # Sesion detached con ventana 'console'. Capturamos el pane ID del pane
        # izquierdo (la TUI fleetview, o el fallback claro).
        left_pane=$($T new-session -d -s "$session" -n console -c "$cwd" -P -F '#{pane_id}')
        $T send-keys -t "$left_pane" "$left_cmd" C-m

        # pane derecho = el ORQUESTADOR de la flota: un Claude que arranca ya en
        # modo orquestador invocando el skill /orquestador como primer prompt. Es
        # el Claude con el que el humano habla; vigila la flota por su DoD.
        right_pane=$($T split-window -h -t "$left_pane" -c "$cwd" -P -F '#{pane_id}')
        $T send-keys -t "$right_pane" "exec claude --dangerously-skip-permissions '/orquestador'" C-m

        # Fijar el ancho del pane izquierdo en columnas.
        $T resize-pane -t "$left_pane" -x "$cols"

        # Foco inicial en el pane del orquestador (derecha).
        $T select-pane -t "$right_pane"

        # Marcar el orquestador con role=orchestrator en su goal.json para que la
        # TUI lo pinee arriba (estrella). El sessionId no se conoce hasta que
        # Claude escribe sessions/<PID>.json; mark_claude_role resuelve
        # PID->sessionId esperando ese archivo. En background (no bloquea el
        # arranque) y con sleep para que el `exec claude` reemplace al shell antes
        # de leer el pane_pid. Fallo = no-fatal (el orquestador no se pinea).
        if [[ -x "$repo_root/fn" ]]; then
            ( sleep 1
              orch_pid=$($T display-message -p -t "$right_pane" '#{pane_pid}' 2>/dev/null || true)
              [[ -n "$orch_pid" ]] && "$repo_root/fn" run mark_claude_role "$orch_pid" orchestrator >/dev/null 2>&1
            ) >/dev/null 2>&1 &
            disown 2>/dev/null || true
        fi

        # Sembrar 1 ejecutor idle: una window detached con un claude normal,
        # listo para recibir tarea del orquestador. Aparece en la TUI bajo el
        # orquestador (role executor por defecto). Hereda FLEET_SOCKET/SESSION
        # del server (set-environment), asi apunta a este perfil.
        local idle_pane
        idle_pane=$($T new-window -d -t "$session" -n claude -c "$cwd" -P -F '#{pane_id}')
        $T send-keys -t "$idle_pane" "exec claude --dangerously-skip-permissions" C-m
    fi

    # Si reutilizamos sesion (o por seguridad), derivar el pane ID de la TUI:
    # el primer pane de la ventana 'console' (orden por indice) es el izquierdo.
    if [[ -z "$left_pane" ]]; then
        left_pane=$($T list-panes -t "$session":console -F '#{pane_id}' 2>/dev/null | head -n1)
    fi

    # -----------------------------------------------------------------------
    # Atajos globales (alt+*) en el socket aislado: redirigen la tecla al pane
    # de la TUI (console.0) ESTES DONDE ESTES, para controlar la flota sin salir
    # del pane de Claude. La TUI (fleetview) es quien interpreta Up/Down/Enter/n.
    # `bind -n` = tabla root (sin prefijo). Idempotente: re-set en cada lanzamiento.
    # -----------------------------------------------------------------------
    $T bind -n M-Up    send-keys -t "$left_pane" Up
    $T bind -n M-Down  send-keys -t "$left_pane" Down
    $T bind -n M-Enter send-keys -t "$left_pane" Enter
    $T bind -n M-n     send-keys -t "$left_pane" n
    $T bind -n M-0     send-keys -t "$left_pane" n
    $T bind -n M-k     send-keys -t "$left_pane" k
    $T bind -n M-r     send-keys -t "$left_pane" r
    $T bind -n M-u     send-keys -t "$left_pane" u
    $T bind -n M-h     send-keys -t "$left_pane" h
    $T bind -n M-R     send-keys -t "$left_pane" R
    $T bind -n M-Left  send-keys -t "$left_pane" Escape
    $T bind -n M-q     send-keys -t "$left_pane" Q
    # Entorno del perfil en el server tmux: respawn-pane (alt+R, recompila la TUI)
    # y los Claude nuevos heredan FLEET_SOCKET/FLEET_SESSION para apuntar al
    # socket correcto aunque no sea el default "fleet".
    $T set-environment -g FLEET_SOCKET "$session"
    $T set-environment -g FLEET_SESSION "$session"
    # Raton: enruta clicks/rueda al pane bajo el cursor; la TUI los interpreta.
    $T set -g mouse on
    # Al salir un Claude (exit / Ctrl-D / kill), cerrar su window en vez de
    # dejarla muerta ("dead" pane) en la sesion.
    $T set -g remain-on-exit off

    # Estetica neutra: sin el verde fosforo por defecto de tmux. Status bar gris y
    # bordes de pane gris tenue, iguales en activo e inactivo (separacion simple,
    # sin resaltado de enfoque).
    $T set -g status-style "bg=colour236,fg=colour250"
    $T set -g pane-border-style "fg=colour238"
    $T set -g pane-active-border-style "fg=colour240"

    # Mantener el ancho del sidebar (pane 0) cuando kitty redimensiona la ventana
    # tras el attach, o cuando se conmuta de Claude (window-linked / layout change).
    $T set-hook -g client-resized        "resize-pane -t $left_pane -x $cols"
    $T set-hook -g window-layout-changed "resize-pane -t $left_pane -x $cols"

    # -----------------------------------------------------------------------
    # Adjuntar la sesion en una terminal, DESACOPLADA del shell padre para que
    # no muera al cerrar la terminal invocadora.
    # -----------------------------------------------------------------------
    # Adjuntar la sesion:
    #   - Terminal interactiva y FUERA de tmux: convertir ESA terminal en el
    #     panel FleetView (exec reemplaza el proceso; al hacer detach vuelve la
    #     shell). Asi `fleetclaude` no abre otra ventana: usa la actual.
    #   - DENTRO de tmux (o sin TTY: atajo de escritorio, cron, script): abrir
    #     una ventana de terminal NUEVA desacoplada. No hacemos `attach`
    #     anidado dentro de otra sesion tmux (rompe / da el warning de nesting).
    if [ -t 0 ] && [ -t 1 ] && [ -z "${TMUX:-}" ]; then
        exec tmux -L "$session" attach -t "$session"
    fi

    # -----------------------------------------------------------------------
    # Ruta ventana-nueva: AUTO-DETECTAR la terminal disponible (sin config por
    # PC). El mismo `fleetclaude` funciona en un escritorio Linux con kitty y en
    # un WSL sin kitty pero con Windows Terminal.
    #   1. kitty instalado + display usable ($DISPLAY/$WAYLAND_DISPLAY) -> kitty
    #      (escritorio Linux nativo, o WSLg con kitty instalado).
    #   2. WSL con wt.exe alcanzable -> Windows Terminal ejecutando wsl.exe que
    #      adjunta la sesion tmux (PCs WSL sin kitty: la ventana kitty nunca
    #      aparece sin una terminal Linux real, por eso "se lanza pero no se ve").
    #   3. Ninguna -> error claro con las dos salidas posibles.
    # -----------------------------------------------------------------------
    if command -v kitty >/dev/null 2>&1 && [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
        setsid kitty --title "FleetView ($session)" -e tmux -L "$session" attach -t "$session" </dev/null >/dev/null 2>&1 &
        disown 2>/dev/null || true
        echo "launch_fleetclaude: ventana kitty 'FleetView ($session)' adjunta al perfil '$session'."
        return 0
    fi

    if command -v wt.exe >/dev/null 2>&1; then
        # bash -lic <attach> dentro de wsl.exe: login+interactive para que tmux y
        # el PATH del perfil esten disponibles en la ventana de Windows Terminal.
        local attach_cmd
        attach_cmd="tmux -L $(printf '%q' "$session") attach -t $(printf '%q' "$session")"
        local distro="${WSL_DISTRO_NAME:-}"
        local wsl_args=(wsl.exe)
        [[ -n "$distro" ]] && wsl_args+=(-d "$distro")
        wsl_args+=(-- bash -lic "$attach_cmd")
        # cd a una ruta Windows (/mnt/c) evita el warning de wt.exe por cwd UNC
        # (\\wsl.localhost\...). El cwd real de los panes lo fija la sesion tmux.
        ( cd /mnt/c 2>/dev/null || cd /
          wt.exe new-tab --title "FleetView ($session)" "${wsl_args[@]}" </dev/null >/dev/null 2>&1 &
          disown 2>/dev/null || true )
        echo "launch_fleetclaude: Windows Terminal 'FleetView ($session)' adjunta al perfil '$session' (WSL distro '${distro:-default}')."
        return 0
    fi

    echo "launch_fleetclaude: no hay terminal para abrir una ventana nueva." >&2
    echo "launch_fleetclaude:   - escritorio Linux: instala kitty y exporta DISPLAY/WAYLAND_DISPLAY." >&2
    echo "launch_fleetclaude:   - WSL: usa Windows Terminal (wt.exe debe estar en el PATH)." >&2
    echo "launch_fleetclaude:   - o lanza fleetclaude desde una terminal interactiva fuera de tmux." >&2
    return 1
}

# Permitir ejecutar el archivo directamente (no solo como funcion sourced).
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    launch_fleetclaude "$@"
fi
