//! Pagination tests for dirigent_archivist
//!
//! These tests verify the count_messages and get_messages_range functionality.

#[cfg(test)]
mod pagination_tests {
    use chrono::Utc;
    use dirigent_archivist::{
        backends::JsonlBackend, Archivist, MessageRecord, RegisterConnectorRequest,
        RegisterSessionRequest, Result,
    };
    use std::sync::Arc;
    use uuid::Uuid;

    /// Build a self-contained coordinator rooted at `archive_root`, backed by
    /// a single `JsonlBackend`. Avoids the shared `.archives.json` race that
    /// `new_with_single_archive` creates in the tempdir's parent.
    async fn mk_archivist(archive_root: std::path::PathBuf) -> Result<Archivist> {
        let backend = Arc::new(JsonlBackend::new(archive_root).await?);
        Archivist::from_single_backend("main".into(), backend).await
    }

    #[tokio::test]
    async fn test_pagination_count_and_range() -> Result<()> {
        let temp_dir = std::env::temp_dir().join(format!("archivist_test_{}", Uuid::now_v7()));
        let archivist = mk_archivist(temp_dir.clone()).await?;

        // Register connector
        let connector_req = RegisterConnectorRequest {
            r#type: "OpenCode".to_string(),
            title: "Test Connector".to_string(),
            client_native_id: "opencode@localhost:12225".to_string(),
            custom_uid: None,
            metadata: serde_json::json!({}),
            fingerprint: None,
        };
        let connector_response = archivist.register_connector(connector_req, None).await?;

        // Register session
        let session_req = RegisterSessionRequest {
            connector_uid: connector_response.connector_uid,
            native_session_id: "native-123".to_string(),
            title: Some("Pagination Test".to_string()),
            custom_scroll_id: None,
            metadata: serde_json::json!({}),
            completeness: Default::default(),
            parent_scroll_id: None,
            is_subagent: false,
            continuation: None,
            agent_id: None,
            subagent_type: None,
            spawning_tool_use_id: None,
        };
        let session_response = archivist.register_session(session_req, None).await?;
        let scroll_id = session_response.scroll_id;

        // Test empty session
        let count = archivist.count_messages(scroll_id, None).await?;
        assert_eq!(count, 0, "Empty session should have 0 messages");

        let range = archivist.get_messages_range(scroll_id, 0, 10, None).await?;
        assert_eq!(range.len(), 0, "Empty session should return empty range");

        // Add 25 messages with varying timestamps
        let mut messages = Vec::new();
        let base_time = Utc::now();
        for i in 0..25 {
            messages.push(MessageRecord {
                version: 1,
                message_id: Uuid::now_v7(),
                session: scroll_id,
                parent_id: None,
                ts: base_time + chrono::Duration::seconds(i),
                role: if i % 2 == 0 { "user" } else { "assistant" }.to_string(),
                author: Some("test".to_string()),
                content_md: format!("Message {}", i),
                content_parts: None,
                attachments: Vec::new(),
                metadata: serde_json::json!({}),
            });
        }
        archivist.append_messages(scroll_id, messages, None).await?;

        // Test count_messages
        let count = archivist.count_messages(scroll_id, None).await?;
        assert_eq!(count, 25, "Should count 25 messages");

        // Test get_messages_range - first page
        let page1 = archivist.get_messages_range(scroll_id, 0, 10, None).await?;
        assert_eq!(page1.len(), 10, "First page should have 10 messages");
        assert_eq!(page1[0].content_md, "Message 0", "First message should be Message 0");
        assert_eq!(page1[9].content_md, "Message 9", "10th message should be Message 9");

        // Test get_messages_range - second page
        let page2 = archivist.get_messages_range(scroll_id, 10, 10, None).await?;
        assert_eq!(page2.len(), 10, "Second page should have 10 messages");
        assert_eq!(page2[0].content_md, "Message 10", "11th message should be Message 10");
        assert_eq!(page2[9].content_md, "Message 19", "20th message should be Message 19");

        // Test get_messages_range - partial last page
        let page3 = archivist.get_messages_range(scroll_id, 20, 10, None).await?;
        assert_eq!(page3.len(), 5, "Last page should have 5 messages");
        assert_eq!(page3[0].content_md, "Message 20", "21st message should be Message 20");
        assert_eq!(page3[4].content_md, "Message 24", "25th message should be Message 24");

        // Test get_messages_range - offset beyond messages
        let page4 = archivist.get_messages_range(scroll_id, 30, 10, None).await?;
        assert_eq!(page4.len(), 0, "Offset beyond messages should return empty");

        // Verify chronological ordering is maintained in pagination
        let all_messages = archivist.get_messages(scroll_id, None).await?;
        let first_10_from_all = &all_messages[0..10];
        let first_10_from_page = &page1[..];

        for i in 0..10 {
            assert_eq!(
                first_10_from_all[i].message_id,
                first_10_from_page[i].message_id,
                "Pagination should maintain same order as get_messages()"
            );
        }

        // Clean up
        tokio::fs::remove_dir_all(temp_dir).await.ok();
        Ok(())
    }

    #[tokio::test]
    async fn test_count_messages_nonexistent_session() -> Result<()> {
        let temp_dir = std::env::temp_dir().join(format!("archivist_test_{}", Uuid::now_v7()));
        let archivist = mk_archivist(temp_dir.clone()).await?;

        // Count messages for non-existent session (should return 0, not error)
        let nonexistent_scroll_id = Uuid::now_v7();
        let count = archivist.count_messages(nonexistent_scroll_id, None).await?;
        assert_eq!(count, 0, "Non-existent session should have 0 messages");

        // Clean up
        tokio::fs::remove_dir_all(temp_dir).await.ok();
        Ok(())
    }
}
