//! Tests for Event Adapter Integration
//!
//! T071: Event Adapter Integration
//! - SSE events translated correctly by OpenCodeAdapter
//! - Events forwarded to broadcast channel

#![cfg(feature = "server")]
use dirigent_protocol::adapters::OpenCodeAdapter;
use dirigent_protocol::Event;
use std::time::Duration;
use tokio::time::timeout;

// ============================================================================
// T071: Event Adapter Integration
// ============================================================================

#[test]
fn test_t071_adapter_can_be_created() {
    let _adapter = OpenCodeAdapter::new();
    // If this compiles and runs, the adapter can be instantiated
}

#[test]
fn test_t071_adapter_translates_session_created() {
    use opencode_client::types as oc;

    let adapter = OpenCodeAdapter::new();

    let oc_session = oc::Session {
        id: "session-123".to_string(),
        project_id: "project-1".to_string(),
        directory: "/test".to_string(),
        parent_id: None,
        summary: None,
        share: None,
        title: "Test Session".to_string(),
        version: "1.0".to_string(),
        time: oc::SessionTime {
            created: 1234567890,
            updated: 1234567890,
            compacting: None,
        },
        revert: None,
    };

    let oc_event = oc::Event::SessionCreated {
        properties: oc::SessionEventInfo {
            info: oc_session.clone(),
        },
    };

    let result = adapter.translate_event(oc_event);
    assert!(result.is_ok(), "Translation should succeed");

    if let Ok(Event::SessionCreated { session, .. }) = result {
        assert_eq!(session.id, "session-123");
        assert_eq!(session.title, "Test Session");
    } else {
        panic!("Expected SessionCreated event, got {:?}", result);
    }
}

#[test]
fn test_t071_adapter_translates_message_updated() {
    use opencode_client::types as oc;

    let adapter = OpenCodeAdapter::new();

    let oc_message = oc::Message::Assistant(oc::AssistantMessage {
        id: "msg-123".to_string(),
        session_id: "session-456".to_string(),
        time: oc::AssistantMessageTime {
            created: 1234567890,
            completed: None,
        },
        error: None,
        system: vec![],
        parent_id: None,
        model_id: None,
        provider_id: None,
        mode: None,
        path: None,
        summary: None,
        cost: 0.0,
        tokens: oc::TokenUsage::default(),
    });

    let oc_event = oc::Event::MessageUpdated {
        properties: oc::MessageEventInfo {
            info: oc_message.clone(),
        },
    };

    let result = adapter.translate_event(oc_event);
    assert!(result.is_ok(), "Translation should succeed");

    // The adapter might return MessageStarted or MessageCompleted depending on status
    match result {
        Ok(Event::MessageStarted { message, .. }) => {
            assert_eq!(message.id, "msg-123");
            assert_eq!(message.session_id, "session-456");
        }
        Ok(Event::MessageCompleted { message, .. }) => {
            assert_eq!(message.id, "msg-123");
            assert_eq!(message.session_id, "session-456");
        }
        other => {
            panic!(
                "Expected MessageStarted or MessageCompleted, got {:?}",
                other
            );
        }
    }
}

#[test]
fn test_t071_adapter_handles_duplicate_events() {
    use opencode_client::types as oc;

    let adapter = OpenCodeAdapter::new();

    let oc_message = oc::Message::Assistant(oc::AssistantMessage {
        id: "msg-same".to_string(),
        session_id: "session-1".to_string(),
        time: oc::AssistantMessageTime {
            created: 1234567890,
            completed: None,
        },
        error: None,
        system: vec![],
        parent_id: None,
        model_id: None,
        provider_id: None,
        mode: None,
        path: None,
        summary: None,
        cost: 0.0,
        tokens: oc::TokenUsage::default(),
    });

    let oc_event = oc::Event::MessageUpdated {
        properties: oc::MessageEventInfo {
            info: oc_message.clone(),
        },
    };

    // First translation should succeed
    let result1 = adapter.translate_event(oc_event.clone());
    assert!(result1.is_ok(), "First translation should succeed");

    // Second translation of the same event should return Duplicate error
    let result2 = adapter.translate_event(oc_event);
    assert!(
        result2.is_err(),
        "Second translation should detect duplicate"
    );

    if let Err(dirigent_protocol::adapters::opencode::TranslationError::Duplicate) = result2 {
        // Expected
    } else {
        panic!("Expected Duplicate error, got {:?}", result2);
    }
}

#[tokio::test]
async fn test_t071_events_forwarded_to_broadcast_channel() {
    // Test that the broadcast channel mechanism works
    // We create our own channels to test the pattern used by connectors
    let (events_tx, mut events_rx) = tokio::sync::broadcast::channel(1000);

    // Send a test event
    events_tx.send(dirigent_protocol::Event::Connected).ok();

    // Verify we can receive it
    let event_received = timeout(Duration::from_millis(100), events_rx.recv()).await;

    assert!(
        event_received.is_ok(),
        "Should receive events via broadcast channel"
    );
    assert!(matches!(
        event_received.unwrap().unwrap(),
        dirigent_protocol::Event::Connected
    ));
}

