//! Integration tests for Knowledge Lifecycle Management (Phase 13).
//!
//! Tests cover:
//! - Pattern deprecation with sunset dates
//! - Status transitions and audit trail
//! - Migration tracking across projects
//! - Scan integration with deprecated pattern detection

use chrono::{Duration, Utc};
use tempfile::tempdir;
use uuid::Uuid;

use crate::learning::{ClaimTemplate, LearnedPattern, ValueType};
use crate::lifecycle::{KnowledgeStatus, LifecycleStore, MigrationStore, StatusTransition};
use crate::scope::ScopeId;
use crate::types::Language;

/// Test basic lifecycle status transitions.
#[test]
fn test_lifecycle_status_transitions() {
    let dir = tempdir().expect("create temp dir");
    let store = LifecycleStore::new(dir.path()).expect("create lifecycle store");

    let pattern_id = Uuid::new_v4();

    // Initial state should be Active (implicit)
    assert!(store.get_current_status(&pattern_id).is_none());

    // Deprecate the pattern
    let deprecation = KnowledgeStatus::Deprecated {
        reason: "Security vulnerability discovered".to_string(),
        superseded_by: None,
        sunset_date: Some(Utc::now() + Duration::days(90)),
        migration_guide: Some("https://example.com/migration".to_string()),
    };

    let transition1 = StatusTransition::new(
        pattern_id,
        KnowledgeStatus::Active,
        deprecation.clone(),
        "security-team",
        Some("CVE-2024-1234 requires deprecation".to_string()),
    );
    store.record_transition(transition1).expect("record transition");

    // Verify status changed
    let status = store.get_current_status(&pattern_id).expect("has status");
    assert!(status.is_deprecated());

    // Archive the pattern after sunset
    let archived = KnowledgeStatus::Archived {
        archived_at: Utc::now(),
        reason: "Pattern removed after sunset".to_string(),
    };

    let transition2 = StatusTransition::new(
        pattern_id,
        deprecation,
        archived,
        "system",
        Some("Auto-archived after sunset".to_string()),
    );
    store.record_transition(transition2).expect("record transition");

    // Verify final status
    let status = store.get_current_status(&pattern_id).expect("has status");
    assert!(status.is_terminal());

    // Check history
    let history = store.get_history(&pattern_id);
    assert_eq!(history.len(), 2);
    assert_eq!(history[0].initiated_by, "security-team");
    assert_eq!(history[1].initiated_by, "system");
}

/// Test sunset date tracking.
#[test]
fn test_sunset_date_tracking() {
    // Future sunset date
    let future_date = Utc::now() + Duration::days(30);
    let status = KnowledgeStatus::Deprecated {
        reason: "Will be removed".to_string(),
        superseded_by: None,
        sunset_date: Some(future_date),
        migration_guide: None,
    };

    assert!(!status.is_past_sunset());
    let days = status.days_until_sunset().expect("has days");
    assert!((29..=31).contains(&days)); // Account for timing

    // Past sunset date
    let past_date = Utc::now() - Duration::days(10);
    let overdue = KnowledgeStatus::Deprecated {
        reason: "Should have been removed".to_string(),
        superseded_by: None,
        sunset_date: Some(past_date),
        migration_guide: None,
    };

    assert!(overdue.is_past_sunset());
    let days = overdue.days_until_sunset().expect("has days");
    assert!(days < 0);
}

/// Test pattern with replacement (superseded_by).
#[test]
fn test_pattern_supersession() {
    let new_pattern_id = Uuid::new_v4();

    let deprecated = KnowledgeStatus::Deprecated {
        reason: "Replaced by improved pattern".to_string(),
        superseded_by: Some(new_pattern_id),
        sunset_date: Some(Utc::now() + Duration::days(60)),
        migration_guide: Some("Run: aphoria migrate <pattern-id>".to_string()),
    };

    assert_eq!(deprecated.superseded_by(), Some(new_pattern_id));
    assert!(deprecated.is_active()); // Deprecated patterns still match

    // Later mark as fully superseded (no longer active)
    let superseded =
        KnowledgeStatus::Superseded { replaced_by: new_pattern_id, superseded_at: Utc::now() };

    assert!(!superseded.is_active()); // Superseded patterns don't match
    assert!(superseded.is_terminal());
    assert_eq!(superseded.superseded_by(), Some(new_pattern_id));
}

