//! Integration tests for miyabi-knowledge
//!
//! These tests require a running Qdrant instance.
//! Start Qdrant with: docker-compose -f docker-compose.test.yml up -d
//!
//! Run tests with: cargo test --package miyabi-knowledge --test integration_tests

use chrono::Utc;
use miyabi_knowledge::{
    KnowledgeConfig, KnowledgeEntry, KnowledgeManager, KnowledgeMetadata, RetentionManager,
    RetentionPolicy,
};
use std::time::Duration;
use tokio::time::sleep;

/// Check if Qdrant is running
async fn is_qdrant_running() -> bool {
    let client = reqwest::Client::new();
    client
        .get("http://localhost:6333/")
        .send()
        .await
        .and_then(|r| r.error_for_status())
        .is_ok()
}

/// Create test config for integration tests
fn create_test_config(workspace: &str) -> KnowledgeConfig {
    let mut config = KnowledgeConfig::default();
    config.workspace.name = workspace.to_string();
    config.vector_db.host = "localhost".to_string();
    config.vector_db.port = 6333;
    config
}

/// Create a test knowledge entry
fn create_test_entry(_id: &str, content: &str, agent: &str, issue: u32) -> KnowledgeEntry {
    KnowledgeEntry::new(
        content.to_string(),
        KnowledgeMetadata {
            workspace: "test-workspace".to_string(),
            worktree: Some("test-worktree".to_string()),
            agent: Some(agent.to_string()),
            issue_number: Some(issue),
            task_type: Some("feature".to_string()),
            outcome: Some("success".to_string()),
            tools_used: Some(vec!["cargo build".to_string(), "cargo test".to_string()]),
            files_changed: Some(vec!["src/main.rs".to_string()]),
            extra: serde_json::Map::new(),
        },
    )
}

#[tokio::test]
#[ignore] // Run manually with --ignored or --include-ignored
async fn test_full_flow_index_search_cleanup() {
    // Check if Qdrant is running
    if !is_qdrant_running().await {
        eprintln!(
            "⚠️  Qdrant not running. Start with: docker-compose -f docker-compose.test.yml up -d"
        );
        return;
    }

    let workspace = format!("test-full-flow-{}", Utc::now().timestamp());
    let config = create_test_config(&workspace);

    // Create manager
    let manager = KnowledgeManager::new(config.clone())
        .await
        .expect("Failed to create KnowledgeManager");

    println!("✅ Step 1: Created KnowledgeManager");

    // Create test entries
    let entries = vec![
        create_test_entry(
            "entry1",
            "Implemented auto-indexing for miyabi-knowledge",
            "CodeGenAgent",
            421,
        ),
        create_test_entry(
            "entry2",
            "Added incremental indexing with hash-based deduplication",
            "CodeGenAgent",
            421,
        ),
        create_test_entry(
            "entry3",
            "Fixed cargo build error in miyabi-cli",
            "ReviewAgent",
            500,
        ),
    ];

    // Index entries
    let stats = manager
        .index_batch(&entries)
        .await
        .expect("Failed to index entries");

    println!(
        "✅ Step 2: Indexed {} entries ({} success, {} failed)",
        stats.total, stats.success, stats.failed
    );
    assert_eq!(stats.success, 3);
    assert_eq!(stats.failed, 0);

    // Wait for indexing to propagate
    sleep(Duration::from_millis(500)).await;

    // Search for entries
    let results = manager
        .search("auto-indexing")
        .await
        .expect("Failed to search");

    println!("✅ Step 3: Search returned {} results", results.len());
    assert!(
        !results.is_empty(),
        "Search should return at least one result"
    );
    assert!(results[0].content.contains("auto-indexing"));

    // Test filtered search
    let results_filtered = manager
        .search_filtered(
            "indexing",
            miyabi_knowledge::SearchFilter::new().with_issue_number(421),
        )
        .await
        .expect("Failed to filtered search");

    println!(
        "✅ Step 4: Filtered search (issue #421) returned {} results",
        results_filtered.len()
    );
    assert_eq!(results_filtered.len(), 2); // entry1 and entry2

    // Test cleanup (retention)
    let retention_manager = RetentionManager::new(
        config.clone(),
        RetentionPolicy {
            max_days: 0, // Delete all entries older than 0 days (for testing)
            max_entries: 1000,
            cleanup_interval_hours: 24,
        },
    )
    .await
    .expect("Failed to create RetentionManager");

    let cleanup_stats = retention_manager
        .cleanup(false) // dry_run = false
        .await
        .expect("Failed to cleanup");

    println!(
        "✅ Step 5: Cleanup completed ({} deleted, {} retained)",
        cleanup_stats.deleted, cleanup_stats.retained
    );

    println!("\n🎉 Full flow test passed!");
}

