#!/usr/bin/env bash
#
# Test d'intégration pour l'orchestrateur Skull Pi
# Vérifie le fonctionnement complet du système
#

set -euo pipefail

# Configuration
ORCHESTRATOR_HOST="localhost"
ORCHESTRATOR_PORT="8080"
MQTT_HOST="localhost"
MQTT_PORT="1883"
BASE_URL="http://${ORCHESTRATOR_HOST}:${ORCHESTRATOR_PORT}"

# Couleurs pour l'affichage
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Fonction de logging
log() {
    echo -e "${BLUE}[$(date '+%H:%M:%S')] $*${NC}"
}

success() {
    echo -e "${GREEN}✓ $*${NC}"
}

error() {
    echo -e "${RED}✗ $*${NC}"
}

warning() {
    echo -e "${YELLOW}⚠ $*${NC}"
}

# Vérifier prérequis
check_prerequisites() {
    log "Vérification des prérequis..."
    
    # Vérifier curl
    if ! command -v curl &> /dev/null; then
        error "curl n'est pas installé"
        exit 1
    fi
    
    # Vérifier jq pour parsing JSON
    if ! command -v jq &> /dev/null; then
        warning "jq non installé, affichage JSON limité"
        JQ_AVAILABLE=false
    else
        JQ_AVAILABLE=true
    fi
    
    # Vérifier mosquitto clients
    if ! command -v mosquitto_pub &> /dev/null; then
        warning "mosquitto_clients non installés, tests MQTT limités"
        MQTT_AVAILABLE=false
    else
        MQTT_AVAILABLE=true
    fi
    
    success "Prérequis vérifiés"
}

# Attendre que l'orchestrateur soit prêt
wait_for_orchestrator() {
    log "Attente orchestrateur sur $BASE_URL..."
    
    for i in {1..30}; do
        if curl -s "$BASE_URL/health" &> /dev/null; then
            success "Orchestrateur prêt"
            return 0
        fi
        echo -n "."
        sleep 1
    done
    
    error "Orchestrateur non accessible après 30s"
    exit 1
}

# Test API de base
test_basic_api() {
    log "Test API de base..."
    
    # Health check
    log "  → Health check"
    response=$(curl -s "$BASE_URL/health")
    if [[ $JQ_AVAILABLE == true ]]; then
        status=$(echo "$response" | jq -r '.status')
        if [[ "$status" == "healthy" ]]; then
            success "Health check OK"
        else
            error "Health check failed: $status"
            return 1
        fi
    else
        if [[ "$response" == *"healthy"* ]]; then
            success "Health check OK"
        else
            error "Health check failed"
            return 1
        fi
    fi
    
    # Status global
    log "  → Status global"
    response=$(curl -s "$BASE_URL/status")
    if [[ $JQ_AVAILABLE == true ]]; then
        state=$(echo "$response" | jq -r '.orchestrator.state')
        mode=$(echo "$response" | jq -r '.orchestrator.mode')
        log "    État: $state, Mode: $mode"
        success "Status OK"
    else
        if [[ "$response" == *"orchestrator"* ]]; then
            success "Status OK"
        else
            error "Status failed"
            return 1
        fi
    fi
    
    # Documentation Swagger
    log "  → Documentation API"
    if curl -s "$BASE_URL/docs" | grep -q "swagger"; then
        success "Documentation disponible"
    else
        warning "Documentation non accessible"
    fi
}

# Test gestion des modes
test_mode_management() {
    log "Test gestion des modes..."
    
    # Mode initial
    log "  → Mode initial"
    response=$(curl -s "$BASE_URL/mode")
    if [[ $JQ_AVAILABLE == true ]]; then
        initial_mode=$(echo "$response" | jq -r '.mode')
        log "    Mode initial: $initial_mode"
    fi
    
    # Changement de mode
    log "  → Changement mode IA"
    response=$(curl -s -X POST "$BASE_URL/mode" \
        -H "Content-Type: application/json" \
        -d '{"state":"IA"}')
    
    if [[ $JQ_AVAILABLE == true ]]; then
        success_flag=$(echo "$response" | jq -r '.success')
        if [[ "$success_flag" == "true" ]]; then
            success "Mode IA activé"
        else
            error "Échec changement mode"
            return 1
        fi
    else
        if [[ "$response" == *"true"* ]]; then
            success "Mode IA activé"
        else
            error "Échec changement mode"
            return 1
        fi
    fi
    
    sleep 2
    
    # Vérification mode
    log "  → Vérification mode"
    response=$(curl -s "$BASE_URL/mode")
    if [[ $JQ_AVAILABLE == true ]]; then
        current_mode=$(echo "$response" | jq -r '.mode')
        if [[ "$current_mode" == "IA" ]]; then
            success "Mode correctement changé"
        else
            error "Mode incorrect: $current_mode"
            return 1
        fi
    fi
    
    # Retour mode initial
    if [[ -n "${initial_mode:-}" ]]; then
        log "  → Restauration mode initial"
        curl -s -X POST "$BASE_URL/mode" \
            -H "Content-Type: application/json" \
            -d "{\"state\":\"$initial_mode\"}" > /dev/null
    fi
}

