#!/bin/bash
# Gestion du homelab Funk (storage-01 + gpu-01)
# Usage: funk-cluster [start|stop|status]

GPU01_IP="192.168.10.20"
GPU01_MAC="a8:a1:59:72:a6:11"  # WOL — adresse MAC de gpu-01 (NIC principal)
GPU01_SSH="ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no gpu-01"

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m'

ok()   { echo -e "  ${GREEN}✓${NC} $*"; }
fail() { echo -e "  ${RED}✗${NC} $*"; }
warn() { echo -e "  ${YELLOW}!${NC} $*"; }
info() { echo -e "  → $*"; }

CHECKS_OK=0
CHECKS_FAIL=0

check_ok()   { ok "$*";   CHECKS_OK=$((CHECKS_OK + 1)); }
check_fail() { fail "$*"; CHECKS_FAIL=$((CHECKS_FAIL + 1)); }

# --- Wake-on-LAN (python3, pas de dépendance externe) ---
wol() {
    local mac="${1//:}"
    python3 -c "
import socket
mac = '$mac'
payload = bytes.fromhex('ff' * 6 + mac * 16)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(payload, ('192.168.10.255', 9))
s.close()
"
    echo -e "  → Paquet WOL envoyé vers $1"
}

# --- Vérification service systemd ---
check_service() {
    local svc=$1
    if systemctl is-active --quiet "$svc" 2>/dev/null; then
        check_ok "$svc"
        return 0
    else
        check_fail "$svc (inactif)"
        return 1
    fi
}

# --- Vérification PostgreSQL (connexion réelle via postgres) ---
check_postgresql() {
    if sudo -u postgres psql -c "SELECT 1" hermes &>/dev/null 2>&1; then
        check_ok "PostgreSQL — base hermes accessible"
    else
        check_fail "PostgreSQL — base hermes inaccessible"
    fi
}