#[tokio::test]
async fn test_t071_multiple_subscribers_receive_same_events() {
    // Test that multiple subscribers all receive broadcast events
    let (events_tx, _) = tokio::sync::broadcast::channel(1000);

    // Create multiple subscriptions
    let mut events1 = events_tx.subscribe();
    let mut events2 = events_tx.subscribe();
    let mut events3 = events_tx.subscribe();

    // Send an event
    events_tx.send(dirigent_protocol::Event::Connected).ok();

    // All subscribers should receive events
    let timeout_duration = Duration::from_millis(100);

    let result1 = timeout(timeout_duration, events1.recv()).await;
    let result2 = timeout(timeout_duration, events2.recv()).await;
    let result3 = timeout(timeout_duration, events3.recv()).await;

    // All three should receive events
    assert!(result1.is_ok(), "Subscriber 1 should receive events");
    assert!(result2.is_ok(), "Subscriber 2 should receive events");
    assert!(result3.is_ok(), "Subscriber 3 should receive events");
}

#[tokio::test]
async fn test_t071_events_contain_correct_data() {
    // Test that events can be sent and received with correct data
    let (events_tx, mut events_rx) = tokio::sync::broadcast::channel(1000);

    // Send various event types
    events_tx.send(Event::Connected).ok();
    events_tx.send(Event::Disconnected).ok();
    events_tx
        .send(Event::Error {
            message: "Test error".to_string(),
        })
        .ok();

    // Collect events
    let mut received_events = Vec::new();
    while let Ok(result) = timeout(Duration::from_millis(10), events_rx.recv()).await {
        if let Ok(event) = result {
            received_events.push(event);
        }
        if received_events.len() >= 3 {
            break;
        }
    }

    // We should have received all events
    assert_eq!(received_events.len(), 3, "Should receive all events");

    // Check that events are valid Event enum variants
    for event in &received_events {
        match event {
            Event::Connected => {}
            Event::Disconnected => {}
            Event::Error { message } => {
                assert!(!message.is_empty(), "Error messages should not be empty");
            }
            _ => {}
        }
    }
}

#[test]
fn test_t071_adapter_translates_message_part() {
    use opencode_client::types as oc;

    let adapter = OpenCodeAdapter::new();

    // First, create a message so the part can be associated
    let oc_message = oc::Message::Assistant(oc::AssistantMessage {
        id: "msg-123".to_string(),
        session_id: "session-456".to_string(),
        time: oc::AssistantMessageTime {
            created: 1234567890,
            completed: None,
        },
        error: None,
        system: vec![],
        parent_id: None,
        model_id: None,
        provider_id: None,
        mode: None,
        path: None,
        summary: None,
        cost: 0.0,
        tokens: oc::TokenUsage::default(),
    });

    let msg_event = oc::Event::MessageUpdated {
        properties: oc::MessageEventInfo {
            info: oc_message.clone(),
        },
    };

    adapter
        .translate_event(msg_event)
        .expect("Message should translate");

    // Now translate a message part
    let oc_part = oc::Part::Text(oc::TextPart {
        id: "part-123".to_string(),
        session_id: "session-456".to_string(),
        message_id: "msg-123".to_string(),
        text: "Hello, world!".to_string(),
        synthetic: None,
        time: Some(oc::PartTime {
            start: 1234567890,
            end: Some(1234567900),
        }),
    });

    let part_event = oc::Event::MessagePartUpdated {
        properties: oc::MessagePartEventInfo {
            part: oc_part.clone(),
            delta: Some("Hello, world!".to_string()),
        },
    };

    let result = adapter.translate_event(part_event);
    assert!(result.is_ok(), "Part translation should succeed");

    if let Ok(Event::SessionUpdate { connector_id: _, session_id, update }) = result {
        assert_eq!(session_id, "ses-456");
        match update {
            dirigent_protocol::SessionUpdate::AgentMessageChunk {
                message_id,
                content,
                ..
            } => {
                assert_eq!(message_id, "msg-123");
                match content {
                    dirigent_protocol::ContentBlock::Text { text } => {
                        assert_eq!(text, "Hello, world!");
                    }
                    _ => panic!("Expected Text content block"),
                }
            }
            _ => panic!("Expected AgentMessageChunk"),
        }
    } else {
        panic!("Expected SessionUpdate event, got {:?}", result);
    }
}

#[tokio::test]
async fn test_t071_broadcast_channel_capacity() {
    // Test that the broadcast channel has sufficient capacity
    let (events_tx, mut events_rx) = tokio::sync::broadcast::channel(1000);

    // Send many events
    for i in 0..100 {
        events_tx
            .send(Event::Error {
                message: format!("Event {}", i),
            })
            .ok();
    }

    // Receive them all
    let mut count = 0;
    while let Ok(result) = timeout(Duration::from_millis(10), events_rx.recv()).await {
        if result.is_ok() {
            count += 1;
        } else {
            break;
        }
        if count >= 100 {
            break;
        }
    }

    // We should have received all events without lagging
    assert_eq!(count, 100, "Should receive all events without lag");
}