# Test configuration
test_configuration() {
    log "Test configuration..."
    
    # Récupération config
    log "  → Récupération configuration"
    response=$(curl -s "$BASE_URL/config")
    if [[ $JQ_AVAILABLE == true ]]; then
        mqtt_broker=$(echo "$response" | jq -r '.mqtt.broker // "null"')
        if [[ "$mqtt_broker" != "null" ]]; then
            success "Configuration accessible"
            log "    MQTT Broker: $mqtt_broker"
        else
            error "Configuration invalide"
            return 1
        fi
    else
        if [[ "$response" == *"mqtt"* ]]; then
            success "Configuration accessible"
        else
            error "Configuration inaccessible"
            return 1
        fi
    fi
    
    # Section spécifique
    log "  → Section motion"
    response=$(curl -s "$BASE_URL/config/motion")
    if [[ $JQ_AVAILABLE == true ]] && echo "$response" | jq -e '.motion' &> /dev/null; then
        success "Section motion OK"
    elif [[ "$response" == *"motion"* ]]; then
        success "Section motion OK"
    else
        error "Section motion inaccessible"
        return 1
    fi
}

# Test contrôle servos
test_servo_control() {
    log "Test contrôle servos..."
    
    # Limites servo
    log "  → Limites servo pan"
    response=$(curl -s "$BASE_URL/servo/pan/limits")
    if [[ $JQ_AVAILABLE == true ]]; then
        min_pos=$(echo "$response" | jq -r '.min_position')
        max_pos=$(echo "$response" | jq -r '.max_position')
        log "    Limites pan: [$min_pos, $max_pos]"
        success "Limites servo OK"
    else
        if [[ "$response" == *"min_position"* ]]; then
            success "Limites servo OK"
        else
            error "Limites servo inaccessibles"
            return 1
        fi
    fi
    
    # Mouvement servo
    log "  → Mouvement servo pan"
    response=$(curl -s -X POST "$BASE_URL/servo/pan/move" \
        -H "Content-Type: application/json" \
        -d '{"position":0.0,"speed":50}')
    
    if [[ $JQ_AVAILABLE == true ]]; then
        success_flag=$(echo "$response" | jq -r '.success')
        if [[ "$success_flag" == "true" ]]; then
            success "Mouvement servo OK"
        else
            error "Échec mouvement servo"
            return 1
        fi
    else
        if [[ "$response" == *"true"* ]]; then
            success "Mouvement servo OK"
        else
            error "Échec mouvement servo"
            return 1
        fi
    fi
}

# Test services systemd
test_services() {
    log "Test services systemd..."
    
    # Status services
    log "  → Status services"
    response=$(curl -s "$BASE_URL/services")
    if [[ $JQ_AVAILABLE == true ]]; then
        services_count=$(echo "$response" | jq '. | keys | length')
        log "    Services gérés: $services_count"
        success "Services listés"
    else
        if [[ "$response" == *"skull-"* ]]; then
            success "Services listés"
        else
            error "Services non listés"
            return 1
        fi
    fi
    
    # Service spécifique
    log "  → Service skull-motion"
    response=$(curl -s "$BASE_URL/services/skull-motion")
    if [[ "$response" == *"skull-motion"* ]]; then
        success "Service motion accessible"
    else
        error "Service motion inaccessible"
        return 1
    fi
}

# Test MQTT (si disponible)
test_mqtt_integration() {
    if [[ $MQTT_AVAILABLE == false ]]; then
        warning "Tests MQTT ignorés (mosquitto_clients non disponible)"
        return 0
    fi
    
    log "Test intégration MQTT..."
    
    # Test publication
    log "  → Publication topic test"
    mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" \
        -t "test/orchestrator" -m "integration_test" -q 1
    
    success "Publication MQTT OK"
    
    # Test retained topics
    log "  → Vérification topics retained"
    timeout 5s mosquitto_sub -h "$MQTT_HOST" -p "$MQTT_PORT" \
        -t "skull/mode" -C 1 > /tmp/skull_mode.txt || true
    
    if [[ -s /tmp/skull_mode.txt ]]; then
        mode_value=$(cat /tmp/skull_mode.txt)
        log "    Mode actuel: $mode_value"
        success "Topics retained OK"
    else
        warning "Pas de topics retained détectés"
    fi
    
    rm -f /tmp/skull_mode.txt
}