# --- Vérification Qdrant ---
check_qdrant() {
    local result
    result=$(curl -sf --max-time 5 "http://127.0.0.1:6333/collections" \
        | python3 -c "
import sys, json
d = json.load(sys.stdin)
cols = d.get('result', {}).get('collections', [])
print(len(cols))
" 2>/dev/null)
    if [ -n "$result" ]; then
        check_ok "Qdrant — $result collection(s)"
    else
        check_fail "Qdrant non joignable (port 6333)"
    fi
}

# --- Vérification LiteLLM ---
check_litellm() {
    local models
    models=$(curl -sf --max-time 5 \
        -H "Authorization: Bearer lm-studio" \
        "http://127.0.0.1:4000/v1/models" \
        | python3 -c "
import sys, json
d = json.load(sys.stdin).get('data', [])
print(', '.join(m['id'] for m in d))
" 2>/dev/null)
    if [ -n "$models" ]; then
        check_ok "LiteLLM — modèles : $models"
    else
        check_fail "LiteLLM non joignable (port 4000)"
    fi
}

# --- Vérification Hermes HTTP ---
check_hermes() {
    if curl -sf --max-time 5 "http://127.0.0.1:8080/health" &>/dev/null; then
        check_ok "Hermes HTTP (port 8080)"
    elif systemctl is-active --quiet hermes-agent 2>/dev/null; then
        check_ok "Hermes service actif (pas d'endpoint HTTP)"
    else
        check_fail "Hermes inactif"
    fi
}

# --- Vérification NFS export ---
check_nfs_export() {
    if showmount -e localhost 2>/dev/null | grep -q "/srv/data/models"; then
        check_ok "NFS export /srv/data/models OK"
    else
        check_fail "NFS export /srv/data/models manquant"
    fi
}

# --- Vérification llama-server sur gpu-01 ---
check_llama_server() {
    local model
    model=$(curl -sf --max-time 5 "http://${GPU01_IP}:1234/v1/models" \
        | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data'][0]['id'])" 2>/dev/null)
    if [ -n "$model" ]; then
        check_ok "llama-server — modèle : $model"
        return 0
    else
        check_fail "llama-server (non joignable)"
        return 1
    fi
}

# --- Vérification embeddings ---
check_embeddings() {
    local dim
    dim=$(curl -sf --max-time 15 -X POST "http://${GPU01_IP}:1234/v1/embeddings" \
        -H "Content-Type: application/json" \
        -d '{"model":"qwen3-8b","input":["test"]}' \
        | python3 -c "import sys,json; print(len(json.load(sys.stdin)['data'][0]['embedding']))" 2>/dev/null)
    if [ -n "$dim" ]; then
        check_ok "Embeddings OK — dimension : $dim"
    else
        check_fail "Embeddings non disponibles"
    fi
}

# --- Attendre qu'un hôte réponde au ping ---
wait_ping() {
    local host=$1 timeout=${2:-120} elapsed=0
    while ! ping -c1 -W1 "$host" &>/dev/null; do
        sleep 3; elapsed=$((elapsed + 3))
        [ $elapsed -ge $timeout ] && return 1
        echo -ne "  → Attente ping $host... ${elapsed}s\r"
    done
    echo ""
    return 0
}

# --- Attendre llama-server HTTP ---
wait_llama() {
    local timeout=${1:-240} elapsed=0
    while ! curl -sf --max-time 3 "http://${GPU01_IP}:1234/v1/models" &>/dev/null; do
        sleep 5; elapsed=$((elapsed + 5))
        [ $elapsed -ge $timeout ] && return 1
        echo -ne "  → Attente llama-server... ${elapsed}s\r"
    done
    echo ""
    return 0
}

# --- Afficher le score final ---
print_score() {
    local total=$((CHECKS_OK + CHECKS_FAIL))
    echo ""
    if [ $CHECKS_FAIL -eq 0 ]; then
        echo -e "  ${GREEN}${BOLD}[$CHECKS_OK/$total] Tous les checks OK${NC}"
    else
        echo -e "  ${YELLOW}${BOLD}[$CHECKS_OK/$total] — $CHECKS_FAIL check(s) en échec${NC}"
    fi
}

# ============================================================
# STATUS
# ============================================================
cmd_status() {
    CHECKS_OK=0; CHECKS_FAIL=0
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "  FUNK — État du homelab"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    echo ""
    echo "[ storage-01 — services ]"
    check_service postgresql-16
    check_service qdrant
    check_service litellm
    check_service hermes-agent

    echo ""
    echo "[ storage-01 — santé ]"
    check_postgresql
    check_qdrant
    check_litellm
    check_hermes
    check_nfs_export

    echo ""
    echo "[ gpu-01 — 192.168.10.20 ]"
    if ping -c1 -W2 "$GPU01_IP" &>/dev/null; then
        check_ok "ping OK"
        check_llama_server
        check_embeddings
        if $GPU01_SSH "mountpoint -q /mnt/models" 2>/dev/null; then
            check_ok "NFS /mnt/models monté"
        else
            check_fail "NFS /mnt/models non monté"
        fi
    else
        check_fail "gpu-01 non joignable (éteint ?)"
    fi

    print_score
    echo ""
}

# ============================================================
# START
# ============================================================
cmd_start() {
    CHECKS_OK=0; CHECKS_FAIL=0
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "  FUNK — Démarrage"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    # 1. Services storage-01
    echo ""
    echo "[ storage-01 — démarrage des services ]"
    for svc in postgresql-16 qdrant litellm hermes-agent; do
        systemctl start "$svc" 2>/dev/null
        sleep 1
        if systemctl is-active --quiet "$svc"; then
            ok "$svc démarré"
        else
            warn "$svc — problème au démarrage (voir: journalctl -u $svc -n 20)"
        fi
    done

    # 2. Vérifications santé storage-01
    echo ""
    echo "[ storage-01 — vérifications ]"
    sleep 2  # laisser les services s'initialiser
    check_postgresql
    check_qdrant
    check_litellm
    check_hermes
    check_nfs_export

    # 3. gpu-01 — Wake-on-LAN si éteint
    echo ""
    echo "[ gpu-01 — démarrage ]"
    if ping -c1 -W2 "$GPU01_IP" &>/dev/null; then
        check_ok "gpu-01 déjà allumé"
    else
        wol "$GPU01_MAC"
        info "Attente du démarrage de gpu-01..."
        if ! wait_ping "$GPU01_IP" 120; then
            check_fail "gpu-01 n'a pas répondu au ping en 120s"
            print_score
            return 1
        fi
        check_ok "gpu-01 joignable"
        # Attendre que SSH soit disponible
        local ssh_tries=0
        while ! $GPU01_SSH "true" 2>/dev/null; do
            sleep 3; ssh_tries=$((ssh_tries + 1))
            [ $ssh_tries -ge 10 ] && break
            echo -ne "  → Attente SSH gpu-01... $((ssh_tries * 3))s\r"
        done
        echo ""
    fi

    # 4. Vérifier NFS sur gpu-01
    info "Vérification NFS sur gpu-01..."
    local nfs_tries=0
    while ! $GPU01_SSH "mountpoint -q /mnt/models" 2>/dev/null; do
        sleep 3; nfs_tries=$((nfs_tries + 1))
        [ $nfs_tries -ge 20 ] && break
        echo -ne "  → Attente montage NFS... $((nfs_tries * 3))s\r"
    done
    echo ""
    if $GPU01_SSH "mountpoint -q /mnt/models" 2>/dev/null; then
        check_ok "NFS /mnt/models monté sur gpu-01"
    else
        check_fail "NFS /mnt/models non monté (modèle non accessible)"
    fi

    # 5. Attendre llama-server
    echo ""
    echo "[ gpu-01 — llama-server ]"
    info "Attente chargement du modèle LLM (jusqu'à 4 min)..."
    if wait_llama 240; then
        check_llama_server
        check_embeddings
    else
        check_fail "llama-server n'a pas répondu en 4 minutes"
    fi

    # 6. Score final
    print_score
    if [ $CHECKS_FAIL -eq 0 ]; then
        echo -e "  ${GREEN}Homelab Funk opérationnel — bonne session !${NC}"
    else
        echo -e "  ${YELLOW}Homelab démarré avec des avertissements${NC}"
    fi
    echo ""
}

# ============================================================
# STOP
# ============================================================
cmd_stop() {
    echo ""
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo "  FUNK — Arrêt"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    # 1. Arrêter Hermes et LiteLLM proprement
    echo ""
    echo "[ storage-01 — arrêt des services applicatifs ]"
    for svc in hermes-agent litellm; do
        systemctl stop "$svc" 2>/dev/null && ok "$svc arrêté" || warn "$svc déjà inactif"
    done

    # 2. Éteindre gpu-01
    echo ""
    echo "[ gpu-01 — arrêt ]"
    if ping -c1 -W2 "$GPU01_IP" &>/dev/null; then
        info "Arrêt de gpu-01..."
        $GPU01_SSH "sudo shutdown -h now" 2>/dev/null
        local tries=0
        while ping -c1 -W1 "$GPU01_IP" &>/dev/null; do
            sleep 2; tries=$((tries + 1))
            [ $tries -ge 30 ] && break
            echo -ne "  → Extinction en cours... $((tries * 2))s\r"
        done
        echo ""
        ok "gpu-01 éteint"
    else
        warn "gpu-01 déjà éteint"
    fi

    # 3. Arrêter Qdrant et PostgreSQL
    echo ""
    echo "[ storage-01 — arrêt des services données ]"
    for svc in qdrant postgresql-16; do
        systemctl stop "$svc" 2>/dev/null && ok "$svc arrêté" || warn "$svc déjà inactif"
    done

    echo ""
    ok "Homelab Funk arrêté proprement"
    echo ""
}

# ============================================================
case "${1:-status}" in
    start)  cmd_start ;;
    stop)   cmd_stop  ;;
    status) cmd_status ;;
    *)
        echo "Usage: funk-cluster [start|stop|status]"
        echo ""
        echo "  start   Démarre gpu-01 (WOL) + vérifie tous les services"
        echo "  stop    Arrêt propre gpu-01 + services storage-01"
        echo "  status  État de tous les services"
        exit 1
        ;;
esac
