// Integration tests for Phase 3: Workflow orchestration
// Tests the complete workflow system end-to-end

use std::sync::Arc;

use vapora_agents::{
    config::{AgentConfig, RegistryConfig},
    coordinator::AgentCoordinator,
    registry::AgentRegistry,
};
use vapora_backend::{
    api::websocket::WorkflowBroadcaster,
    audit::AuditTrail,
    services::{WorkflowService, WorkflowServiceError},
    workflow::{
        engine::WorkflowEngine,
        executor::StepExecutor,
        parser::WorkflowParser,
        scheduler::Scheduler,
        state::{Phase, StepStatus, Workflow, WorkflowStatus, WorkflowStep},
    },
};

#[tokio::test]
async fn test_workflow_state_transitions() {
    let mut workflow = Workflow::new("wf-1".to_string(), "Test Workflow".to_string(), vec![]);

    // Test valid transitions
    assert!(workflow.transition(WorkflowStatus::Planning).is_ok());
    assert_eq!(workflow.status, WorkflowStatus::Planning);

    assert!(workflow.transition(WorkflowStatus::InProgress).is_ok());
    assert_eq!(workflow.status, WorkflowStatus::InProgress);
    assert!(workflow.started_at.is_some());

    assert!(workflow.transition(WorkflowStatus::Completed).is_ok());
    assert_eq!(workflow.status, WorkflowStatus::Completed);
    assert!(workflow.completed_at.is_some());
}

#[tokio::test]
async fn test_workflow_parser() {
    let yaml = r#"
workflow:
  id: test-workflow
  title: Test Workflow
  phases:
    - id: phase1
      name: Design Phase
      parallel: false
      estimated_hours: 2.0
      steps:
        - id: step1
          name: Create design
          agent: architect
          depends_on: []
          parallelizable: false
    - id: phase2
      name: Implementation
      parallel: true
      estimated_hours: 8.0
      steps:
        - id: step2
          name: Implement backend
          agent: developer
          depends_on: []
          parallelizable: true
        - id: step3
          name: Implement frontend
          agent: developer
          depends_on: []
          parallelizable: true
"#;

    let result = WorkflowParser::parse_string(yaml);
    assert!(result.is_ok());

    let workflow = result.unwrap();
    assert_eq!(workflow.id, "test-workflow");
    assert_eq!(workflow.phases.len(), 2);
    assert!(workflow.phases[1].parallel);
    assert_eq!(workflow.phases[1].steps.len(), 2);
}