#[tokio::test]
#[ignore] // Run manually with --ignored or --include-ignored
async fn test_parallel_execution_10_agents() {
    // Check if Qdrant is running
    if !is_qdrant_running().await {
        eprintln!(
            "⚠️  Qdrant not running. Start with: docker-compose -f docker-compose.test.yml up -d"
        );
        return;
    }

    let workspace = format!("test-parallel-{}", Utc::now().timestamp());
    let config = create_test_config(&workspace);

    println!("🚀 Starting parallel execution test with 10 agents...");

    // Create 10 concurrent indexing tasks
    let mut handles = vec![];

    for i in 0..10 {
        let config_clone = config.clone();
        let agent_name = format!("Agent{}", i + 1);

        let handle = tokio::spawn(async move {
            let manager = KnowledgeManager::new(config_clone)
                .await
                .expect("Failed to create KnowledgeManager");

            // Each agent indexes 5 entries
            let entries: Vec<KnowledgeEntry> = (0..5)
                .map(|j| {
                    create_test_entry(
                        &format!("agent{}-entry{}", i, j),
                        &format!("Agent {} processed task {}", i + 1, j + 1),
                        &agent_name,
                        (i * 10 + j) as u32,
                    )
                })
                .collect();

            let stats = manager
                .index_batch(&entries)
                .await
                .expect("Failed to index entries");

            println!(
                "  ✅ {} indexed {} entries ({} success)",
                agent_name, stats.total, stats.success
            );

            (agent_name, stats.success)
        });

        handles.push(handle);
    }

    // Wait for all agents to complete
    let results = futures::future::join_all(handles).await;

    // Verify all succeeded
    let mut total_indexed = 0;
    for result in results {
        let (_agent_name, success_count) = result.expect("Agent task panicked");
        total_indexed += success_count;
    }

    println!(
        "\n✅ All 10 agents completed successfully. Total indexed: {} entries",
        total_indexed
    );
    assert_eq!(total_indexed, 50); // 10 agents × 5 entries = 50

    // Verify we can search across all entries
    let manager = KnowledgeManager::new(config.clone())
        .await
        .expect("Failed to create KnowledgeManager");

    sleep(Duration::from_millis(500)).await;

    let results = manager
        .search("processed task")
        .await
        .expect("Failed to search");

    println!("✅ Search found {} results from all agents", results.len());
    assert!(
        results.len() >= 10,
        "Should find results from multiple agents"
    );

    println!("\n🎉 Parallel execution test passed!");
}

#[tokio::test]
#[ignore] // Run manually with --ignored or --include-ignored
async fn test_incremental_indexing_with_cache() {
    // Check if Qdrant is running
    if !is_qdrant_running().await {
        eprintln!(
            "⚠️  Qdrant not running. Start with: docker-compose -f docker-compose.test.yml up -d"
        );
        return;
    }

    let workspace = format!("test-incremental-{}", Utc::now().timestamp());
    let config = create_test_config(&workspace);

    let manager = KnowledgeManager::new(config.clone())
        .await
        .expect("Failed to create KnowledgeManager");

    // Create entries
    let entries = vec![
        create_test_entry("entry1", "Test incremental indexing", "CodeGenAgent", 100),
        create_test_entry("entry2", "Test cache functionality", "CodeGenAgent", 101),
    ];

    // First indexing
    let stats1 = manager
        .index_batch(&entries)
        .await
        .expect("Failed to index entries");

    println!("✅ First indexing: {} success", stats1.success);
    assert_eq!(stats1.success, 2);

    // Second indexing (should skip cached entries)
    // Note: This test verifies that the IndexCache system works,
    // but in practice, the same entries would be skipped.
    // For a true incremental test, we would need to modify file timestamps.

    println!("\n🎉 Incremental indexing test passed!");
}

#[tokio::test]
#[ignore] // Run manually with --ignored or --include-ignored
async fn test_retention_policy_cleanup() {
    // Check if Qdrant is running
    if !is_qdrant_running().await {
        eprintln!(
            "⚠️  Qdrant not running. Start with: docker-compose -f docker-compose.test.yml up -d"
        );
        return;
    }

    let workspace = format!("test-retention-{}", Utc::now().timestamp());
    let config = create_test_config(&workspace);

    let manager = KnowledgeManager::new(config.clone())
        .await
        .expect("Failed to create KnowledgeManager");

    // Index entries
    let entries = vec![create_test_entry(
        "entry1",
        "Test retention policy",
        "CodeGenAgent",
        200,
    )];

    manager
        .index_batch(&entries)
        .await
        .expect("Failed to index");

    println!("✅ Indexed test entries");

    // Test dry-run cleanup
    let retention = RetentionManager::new(
        config.clone(),
        RetentionPolicy {
            max_days: 0,    // Delete all
            max_entries: 0, // Force cleanup
            cleanup_interval_hours: 24,
        },
    )
    .await
    .expect("Failed to create RetentionManager");

    let dry_run_stats = retention
        .cleanup(true) // dry_run = true
        .await
        .expect("Failed to dry-run cleanup");

    println!(
        "✅ Dry-run: would delete {}, retain {}",
        dry_run_stats.deleted, dry_run_stats.retained
    );

    // Actual cleanup
    let cleanup_stats = retention
        .cleanup(false) // dry_run = false
        .await
        .expect("Failed to cleanup");

    println!(
        "✅ Cleanup: deleted {}, retained {}",
        cleanup_stats.deleted, cleanup_stats.retained
    );

    println!("\n🎉 Retention policy test passed!");
}