/// Test migration store tracking.
#[test]
fn test_migration_tracking() {
    let dir = tempdir().expect("create temp dir");
    let store = MigrationStore::new(dir.path()).expect("create migration store");

    let pattern_id = Uuid::new_v4();

    // Record usages across projects
    for i in 0..5 {
        let usage = crate::lifecycle::DeprecatedUsage::new(
            pattern_id,
            "tls_min_version",
            format!("project{}/src/config.rs", i),
            42 + i,
            format!("project-hash-{}", i),
        );
        store.record_usage(usage).expect("record usage");
    }

    // Check progress
    let progress = store.get_progress(&pattern_id, "tls_min_version");
    assert_eq!(progress.total_usages, 5);
    assert_eq!(progress.resolved_usages, 0);
    assert_eq!(progress.completion_percent(), 0.0);
    assert!(!progress.is_complete());

    // Resolve some usages
    store.resolve_usage(&pattern_id, "project0/src/config.rs", 42).expect("resolve");
    store.resolve_usage(&pattern_id, "project1/src/config.rs", 43).expect("resolve");

    // Check updated progress
    let progress = store.get_progress(&pattern_id, "tls_min_version");
    assert_eq!(progress.total_usages, 5);
    assert_eq!(progress.resolved_usages, 2);
    assert_eq!(progress.completion_percent(), 40.0);
    assert_eq!(progress.pending_usages(), 3);
}

/// Test migration with scope tracking.
#[test]
fn test_migration_with_scopes() {
    let dir = tempdir().expect("create temp dir");
    let store = MigrationStore::new(dir.path()).expect("create migration store");

    let pattern_id = Uuid::new_v4();
    let team_scope = ScopeId::team("platform");

    // Record usage with scope
    let usage = crate::lifecycle::DeprecatedUsage::new(
        pattern_id,
        "jwt_validation",
        "src/auth.rs",
        100,
        "api-gateway-hash",
    )
    .with_scope(team_scope.clone());

    store.record_usage(usage).expect("record usage");

    // Get usages by scope
    let team_usages = store.get_usages_by_scope(&team_scope);
    assert_eq!(team_usages.len(), 1);
    assert_eq!(team_usages[0].pattern_name, "jwt_validation");
}

/// Test lifecycle field in LearnedPattern.
#[test]
fn test_learned_pattern_lifecycle() {
    let template =
        ClaimTemplate::new("tls/min_version", "version", ValueType::Text, "TLS minimum version");

    let mut pattern = LearnedPattern::new(
        "const TLS_MIN = \"1.0\"",
        "const TLS_MIN = <string:version>",
        template,
        Language::Rust,
        "project-hash",
        0.95,
    );

    // Default lifecycle is Active
    assert!(pattern.lifecycle.is_active());
    assert!(!pattern.lifecycle.is_deprecated());

    // Update to deprecated
    let deprecated = KnowledgeStatus::Deprecated {
        reason: "TLS 1.0 is insecure".to_string(),
        superseded_by: None,
        sunset_date: Some(Utc::now() + Duration::days(30)),
        migration_guide: Some("Use TLS 1.2 or higher".to_string()),
    };
    pattern.lifecycle.update_status(deprecated);

    assert!(pattern.lifecycle.is_deprecated());
    assert!(pattern.lifecycle.is_active()); // Deprecated patterns still match
}

