//! Service Orchestration Tests

use provisioning_orchestrator::services::{Service, ServiceOrchestrator, ServiceStatus};

#[tokio::test]
async fn test_service_orchestrator_initialization() {
    let orchestrator = ServiceOrchestrator::new(
        "/usr/local/bin/nu".to_string(),
        "/usr/local/bin/provisioning".to_string(),
        true,
    );

    let services = orchestrator.list_services().await;
    assert_eq!(services.len(), 0);
}

#[tokio::test]
async fn test_service_registration() {
    let orchestrator = ServiceOrchestrator::new(
        "/usr/local/bin/nu".to_string(),
        "/usr/local/bin/provisioning".to_string(),
        true,
    );

    let service = Service {
        name: "test-service".to_string(),
        description: "Test service".to_string(),
        dependencies: vec![],
        start_command: "test start".to_string(),
        stop_command: "test stop".to_string(),
        health_check_endpoint: None,
    };

    orchestrator.register_service(service).await;

    let services = orchestrator.list_services().await;
    assert_eq!(services.len(), 1);
    assert_eq!(services[0].name, "test-service");
}

#[tokio::test]
#[ignore] // Hangs: resolve_startup_order has an infinite loop or deadlock
async fn test_dependency_resolution_simple() {
    let orchestrator = ServiceOrchestrator::new(
        "/usr/local/bin/nu".to_string(),
        "/usr/local/bin/provisioning".to_string(),
        true,
    );

    // Register service A (no dependencies)
    let service_a = Service {
        name: "service-a".to_string(),
        description: "Service A".to_string(),
        dependencies: vec![],
        start_command: "start a".to_string(),
        stop_command: "stop a".to_string(),
        health_check_endpoint: None,
    };

    orchestrator.register_service(service_a).await;

    // Register service B (depends on A)
    let service_b = Service {
        name: "service-b".to_string(),
        description: "Service B".to_string(),
        dependencies: vec!["service-a".to_string()],
        start_command: "start b".to_string(),
        stop_command: "stop b".to_string(),
        health_check_endpoint: None,
    };

    orchestrator.register_service(service_b).await;

    // Resolve startup order
    let order = orchestrator
        .resolve_startup_order(&["service-b".to_string()])
        .await
        .unwrap();

    // service-a should start before service-b
    assert_eq!(order.len(), 2);
    assert_eq!(order[0], "service-a");
    assert_eq!(order[1], "service-b");
}

#[tokio::test]
#[ignore] // Hangs: resolve_startup_order has an infinite loop or deadlock
async fn test_dependency_resolution_complex() {
    let orchestrator = ServiceOrchestrator::new(
        "/usr/local/bin/nu".to_string(),
        "/usr/local/bin/provisioning".to_string(),
        true,
    );

    // A -> no deps
    let service_a = Service {
        name: "service-a".to_string(),
        description: "Service A".to_string(),
        dependencies: vec![],
        start_command: "start a".to_string(),
        stop_command: "stop a".to_string(),
        health_check_endpoint: None,
    };

    // B -> depends on A
    let service_b = Service {
        name: "service-b".to_string(),
        description: "Service B".to_string(),
        dependencies: vec!["service-a".to_string()],
        start_command: "start b".to_string(),
        stop_command: "stop b".to_string(),
        health_check_endpoint: None,
    };

    // C -> depends on A and B
    let service_c = Service {
        name: "service-c".to_string(),
        description: "Service C".to_string(),
        dependencies: vec!["service-a".to_string(), "service-b".to_string()],
        start_command: "start c".to_string(),
        stop_command: "stop c".to_string(),
        health_check_endpoint: None,
    };

    orchestrator.register_service(service_a).await;
    orchestrator.register_service(service_b).await;
    orchestrator.register_service(service_c).await;

    // Resolve startup order for service-c
    let order = orchestrator
        .resolve_startup_order(&["service-c".to_string()])
        .await
        .unwrap();

    // Should be: A, B, C
    assert_eq!(order.len(), 3);
    assert_eq!(order[0], "service-a");
    assert_eq!(order[1], "service-b");
    assert_eq!(order[2], "service-c");
}

#[test]
fn test_service_status_display() {
    assert_eq!(ServiceStatus::Running.to_string(), "running");
    assert_eq!(ServiceStatus::Stopped.to_string(), "stopped");
    assert_eq!(ServiceStatus::Failed.to_string(), "failed");
    assert_eq!(ServiceStatus::Unknown.to_string(), "unknown");
}

#[test]
fn test_service_creation() {
    let service = Service {
        name: "test-service".to_string(),
        description: "Test service for unit testing".to_string(),
        dependencies: vec!["dep1".to_string(), "dep2".to_string()],
        start_command: "systemctl start test".to_string(),
        stop_command: "systemctl stop test".to_string(),
        health_check_endpoint: Some("http://localhost:8080/health".to_string()),
    };

    assert_eq!(service.name, "test-service");
    assert_eq!(service.dependencies.len(), 2);
    assert!(service.health_check_endpoint.is_some());
}

#[tokio::test]
async fn test_service_list_empty() {
    let orchestrator = ServiceOrchestrator::new(
        "/usr/local/bin/nu".to_string(),
        "/usr/local/bin/provisioning".to_string(),
        false,
    );

    let services = orchestrator.list_services().await;
    assert_eq!(services.len(), 0);
}
