//! Integration tests for conflict detection (Phase 2A).

use crate::*;
use ed25519_dalek::SigningKey;
use stemedb_core::types::{Assertion, ObjectValue, SourceClass};

/// Create a minimal test corpus for integration tests.
#[allow(clippy::vec_init_then_push)]
#[allow(dead_code)]
fn create_test_corpus(signing_key: &SigningKey) -> Vec<Assertion> {
    let timestamp = crate::episteme::current_timestamp();
    let mut assertions = Vec::new();

    // TLS verification (RFC 5246 + OWASP)
    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "rfc://5246/tls/cert_verification",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Regulatory,
        "TLS certificate verification MUST be enabled (RFC 5246)",
        timestamp,
    ));

    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "owasp://transport_layer/tls/cert_verification",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Clinical,
        "OWASP: Always verify TLS certificates",
        timestamp,
    ));

    // JWT validation (RFC 7519)
    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "rfc://7519/jwt/audience_validation",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Regulatory,
        "JWT audience claim MUST be validated (RFC 7519 Section 4.1.3)",
        timestamp,
    ));

    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "rfc://7519/jwt/expiry_validation",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Regulatory,
        "JWT expiry claim MUST be validated (RFC 7519 Section 4.1.4)",
        timestamp,
    ));

    // CORS security (OWASP)
    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "owasp://cors/allow_origin",
        "config_value",
        ObjectValue::Text("explicit_list".to_string()),
        SourceClass::Clinical,
        "OWASP: Never use wildcard (*) for CORS Allow-Origin in production",
        timestamp,
    ));

    // Secrets management (OWASP)
    assertions.push(crate::episteme::create_authoritative_assertion(
        signing_key,
        "owasp://secrets/api_key",
        "storage_method",
        ObjectValue::Text("environment_or_vault".to_string()),
        SourceClass::Clinical,
        "OWASP: Never hardcode API keys in source code",
        timestamp,
    ));

    assertions
}

#[ignore = "Needs corpus refactor after hardcoded deletion"]
#[tokio::test]
async fn test_conflict_detection_tls_disabled() {
    // Create temp project with danger_accept_invalid_certs(true)
    let temp_dir =
        tempfile::Builder::new().prefix("aphoria_tls_conflict").tempdir().expect("create temp dir");

    let src_dir = temp_dir.path().join("src");
    std::fs::create_dir_all(&src_dir).expect("create src dir");

    // Write a Rust file with TLS verification disabled
    std::fs::write(
        src_dir.join("client.rs"),
        r#"
            fn create_client() -> Result<Client, Error> {
                let client = reqwest::Client::builder()
                    .danger_accept_invalid_certs(true)
                    .build()?;
                Ok(client)
            }
            "#,
    )
    .expect("write file");

    // Create Cargo.toml so it's detected as a Rust project
    std::fs::write(
        temp_dir.path().join("Cargo.toml"),
        r#"
            [package]
            name = "testproject"
            version = "0.1.0"
            "#,
    )
    .expect("write cargo.toml");

    let args = ScanArgs {
        path: temp_dir.path().to_path_buf(),
        format: "table".to_string(),
        exit_code_enabled: true,
        mode: ScanMode::Ephemeral,
        debug: false,
        sync: false,
        file_source: FileSource::All,
        benchmark: false,
        show_claims: false,
        strict: false,
        show_observations: false,
        explain_authority: false,
        suggest_convergence: false,
    };

    let mut config = AphoriaConfig::default();
    config.episteme.data_dir = temp_dir.path().join(".aphoria").join("db");

    let result = run_scan(args, &config).await.expect("scan should succeed");

    // Assert: conflicts not empty, has_blocks() == true
    assert!(
        !result.conflicts.is_empty(),
        "Should detect conflicts for TLS verification disabled. \
             Claims extracted: {}, Files scanned: {}",
        result.claims_extracted,
        result.files_scanned
    );

    assert!(
        result.has_blocks(),
        "TLS verification disabled should be a BLOCK verdict. \
             Conflicts: {:?}",
        result.conflicts.iter().map(|c| (&c.claim.concept_path, &c.verdict)).collect::<Vec<_>>()
    );
}