# Test complet cycle IA
test_ia_cycle() {
    log "Test cycle IA complet..."
    
    # Passer en mode IA
    log "  → Mode IA"
    curl -s -X POST "$BASE_URL/mode" \
        -H "Content-Type: application/json" \
        -d '{"state":"IA"}' > /dev/null
    
    sleep 1
    
    # Simuler requête IA
    log "  → Requête IA"
    response=$(curl -s -X POST "$BASE_URL/ia/query" \
        -H "Content-Type: application/json" \
        -d '{"text":"Test intégration","context":"test"}')
    
    if [[ $JQ_AVAILABLE == true ]]; then
        success_flag=$(echo "$response" | jq -r '.success')
        if [[ "$success_flag" == "true" ]]; then
            success "Requête IA envoyée"
        else
            error "Échec requête IA"
            return 1
        fi
    else
        if [[ "$response" == *"true"* ]]; then
            success "Requête IA envoyée"
        else
            error "Échec requête IA"
            return 1
        fi
    fi
}

# Test Full Auto
test_full_auto() {
    log "Test Full Auto..."
    
    # Configuration Full Auto
    log "  → Configuration Full Auto (test)"
    response=$(curl -s -X POST "$BASE_URL/fullauto/config" \
        -H "Content-Type: application/json" \
        -d '{"enabled":true,"interval_song_ms":10000,"accueil_after_song":false,"ia_after_accueil":false}')
    
    if [[ "$response" == *"true"* ]]; then
        success "Configuration Full Auto OK"
    else
        error "Échec configuration Full Auto"
        return 1
    fi
    
    # Test cycle unique
    log "  → Test cycle unique"
    response=$(curl -s -X POST "$BASE_URL/fullauto/test-once")
    
    if [[ "$response" == *"true"* ]]; then
        success "Cycle test lancé"
    else
        error "Échec test cycle"
        return 1
    fi
    
    # Restaurer config par défaut
    curl -s -X POST "$BASE_URL/fullauto/config" \
        -H "Content-Type: application/json" \
        -d '{"enabled":false,"interval_song_ms":300000,"accueil_after_song":true,"ia_after_accueil":true}' > /dev/null
}

# Test arrêt d'urgence
test_emergency_stop() {
    log "Test arrêt d'urgence..."
    
    response=$(curl -s -X POST "$BASE_URL/estop")
    
    if [[ "$response" == *"E-STOP"* ]]; then
        success "E-STOP OK"
    else
        error "Échec E-STOP"
        return 1
    fi
    
    sleep 1
    
    # Vérifier retour à Idle
    response=$(curl -s "$BASE_URL/status")
    if [[ $JQ_AVAILABLE == true ]]; then
        state=$(echo "$response" | jq -r '.orchestrator.state')
        if [[ "$state" == "Idle" ]]; then
            success "État Idle après E-STOP"
        else
            warning "État après E-STOP: $state"
        fi
    fi
}

# Résumé des tests
print_summary() {
    log "Résumé des tests d'intégration:"
    echo
    
    if [[ ${FAILED_TESTS:-0} -eq 0 ]]; then
        success "Tous les tests ont réussi ! 🎉"
        echo
        log "L'orchestrateur fonctionne correctement."
    else
        error "$FAILED_TESTS test(s) ont échoué"
        echo
        log "Vérifiez les logs pour plus de détails:"
        log "  sudo journalctl -u skull-orchestrator -f"
        log "  tail -f /opt/Skull/logs/orchestrator.log"
    fi
}

# Fonction pour exécuter un test avec gestion d'erreurs
run_test() {
    local test_name=$1
    local test_function=$2
    
    log "=== $test_name ==="
    
    if $test_function; then
        success "$test_name réussi"
    else
        error "$test_name échoué"
        FAILED_TESTS=$((${FAILED_TESTS:-0} + 1))
    fi
    
    echo
}

# Point d'entrée principal
main() {
    log "🚀 Démarrage tests d'intégration Orchestrateur Skull Pi"
    echo
    
    FAILED_TESTS=0
    
    check_prerequisites
    wait_for_orchestrator
    
    echo
    log "Exécution des tests..."
    echo
    
    # Tests principaux
    run_test "API de base" test_basic_api
    run_test "Gestion des modes" test_mode_management  
    run_test "Configuration" test_configuration
    run_test "Contrôle servos" test_servo_control
    run_test "Services systemd" test_services
    run_test "Intégration MQTT" test_mqtt_integration
    run_test "Cycle IA" test_ia_cycle
    run_test "Full Auto" test_full_auto
    run_test "Arrêt d'urgence" test_emergency_stop
    
    print_summary
    
    # Code de sortie
    if [[ $FAILED_TESTS -eq 0 ]]; then
        exit 0
    else
        exit 1
    fi
}

# Exécution si script lancé directement
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi