#!/bin/bash
# DB Down Drill - Script de validation opérationnelle
# Objectif: Vérifier que /readyz retourne 503 + status "not_ready" quand DB est down
# Usage: ./scripts/ops_drills/db_down_drill.sh [API_URL] [PROMETHEUS_URL]

set -e

API_URL="${1:-http://localhost:8080}"
PROMETHEUS_URL="${2:-http://localhost:9090}"
DRILL_LOG="/tmp/db_down_drill_$(date +%Y%m%d_%H%M%S).log"

echo "========================================="
echo "DB Down Drill - $(date)"
echo "========================================="
echo "API URL: $API_URL"
echo "Prometheus URL: $PROMETHEUS_URL"
echo "Log: $DRILL_LOG"
echo ""

# Fonction helper pour logger
log() {
    echo "[$(date +%H:%M:%S)] $1" | tee -a "$DRILL_LOG"
}

# Fonction helper pour vérifier métrique Prometheus
check_prometheus_metric() {
    local metric=$1
    local expected_value=$2
    local query="query=$metric"
    
    log "Vérification métrique: $metric"
    local result=$(curl -s "$PROMETHEUS_URL/api/v1/query?$query" | jq -r '.data.result[0].value[1]' 2>/dev/null || echo "N/A")
    
    if [ "$result" != "N/A" ] && [ "$result" != "null" ]; then
        log "  ✓ Métrique trouvée: $metric = $result"
        if [ -n "$expected_value" ]; then
            if [ "$result" == "$expected_value" ]; then
                log "  ✓ Valeur attendue: $expected_value"
                return 0
            else
                log "  ⚠ Valeur inattendue: attendu $expected_value, obtenu $result"
                return 1
            fi
        fi
        return 0
    else
        log "  ✗ Métrique non trouvée ou non disponible"
        return 1
    fi
}

# Étape 1: État initial (baseline)
log "=== ÉTAPE 1: État initial (baseline) ==="
log "Vérification /readyz avant coupure DB..."
initial_response=$(curl -s -w "\n%{http_code}" "$API_URL/readyz" || echo -e "\n000")
initial_body=$(echo "$initial_response" | head -n -1)
initial_status=$(echo "$initial_response" | tail -n 1)

if [ "$initial_status" == "200" ]; then
    log "✓ /readyz retourne 200 (état normal)"
    initial_status_value=$(echo "$initial_body" | jq -r '.data.status' 2>/dev/null || echo "unknown")
    log "  Status: $initial_status_value"
else
    log "⚠ /readyz retourne $initial_status (peut être normal si DB déjà down)"
fi

# Vérifier métriques DB initiales
log ""
log "Métriques DB initiales:"
check_prometheus_metric "veza_db_pool_open_connections" || true
check_prometheus_metric "veza_db_pool_in_use" || true

echo ""
log "=== ÉTAPE 2: Simulation DB Down ==="
log ""
log "OPTIONS:"
log "  1) Arrêter PostgreSQL (nécessite sudo)"
log "  2) Modifier DATABASE_URL pour DSN invalide (recommandé pour staging)"
log "  3) Utiliser firewall pour bloquer port 5432"
log ""
read -p "Choisir option (1/2/3) ou 'skip' pour continuer avec DB actuelle: " option

case $option in
    1)
        log "Arrêt PostgreSQL..."
        if command -v systemctl &> /dev/null; then
            sudo systemctl stop postgresql
            DB_STOPPED=true
        elif command -v docker &> /dev/null; then
            docker stop veza-postgres 2>/dev/null || docker stop $(docker ps -q --filter "ancestor=postgres") 2>/dev/null || true
            DB_STOPPED=true
        else
            log "⚠ Impossible d'arrêter PostgreSQL automatiquement"
            log "  Arrêtez PostgreSQL manuellement et appuyez sur Entrée"
            read
            DB_STOPPED=true
        fi
        ;;
    2)
        log "⚠ Pour modifier DATABASE_URL, redémarrez l'application avec:"
        log "  DATABASE_URL=postgresql://invalid:invalid@invalid:5432/invalid"
        log "  Puis appuyez sur Entrée pour continuer..."
        read
        DB_STOPPED=true
        ;;
    3)
        log "⚠ Pour bloquer le port 5432, utilisez:"
        log "  sudo iptables -A OUTPUT -p tcp --dport 5432 -j DROP"
        log "  Puis appuyez sur Entrée pour continuer..."
        read
        DB_STOPPED=true
        ;;
    skip)
        log "Skip - Utilisation DB actuelle (peut être déjà down)"
        DB_STOPPED=false
        ;;
    *)
        log "Option invalide, skip"
        DB_STOPPED=false
        ;;
esac

# Attendre quelques secondes pour que la connexion expire
log ""
log "Attente 5 secondes pour propagation..."
sleep 5