/// Test lifecycle store persistence.
#[test]
fn test_lifecycle_store_persistence() {
    let dir = tempdir().expect("create temp dir");
    let pattern_id = Uuid::new_v4();

    // Create store and record transition
    {
        let store = LifecycleStore::new(dir.path()).expect("create store");

        let transition = StatusTransition::new(
            pattern_id,
            KnowledgeStatus::Active,
            KnowledgeStatus::Deprecated {
                reason: "Persistence test".to_string(),
                superseded_by: None,
                sunset_date: None,
                migration_guide: None,
            },
            "test-user",
            None,
        );

        store.record_transition(transition).expect("record");
    }

    // Reopen store and verify
    {
        let store = LifecycleStore::new(dir.path()).expect("reopen store");

        let status = store.get_current_status(&pattern_id).expect("has status");
        assert!(status.is_deprecated());

        let history = store.get_history(&pattern_id);
        assert_eq!(history.len(), 1);
        assert_eq!(history[0].initiated_by, "test-user");
    }
}

/// Test getting overdue patterns.
#[test]
fn test_get_overdue_patterns() {
    let dir = tempdir().expect("create temp dir");
    let store = LifecycleStore::new(dir.path()).expect("create store");

    let pattern1 = Uuid::new_v4();
    let pattern2 = Uuid::new_v4();
    let pattern3 = Uuid::new_v4();

    // Pattern 1: deprecated with past sunset
    store
        .record_transition(StatusTransition::new(
            pattern1,
            KnowledgeStatus::Active,
            KnowledgeStatus::Deprecated {
                reason: "Old".to_string(),
                superseded_by: None,
                sunset_date: Some(Utc::now() - Duration::days(10)),
                migration_guide: None,
            },
            "test",
            None,
        ))
        .expect("record");

    // Pattern 2: deprecated with future sunset
    store
        .record_transition(StatusTransition::new(
            pattern2,
            KnowledgeStatus::Active,
            KnowledgeStatus::Deprecated {
                reason: "Soon".to_string(),
                superseded_by: None,
                sunset_date: Some(Utc::now() + Duration::days(30)),
                migration_guide: None,
            },
            "test",
            None,
        ))
        .expect("record");

    // Pattern 3: deprecated with no sunset
    store
        .record_transition(StatusTransition::new(
            pattern3,
            KnowledgeStatus::Active,
            KnowledgeStatus::Deprecated {
                reason: "Eventually".to_string(),
                superseded_by: None,
                sunset_date: None,
                migration_guide: None,
            },
            "test",
            None,
        ))
        .expect("record");

    // Only pattern1 should be overdue
    let overdue = store.get_overdue_patterns();
    assert_eq!(overdue.len(), 1);
    assert_eq!(overdue[0].0, pattern1);
}

/// Test CSV export of migration data.
#[test]
fn test_migration_export_csv() {
    let dir = tempdir().expect("create temp dir");
    let store = MigrationStore::new(dir.path()).expect("create store");

    let pattern_id = Uuid::new_v4();

    let usage = crate::lifecycle::DeprecatedUsage::new(
        pattern_id,
        "test_pattern",
        "src/main.rs",
        50,
        "hash-abc",
    );
    store.record_usage(usage).expect("record");

    let csv = store.export_csv(true);

    assert!(csv.contains("pattern_id"));
    assert!(csv.contains("test_pattern"));
    assert!(csv.contains("src/main.rs"));
    assert!(csv.contains("50"));
}

/// Test status transition audit trail.
#[test]
fn test_status_transition_audit() {
    let pattern_id = Uuid::new_v4();

    let transition = StatusTransition::new(
        pattern_id,
        KnowledgeStatus::Active,
        KnowledgeStatus::Deprecated {
            reason: "Audit test".to_string(),
            superseded_by: None,
            sunset_date: None,
            migration_guide: None,
        },
        "admin@example.com",
        Some("Approved in security review #123".to_string()),
    );

    assert_eq!(transition.pattern_id, pattern_id);
    assert_eq!(transition.initiated_by, "admin@example.com");
    assert_eq!(transition.comment, Some("Approved in security review #123".to_string()));

    let desc = transition.description();
    assert!(desc.contains("active"));
    assert!(desc.contains("deprecated"));
}