#[tokio::test]
async fn test_dependency_resolution() {
    let steps = vec![
        WorkflowStep {
            id: "a".to_string(),
            name: "Step A".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec![],
            can_parallelize: true,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
        WorkflowStep {
            id: "b".to_string(),
            name: "Step B".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec!["a".to_string()],
            can_parallelize: true,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
        WorkflowStep {
            id: "c".to_string(),
            name: "Step C".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec!["a".to_string()],
            can_parallelize: true,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
    ];

    let result = Scheduler::resolve_dependencies(&steps);
    assert!(result.is_ok());

    let levels = result.unwrap();
    assert_eq!(levels.len(), 2);
    assert_eq!(levels[0], vec!["a"]);
    assert_eq!(levels[1].len(), 2); // b and c can execute in parallel
}

#[tokio::test]
async fn test_workflow_engine() {
    let registry = Arc::new(AgentRegistry::new(5));
    let config = AgentConfig {
        registry: RegistryConfig {
            max_agents_per_role: 5,
            health_check_interval: 30,
            agent_timeout: 300,
        },
        agents: vec![],
    };
    let coordinator = Arc::new(
        AgentCoordinator::new(config, registry)
            .await
            .expect("coordinator creation failed"),
    );
    let executor = StepExecutor::new(coordinator);
    let engine = WorkflowEngine::new(executor);

    let workflow = Workflow::new(
        "engine-test".to_string(),
        "Engine Test".to_string(),
        vec![Phase {
            id: "p1".to_string(),
            name: "Phase 1".to_string(),
            status: StepStatus::Pending,
            parallel: false,
            estimated_hours: 1.0,
            steps: vec![WorkflowStep {
                id: "s1".to_string(),
                name: "Step 1".to_string(),
                agent_role: "developer".to_string(),
                status: StepStatus::Pending,
                depends_on: vec![],
                can_parallelize: true,
                started_at: None,
                completed_at: None,
                result: None,
                error: None,
            }],
        }],
    );

    let id = workflow.id.clone();
    let result = engine.register_workflow(workflow).await;
    assert!(result.is_ok());

    let retrieved = engine.get_workflow(&id).await;
    assert!(retrieved.is_some());
    assert_eq!(retrieved.unwrap().id, id);
}

#[tokio::test]
#[ignore = "requires SurrealDB at ws://localhost:8000"]
async fn test_workflow_service_integration() {
    let db = surrealdb::Surreal::new::<surrealdb::engine::remote::ws::Ws>("ws://localhost:8000")
        .await
        .expect("connect to SurrealDB");
    db.signin(surrealdb::opt::auth::Root {
        username: "root".to_string(),
        password: "root".to_string(),
    })
    .await
    .expect("signin");
    db.use_ns("vapora_test")
        .use_db("wf_integration")
        .await
        .expect("use ns/db");

    let registry = Arc::new(AgentRegistry::new(5));
    let config = AgentConfig {
        registry: RegistryConfig {
            max_agents_per_role: 5,
            health_check_interval: 30,
            agent_timeout: 300,
        },
        agents: vec![],
    };
    let coordinator = Arc::new(
        AgentCoordinator::new(config, registry)
            .await
            .expect("coordinator creation failed"),
    );
    let executor = StepExecutor::new(coordinator);
    let engine = Arc::new(WorkflowEngine::new(executor));
    let broadcaster = Arc::new(WorkflowBroadcaster::new());
    let audit = Arc::new(AuditTrail::new(db));

    let service = WorkflowService::new(engine, broadcaster, audit);

    let workflow = Workflow::new(
        "service-test".to_string(),
        "Service Test".to_string(),
        vec![Phase {
            id: "p1".to_string(),
            name: "Test Phase".to_string(),
            status: StepStatus::Pending,
            parallel: false,
            estimated_hours: 1.0,
            steps: vec![WorkflowStep {
                id: "s1".to_string(),
                name: "Test Step".to_string(),
                agent_role: "developer".to_string(),
                status: StepStatus::Pending,
                depends_on: vec![],
                can_parallelize: false,
                started_at: None,
                completed_at: None,
                result: None,
                error: None,
            }],
        }],
    );

    let id = workflow.id.clone();
    let result: Result<Workflow, WorkflowServiceError> = service.create_workflow(workflow).await;
    assert!(result.is_ok());

    let audit_entries = service.get_audit_trail(&id).await.expect("get_audit_trail");
    assert!(!audit_entries.is_empty());
}

#[tokio::test]
async fn test_websocket_broadcaster() {
    let broadcaster = WorkflowBroadcaster::new();
    let mut rx = broadcaster.subscribe();

    let update = vapora_backend::api::websocket::WorkflowUpdate::new(
        "wf-1".to_string(),
        "in_progress".to_string(),
        50,
        "Test update".to_string(),
    );

    broadcaster.send_update(update.clone());

    let received = rx.recv().await.unwrap();
    assert_eq!(received.workflow_id, "wf-1");
    assert_eq!(received.progress, 50);
}

#[tokio::test]
#[ignore = "requires SurrealDB at ws://localhost:8000"]
async fn test_audit_trail() {
    let db = surrealdb::Surreal::new::<surrealdb::engine::remote::ws::Ws>("ws://localhost:8000")
        .await
        .expect("connect to SurrealDB");
    db.signin(surrealdb::opt::auth::Root {
        username: "root".to_string(),
        password: "root".to_string(),
    })
    .await
    .expect("signin");
    db.use_ns("vapora_test")
        .use_db("wf_audit_trail")
        .await
        .expect("use ns/db");

    let audit = AuditTrail::new(db);

    audit
        .log_event(
            "wf-1".to_string(),
            "workflow_started".to_string(),
            "system".to_string(),
            serde_json::json!({"test": "data"}),
        )
        .await
        .expect("log_event");

    let entries = audit
        .get_workflow_audit("wf-1")
        .await
        .expect("get_workflow_audit");
    assert_eq!(entries.len(), 1);
    assert_eq!(entries[0].event_type, "workflow_started");
}

#[tokio::test]
async fn test_circular_dependency_detection() {
    let steps = vec![
        WorkflowStep {
            id: "a".to_string(),
            name: "A".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec!["c".to_string()],
            can_parallelize: false,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
        WorkflowStep {
            id: "b".to_string(),
            name: "B".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec!["a".to_string()],
            can_parallelize: false,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
        WorkflowStep {
            id: "c".to_string(),
            name: "C".to_string(),
            agent_role: "dev".to_string(),
            status: StepStatus::Pending,
            depends_on: vec!["b".to_string()],
            can_parallelize: false,
            started_at: None,
            completed_at: None,
            result: None,
            error: None,
        },
    ];

    let result = Scheduler::resolve_dependencies(&steps);
    assert!(result.is_err());
}

#[tokio::test]
async fn test_workflow_progress_calculation() {
    let workflow = Workflow::new(
        "progress-test".to_string(),
        "Progress Test".to_string(),
        vec![Phase {
            id: "p1".to_string(),
            name: "Phase 1".to_string(),
            status: StepStatus::Running,
            parallel: false,
            estimated_hours: 1.0,
            steps: vec![
                WorkflowStep {
                    id: "s1".to_string(),
                    name: "Step 1".to_string(),
                    agent_role: "dev".to_string(),
                    status: StepStatus::Completed,
                    depends_on: vec![],
                    can_parallelize: false,
                    started_at: None,
                    completed_at: None,
                    result: None,
                    error: None,
                },
                WorkflowStep {
                    id: "s2".to_string(),
                    name: "Step 2".to_string(),
                    agent_role: "dev".to_string(),
                    status: StepStatus::Running,
                    depends_on: vec![],
                    can_parallelize: false,
                    started_at: None,
                    completed_at: None,
                    result: None,
                    error: None,
                },
                WorkflowStep {
                    id: "s3".to_string(),
                    name: "Step 3".to_string(),
                    agent_role: "dev".to_string(),
                    status: StepStatus::Pending,
                    depends_on: vec![],
                    can_parallelize: false,
                    started_at: None,
                    completed_at: None,
                    result: None,
                    error: None,
                },
            ],
        }],
    );

    assert_eq!(workflow.progress_percent(), 33); // 1 of 3 completed
}