# Étape 3: Vérifier /readyz après coupure
log ""
log "=== ÉTAPE 3: Vérification /readyz après coupure DB ==="
readyz_response=$(curl -s -w "\n%{http_code}" "$API_URL/readyz" || echo -e "\n000")
readyz_body=$(echo "$readyz_response" | head -n -1)
readyz_status=$(echo "$readyz_response" | tail -n 1)

log "Réponse /readyz:"
log "  HTTP Status: $readyz_status"
log "  Body: $readyz_body"

# Vérifications
SUCCESS=true

if [ "$readyz_status" == "503" ]; then
    log "✓ HTTP Status = 503 (Service Unavailable) - CORRECT"
else
    log "✗ HTTP Status = $readyz_status (attendu: 503) - ÉCHEC"
    SUCCESS=false
fi

status_value=$(echo "$readyz_body" | jq -r '.data.status' 2>/dev/null || echo "unknown")
if [ "$status_value" == "not_ready" ]; then
    log "✓ Status = 'not_ready' - CORRECT"
else
    log "✗ Status = '$status_value' (attendu: 'not_ready') - ÉCHEC"
    SUCCESS=false
fi

db_check_status=$(echo "$readyz_body" | jq -r '.data.checks.database.status' 2>/dev/null || echo "unknown")
if [ "$db_check_status" == "error" ]; then
    log "✓ DB check status = 'error' - CORRECT"
else
    log "⚠ DB check status = '$db_check_status' (attendu: 'error')"
fi

# Étape 4: Vérifier métriques Prometheus
log ""
log "=== ÉTAPE 4: Vérification métriques Prometheus ==="

# Vérifier que les métriques DB sont toujours exposées (même si DB down)
log "Vérification métriques DB pool..."
check_prometheus_metric "veza_db_pool_open_connections" || log "  ⚠ Métrique non disponible (peut être normal)"

# Vérifier wait count (devrait augmenter si pool saturé)
log ""
log "Vérification wait count (devrait augmenter si pool saturé)..."
check_prometheus_metric "veza_db_pool_wait_count_total" || log "  ⚠ Métrique non disponible"

# Étape 5: Vérifier alertes Prometheus
log ""
log "=== ÉTAPE 5: Vérification alertes Prometheus ==="
alerts=$(curl -s "$PROMETHEUS_URL/api/v1/alerts" | jq -r '.data.alerts[] | select(.labels.alertname == "VezaDBPoolExhausted" or .labels.alertname == "VezaReadinessFailed") | .labels.alertname' 2>/dev/null || echo "")

if [ -n "$alerts" ]; then
    log "✓ Alertes déclenchées:"
    echo "$alerts" | while read alert; do
        log "  - $alert"
    done
else
    log "⚠ Aucune alerte déclenchée (peut être normal si seuils non atteints)"
    log "  Vérifier manuellement: $PROMETHEUS_URL/alerts"
fi

# Étape 6: Restauration
log ""
log "=== ÉTAPE 6: Restauration ==="
if [ "$DB_STOPPED" == "true" ]; then
    read -p "Restaurer DB? (y/n): " restore
    if [ "$restore" == "y" ]; then
        case $option in
            1)
                if command -v systemctl &> /dev/null; then
                    sudo systemctl start postgresql
                    log "✓ PostgreSQL redémarré"
                elif command -v docker &> /dev/null; then
                    docker start veza-postgres 2>/dev/null || log "⚠ Redémarrer manuellement le container PostgreSQL"
                fi
                ;;
            3)
                log "Débloquer port 5432:"
                log "  sudo iptables -D OUTPUT -p tcp --dport 5432 -j DROP"
                ;;
        esac
        
        log "Attente 10 secondes pour reconnexion..."
        sleep 10
        
        log "Vérification /readyz après restauration..."
        restored_response=$(curl -s "$API_URL/readyz")
        restored_status=$(echo "$restored_response" | jq -r '.data.status' 2>/dev/null || echo "unknown")
        log "  Status: $restored_status"
        
        if [ "$restored_status" == "ready" ] || [ "$restored_status" == "degraded" ]; then
            log "✓ Service restauré"
        else
            log "⚠ Service pas encore restauré (attendre plus longtemps)"
        fi
    fi
fi

# Résumé
log ""
log "========================================="
log "RÉSUMÉ DU DRILL"
log "========================================="
if [ "$SUCCESS" == "true" ]; then
    log "✓ DRILL RÉUSSI"
    log "  - /readyz retourne 503 quand DB down"
    log "  - Status = 'not_ready'"
    log "  - Métriques exposées"
    exit 0
else
    log "✗ DRILL ÉCHOUÉ"
    log "  Vérifier les points d'échec ci-dessus"
    exit 1
fi