#[ignore = "Needs corpus refactor after hardcoded deletion"]
#[tokio::test]
async fn test_conflict_detection_jwt_audience_disabled() {
    // Create temp project with JWT audience validation disabled
    let temp_dir =
        tempfile::Builder::new().prefix("aphoria_jwt_conflict").tempdir().expect("create temp dir");

    let src_dir = temp_dir.path().join("src");
    std::fs::create_dir_all(&src_dir).expect("create src dir");

    // Write a Rust file with JWT audience validation disabled
    std::fs::write(
        src_dir.join("auth.rs"),
        r#"
            fn validate_token(token: &str) -> Result<Claims, Error> {
                let mut validation = Validation::default();
                validation.validate_aud = false;  // Disabled!
                let token_data = decode::<Claims>(token, &key, &validation)?;
                Ok(token_data.claims)
            }
            "#,
    )
    .expect("write file");

    // Create Cargo.toml
    std::fs::write(
        temp_dir.path().join("Cargo.toml"),
        r#"
            [package]
            name = "testproject"
            version = "0.1.0"
            "#,
    )
    .expect("write cargo.toml");

    let args = ScanArgs {
        path: temp_dir.path().to_path_buf(),
        format: "table".to_string(),
        exit_code_enabled: true,
        mode: ScanMode::Ephemeral,
        debug: false,
        sync: false,
        file_source: FileSource::All,
        benchmark: false,
        show_claims: false,
        strict: false,
        show_observations: false,
        explain_authority: false,
        suggest_convergence: false,
    };

    let mut config = AphoriaConfig::default();
    config.episteme.data_dir = temp_dir.path().join(".aphoria").join("db");

    let result = run_scan(args, &config).await.expect("scan should succeed");

    // Assert: conflicts not empty for JWT audience validation
    assert!(
        !result.conflicts.is_empty(),
        "Should detect conflicts for JWT audience validation disabled. \
             Claims extracted: {}, Files scanned: {}",
        result.claims_extracted,
        result.files_scanned
    );

    // Check that at least one conflict is about JWT audience
    let has_jwt_conflict = result
        .conflicts
        .iter()
        .any(|c| c.claim.concept_path.contains("jwt") && c.claim.concept_path.contains("audience"));
    assert!(
        has_jwt_conflict,
        "Should have a conflict about JWT audience validation. \
             Conflicts: {:?}",
        result.conflicts.iter().map(|c| &c.claim.concept_path).collect::<Vec<_>>()
    );
}

#[ignore = "Needs corpus refactor after hardcoded deletion"]
#[tokio::test]
async fn test_no_conflicts_when_compliant() {
    // Create temp project with compliant code (no dangerous patterns)
    let temp_dir =
        tempfile::Builder::new().prefix("aphoria_compliant").tempdir().expect("create temp dir");

    let src_dir = temp_dir.path().join("src");
    std::fs::create_dir_all(&src_dir).expect("create src dir");

    // Write a Rust file with compliant code
    std::fs::write(
        src_dir.join("main.rs"),
        r#"
            fn main() {
                println!("Hello, world!");
            }
            "#,
    )
    .expect("write file");

    // Create Cargo.toml
    std::fs::write(
        temp_dir.path().join("Cargo.toml"),
        r#"
            [package]
            name = "testproject"
            version = "0.1.0"
            "#,
    )
    .expect("write cargo.toml");

    let args = ScanArgs {
        path: temp_dir.path().to_path_buf(),
        format: "table".to_string(),
        exit_code_enabled: true,
        mode: ScanMode::Ephemeral,
        debug: false,
        sync: false,
        file_source: FileSource::All,
        benchmark: false,
        show_claims: false,
        strict: false,
        show_observations: false,
        explain_authority: false,
        suggest_convergence: false,
    };

    let mut config = AphoriaConfig::default();
    config.episteme.data_dir = temp_dir.path().join(".aphoria").join("db");

    let result = run_scan(args, &config).await.expect("scan should succeed");

    // No dangerous patterns = no claims = no conflicts
    assert!(
        result.conflicts.is_empty(),
        "Compliant code should have no conflicts. Found: {:?}",
        result.conflicts.iter().map(|c| &c.claim.concept_path).collect::<Vec<_>>()
    );
}
