//! Integration tests for session/list RPC method

use dirigent_acp_api::{
    NoOpConnectorOperations, RpcHandler, SessionManager,
};
use dirigent_acp_api::agent_requests::AgentRequestTracker;
use dirigent_acp_api::sse::SseNotifier;
use serde_json::json;
use std::sync::Arc;

fn create_test_handler() -> RpcHandler<NoOpConnectorOperations> {
    RpcHandler::new(
        SessionManager::new(),
        NoOpConnectorOperations,
        SseNotifier::new(),
        Arc::new(AgentRequestTracker::new()),
    )
}

#[tokio::test]
async fn test_session_list_returns_sessions() {
    let handler = create_test_handler();

    let request_body = json!({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "session/list",
        "params": {
            "connectorId": "stub-connector"
        }
    });

    let response = handler.handle_request(&request_body.to_string(), None).await;
    let response_json = serde_json::to_value(&response).unwrap();

    // NoOp returns one stub session
    let result = &response_json["result"];
    assert!(result["sessions"].is_array());
    let sessions = result["sessions"].as_array().unwrap();
    assert!(!sessions.is_empty());
    assert!(sessions[0]["sessionId"].is_string());
}

#[tokio::test]
async fn test_session_list_no_params() {
    let handler = create_test_handler();

    // session/list with no params should use default connector
    let request_body = json!({
        "jsonrpc": "2.0",
        "id": 2,
        "method": "session/list"
    });

    let response = handler.handle_request(&request_body.to_string(), None).await;
    let response_json = serde_json::to_value(&response).unwrap();

    // Should succeed using default connector from NoOp
    let result = &response_json["result"];
    assert!(result["sessions"].is_array());
}

#[tokio::test]
async fn test_session_list_creates_mappings() {
    let session_manager = SessionManager::new();
    let handler = RpcHandler::new(
        session_manager.clone(),
        NoOpConnectorOperations,
        SseNotifier::new(),
        Arc::new(AgentRequestTracker::new()),
    );

    // First, initialize to register a client
    let init_body = json!({
        "jsonrpc": "2.0",
        "id": 0,
        "method": "initialize",
        "params": {}
    });
    let init_response = handler.handle_request(&init_body.to_string(), Some("test-client")).await;
    let init_json = serde_json::to_value(&init_response).unwrap();
    let client_id = init_json["result"]["clientId"].as_str().unwrap();

    // Now list sessions
    let request_body = json!({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "session/list",
        "params": {
            "connectorId": "stub-connector"
        }
    });

    let response = handler.handle_request(&request_body.to_string(), Some(client_id)).await;
    let response_json = serde_json::to_value(&response).unwrap();

    let sessions = response_json["result"]["sessions"].as_array().unwrap();
    assert!(!sessions.is_empty());

    // Session mapping should exist for the returned session
    let session_id = sessions[0]["sessionId"].as_str().unwrap();
    let mapping = session_manager.get_mapping(session_id);
    assert!(mapping.is_some(), "Session mapping should be created for listed sessions");
}

#[tokio::test]
async fn test_session_load_without_connector_id() {
    let handler = create_test_handler();

    // Standard ACP: only sessionId + cwd + mcpServers, no connectorId
    let request_body = json!({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "session/load",
        "params": {
            "sessionId": "sess-abc",
            "cwd": "G:\\dev\\projects\\test",
            "mcpServers": []
        }
    });

    let response = handler.handle_request(&request_body.to_string(), None).await;
    let response_json = serde_json::to_value(&response).unwrap();

    let result = &response_json["result"];
    assert!(result["sessionId"].is_string(), "session/load should succeed without connectorId");
    assert!(result["createdAt"].is_string());
}

#[tokio::test]
async fn test_initialize_advertises_list_sessions() {
    let handler = create_test_handler();

    let request_body = json!({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "initialize",
        "params": {}
    });

    let response = handler.handle_request(&request_body.to_string(), None).await;
    let response_json = serde_json::to_value(&response).unwrap();

    let caps = &response_json["result"]["agentCapabilities"];
    assert_eq!(caps["listSessions"], true, "listSessions capability should be advertised");
    assert_eq!(caps["loadSession"], true, "loadSession capability should still be advertised");

    // Verify nested sessionCapabilities.list is advertised (required by Zed v0.9.4+)
    assert!(
        caps["sessionCapabilities"]["list"].is_object(),
        "sessionCapabilities.list should be advertised as an empty object"
    );
}
