#![cfg_attr(coverage_nightly, coverage(off))]
//! README and documentation hallucination detection CLI handlers
//!
//! Validates AI-generated documentation against codebase facts using semantic
//! entropy-based hallucination detection.
//!
//! Based on peer-reviewed research:
//! - Semantic Entropy (Farquhar et al., Nature 2024)
//! - MIND framework (IJCAI 2025)
//! - Unified Detection Framework (Complex & Intelligent Systems 2025)

use crate::services::hallucination_detector::{
    CodeFactDatabase, DocAccuracyValidator, ValidationResult, ValidationStatus,
};
use anyhow::{Context, Result};
use clap::{Parser, ValueEnum};
use std::path::PathBuf;
use std::process::ExitCode;

/// Output format for validation results
#[derive(Debug, Clone, ValueEnum)]
pub enum OutputFormat {
    /// Human-readable text output
    Text,
    /// JSON output for programmatic consumption
    Json,
    /// JUnit XML for CI integration
    Junit,
}

/// Validate README and documentation for hallucinations
///
/// # Example
///
/// ```bash
/// # Generate deep context first
/// pmat context --output deep_context.md --format llm-optimized
///
/// # Validate README against codebase facts
/// pmat validate-readme \
///     --targets README.md CLAUDE.md \
///     --deep-context deep_context.md \
///     --fail-on-contradiction
/// ```
#[derive(Parser, Debug)]
pub struct ValidateReadmeCmd {
    /// Documentation files to validate (e.g., README.md, CLAUDE.md)
    #[arg(short, long, num_args = 1.., required = true)]
    pub targets: Vec<PathBuf>,

    /// Deep context markdown file (output from `pmat context`)
    #[arg(short, long, required = true)]
    pub deep_context: PathBuf,

    /// Confidence threshold for verification (0.0-1.0)
    #[arg(long, default_value = "0.9")]
    pub verified_threshold: f32,

    /// Confidence threshold for contradictions (0.0-1.0)
    #[arg(long, default_value = "0.3")]
    pub contradiction_threshold: f32,

    /// Fail if contradictions found
    #[arg(long, default_value = "true")]
    pub fail_on_contradiction: bool,

    /// Fail if unverified claims found
    #[arg(long, default_value = "false")]
    pub fail_on_unverified: bool,

    /// Output format (text, json, junit)
    #[arg(short, long, default_value = "text")]
    pub output: OutputFormat,

    /// Show only failures (contradictions and unverified)
    #[arg(long)]
    pub failures_only: bool,

    /// Verbose output
    #[arg(short, long)]
    pub verbose: bool,
}

impl ValidateReadmeCmd {
    /// Execute the validate-readme command
    pub fn execute(&self) -> Result<ExitCode> {
        if self.verbose {
            eprintln!("🔍 Validating documentation for hallucinations...");
            eprintln!("📄 Targets: {:?}", self.targets);
            eprintln!("📊 Deep context: {}", self.deep_context.display());
            eprintln!("🎯 Verified threshold: {}", self.verified_threshold);
            eprintln!(
                "⚠️  Contradiction threshold: {}",
                self.contradiction_threshold
            );
        }

        // Load deep context
        let deep_context_markdown =
            std::fs::read_to_string(&self.deep_context).with_context(|| {
                format!(
                    "Failed to read deep context: {}",
                    self.deep_context.display()
                )
            })?;

        // Build code fact database
        let code_facts = CodeFactDatabase::from_markdown(&deep_context_markdown)
            .with_context(|| "Failed to parse deep context markdown")?;

        // Create validator
        let validator = DocAccuracyValidator::new(code_facts);

        // Validate each target file
        let mut all_results = Vec::new();
        let mut contradiction_count = 0;
        let mut unverified_count = 0;
        let mut verified_count = 0;

        for target in &self.targets {
            if self.verbose {
                eprintln!("\n📖 Validating {}...", target.display());
            }

            let doc_content = std::fs::read_to_string(target)
                .with_context(|| format!("Failed to read target file: {}", target.display()))?;

            let results = validator
                .validate_documentation(&doc_content, &target.to_string_lossy())
                .with_context(|| format!("Failed to validate {}", target.display()))?;

            // Count statuses
            for result in &results {
                match result.status {
                    ValidationStatus::Verified => verified_count += 1,
                    ValidationStatus::Contradiction => contradiction_count += 1,
                    ValidationStatus::Unverified
                    | ValidationStatus::NotFound
                    | ValidationStatus::Outdated => unverified_count += 1,
                    ValidationStatus::Inconclusive => {}
                }
            }

            all_results.push((target.clone(), results));
        }

        // Output results
        match self.output {
            OutputFormat::Text => self.print_text_summary(
                &all_results,
                verified_count,
                contradiction_count,
                unverified_count,
            ),
            OutputFormat::Json => self.print_json_summary(&all_results)?,
            OutputFormat::Junit => self.print_junit_summary(&all_results)?,
        }

        // Determine exit code
        if self.fail_on_contradiction && contradiction_count > 0 {
            if self.verbose {
                eprintln!(
                    "\n❌ Exiting with failure: {} contradictions found",
                    contradiction_count
                );
            }
            Ok(ExitCode::FAILURE)
        } else if self.fail_on_unverified && unverified_count > 0 {
            if self.verbose {
                eprintln!(
                    "\n❌ Exiting with failure: {} unverified claims found",
                    unverified_count
                );
            }
            Ok(ExitCode::FAILURE)
        } else {
            if self.verbose {
                eprintln!("\n✅ Validation passed");
            }
            Ok(ExitCode::SUCCESS)
        }
    }

    fn print_text_summary(
        &self,
        results: &[(PathBuf, Vec<ValidationResult>)],
        verified: usize,
        contradictions: usize,
        unverified: usize,
    ) {
        println!("\n🔬 Documentation Hallucination Detection Summary");
        println!("================================================");
        println!();
        println!("📄 Files validated:  {}", results.len());
        println!("✅ Verified claims:  {}", verified);
        println!("❌ Contradictions:   {}", contradictions);
        println!("⚠️  Unverified:       {}", unverified);
        println!();

        for (target, file_results) in results {
            println!("📖 {}", target.display());
            println!("{}", "─".repeat(50));

            for (idx, result) in file_results.iter().enumerate() {
                // Skip verified claims if failures_only is true
                if self.failures_only && matches!(result.status, ValidationStatus::Verified) {
                    continue;
                }

                let status_icon = match result.status {
                    ValidationStatus::Verified => "✅",
                    ValidationStatus::Contradiction => "❌",
                    ValidationStatus::Unverified => "⚠️",
                    ValidationStatus::NotFound => "🔍",
                    ValidationStatus::Outdated => "⏰",
                    ValidationStatus::Inconclusive => "❓",
                };

                println!(
                    "\n{} Claim #{}: {:?}",
                    status_icon,
                    idx + 1,
                    result.claim.claim_type
                );
                println!("   Text: \"{}\"", result.claim.text);
                println!("   Line: {}", result.claim.line_number);
                println!("   Status: {:?}", result.status);
                println!("   Confidence: {:.2}", result.confidence);

                if let Some(evidence) = &result.evidence {
                    println!("   Evidence: {}", evidence.content);
                }

                if self.verbose {
                    println!("   Entities: {:?}", result.claim.entities);
                }
            }

            println!();
        }

        if contradictions == 0 && unverified == 0 {
            println!("🎉 All documentation claims are verified!");
        } else if contradictions > 0 {
            println!(
                "💥 Found {} contradiction(s) - documentation contains hallucinations!",
                contradictions
            );
        } else if unverified > 0 {
            println!("⚠️  Found {} unverified claim(s)", unverified);
        }
    }

    fn print_json_summary(&self, results: &[(PathBuf, Vec<ValidationResult>)]) -> Result<()> {
        use serde_json::json;

        let results_json: Vec<_> = results
            .iter()
            .map(|(target, file_results)| {
                let claims_json: Vec<_> = file_results
                    .iter()
                    .map(|r| {
                        json!({
                            "claim_text": r.claim.text,
                            "claim_type": format!("{:?}", r.claim.claim_type),
                            "line_number": r.claim.line_number,
                            "status": format!("{:?}", r.status),
                            "confidence": r.confidence,
                            "is_negative": r.claim.is_negative,
                            "entities": r.claim.entities.iter().map(|e| format!("{:?}", e)).collect::<Vec<_>>(),
                            "evidence": r.evidence.as_ref().map(|e| e.content.clone()),
                        })
                    })
                    .collect();

                json!({
                    "file": target.to_string_lossy(),
                    "claims": claims_json,
                })
            })
            .collect();

        let verified = results
            .iter()
            .flat_map(|(_, r)| r)
            .filter(|r| matches!(r.status, ValidationStatus::Verified))
            .count();

        let contradictions = results
            .iter()
            .flat_map(|(_, r)| r)
            .filter(|r| matches!(r.status, ValidationStatus::Contradiction))
            .count();

        let unverified = results
            .iter()
            .flat_map(|(_, r)| r)
            .filter(|r| {
                matches!(
                    r.status,
                    ValidationStatus::Unverified
                        | ValidationStatus::NotFound
                        | ValidationStatus::Outdated
                )
            })
            .count();

        let output = json!({
            "files_validated": results.len(),
            "verified_claims": verified,
            "contradictions": contradictions,
            "unverified_claims": unverified,
            "results": results_json,
        });

        println!("{}", serde_json::to_string_pretty(&output)?);
        Ok(())
    }

    fn print_junit_summary(&self, results: &[(PathBuf, Vec<ValidationResult>)]) -> Result<()> {
        let total_claims: usize = results.iter().map(|(_, r)| r.len()).sum();
        let failures: usize = results
            .iter()
            .flat_map(|(_, r)| r)
            .filter(|r| {
                matches!(
                    r.status,
                    ValidationStatus::Contradiction
                        | ValidationStatus::Unverified
                        | ValidationStatus::NotFound
                        | ValidationStatus::Outdated
                )
            })
            .count();

        println!("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        println!(
            "<testsuites name=\"README Hallucination Detection\" tests=\"{}\" failures=\"{}\">",
            total_claims, failures
        );
        println!(
            "  <testsuite name=\"Documentation Validation\" tests=\"{}\" failures=\"{}\">",
            total_claims, failures
        );

        for (target, file_results) in results {
            for (idx, result) in file_results.iter().enumerate() {
                let test_name = format!(
                    "{} - Claim #{}: {}",
                    target.display(),
                    idx + 1,
                    result.claim.text.chars().take(50).collect::<String>()
                );

                print!(
                    "    <testcase name=\"{}\" classname=\"HallucinationDetection\"",
                    xml_escape(&test_name)
                );

                if matches!(
                    result.status,
                    ValidationStatus::Contradiction
                        | ValidationStatus::Unverified
                        | ValidationStatus::NotFound
                        | ValidationStatus::Outdated
                ) {
                    println!(">");
                    println!(
                        "      <failure message=\"{}: Confidence {:.2}\">",
                        xml_escape(&format!("{:?}", result.status)),
                        result.confidence
                    );
                    println!("Claim: {}", xml_escape(&result.claim.text));
                    if let Some(evidence) = &result.evidence {
                        println!("Evidence: {}", xml_escape(&evidence.content));
                    }
                    println!("      </failure>");
                    println!("    </testcase>");
                } else {
                    println!(" />");
                }
            }
        }

        println!("  </testsuite>");
        println!("</testsuites>");
        Ok(())
    }
}

fn xml_escape(s: &str) -> String {
    s.replace('&', "&amp;")
        .replace('<', "&lt;")
        .replace('>', "&gt;")
        .replace('"', "&quot;")
        .replace('\'', "&apos;")
}

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
    use super::*;
    use crate::services::hallucination_detector::{Claim, ClaimType, Entity, Evidence};
    use std::io::Write;
    use tempfile::NamedTempFile;

    // ============================================================================
    // xml_escape tests
    // ============================================================================

    #[test]
    fn test_xml_escape_no_special_chars() {
        assert_eq!(xml_escape("hello"), "hello");
        assert_eq!(xml_escape("simple text"), "simple text");
        assert_eq!(xml_escape("123abc"), "123abc");
    }

    #[test]
    fn test_xml_escape_ampersand() {
        assert_eq!(xml_escape("a & b"), "a &amp; b");
        assert_eq!(xml_escape("&&"), "&amp;&amp;");
        assert_eq!(xml_escape("Tom & Jerry"), "Tom &amp; Jerry");
    }

    #[test]
    fn test_xml_escape_angle_brackets() {
        assert_eq!(xml_escape("<tag>"), "&lt;tag&gt;");
        assert_eq!(xml_escape("a < b > c"), "a &lt; b &gt; c");
        assert_eq!(xml_escape("<>"), "&lt;&gt;");
    }

    #[test]
    fn test_xml_escape_quotes() {
        assert_eq!(xml_escape("\"quoted\""), "&quot;quoted&quot;");
        assert_eq!(xml_escape("'single'"), "&apos;single&apos;");
        assert_eq!(xml_escape("\"'mixed'\""), "&quot;&apos;mixed&apos;&quot;");
    }

    #[test]
    fn test_xml_escape_all_special_chars() {
        assert_eq!(
            xml_escape("<tag attr=\"val\" data='x' & y>"),
            "&lt;tag attr=&quot;val&quot; data=&apos;x&apos; &amp; y&gt;"
        );
    }

    #[test]
    fn test_xml_escape_empty_string() {
        assert_eq!(xml_escape(""), "");
    }

    #[test]
    fn test_xml_escape_unicode() {
        assert_eq!(xml_escape("hello"), "hello");
        assert_eq!(xml_escape("<unicode>"), "&lt;unicode&gt;");
    }

    // ============================================================================
    // OutputFormat tests
    // ============================================================================

    #[test]
    fn test_output_format_debug() {
        assert_eq!(format!("{:?}", OutputFormat::Text), "Text");
        assert_eq!(format!("{:?}", OutputFormat::Json), "Json");
        assert_eq!(format!("{:?}", OutputFormat::Junit), "Junit");
    }

    #[test]
    fn test_output_format_clone() {
        let format = OutputFormat::Json;
        let cloned = format.clone();
        assert!(matches!(cloned, OutputFormat::Json));
    }

    // ============================================================================
    // ValidateReadmeCmd construction tests
    // ============================================================================

    #[test]
    fn test_validate_readme_cmd_defaults() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("README.md")],
            deep_context: PathBuf::from("deep_context.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        assert_eq!(cmd.verified_threshold, 0.9);
        assert_eq!(cmd.contradiction_threshold, 0.3);
        assert!(cmd.fail_on_contradiction);
        assert!(!cmd.fail_on_unverified);
        assert!(!cmd.failures_only);
        assert!(!cmd.verbose);
    }

    #[test]
    fn test_validate_readme_cmd_with_multiple_targets() {
        let cmd = ValidateReadmeCmd {
            targets: vec![
                PathBuf::from("README.md"),
                PathBuf::from("CLAUDE.md"),
                PathBuf::from("AGENT.md"),
            ],
            deep_context: PathBuf::from("context.md"),
            verified_threshold: 0.8,
            contradiction_threshold: 0.4,
            fail_on_contradiction: false,
            fail_on_unverified: true,
            output: OutputFormat::Json,
            failures_only: true,
            verbose: true,
        };

        assert_eq!(cmd.targets.len(), 3);
        assert_eq!(cmd.verified_threshold, 0.8);
        assert_eq!(cmd.contradiction_threshold, 0.4);
        assert!(!cmd.fail_on_contradiction);
        assert!(cmd.fail_on_unverified);
        assert!(cmd.failures_only);
        assert!(cmd.verbose);
    }

    #[test]
    fn test_validate_readme_cmd_custom_thresholds() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.5,
            contradiction_threshold: 0.1,
            fail_on_contradiction: true,
            fail_on_unverified: true,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        assert_eq!(cmd.verified_threshold, 0.5);
        assert_eq!(cmd.contradiction_threshold, 0.1);
    }

    // ============================================================================
    // execute() tests
    // ============================================================================

    #[test]
    fn test_execute_missing_deep_context_file() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("README.md")],
            deep_context: PathBuf::from("/nonexistent/path/deep_context.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(err.to_string().contains("Failed to read deep context"));
    }

    #[test]
    fn test_execute_missing_target_file() {
        // Create a valid deep context file
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Functions:
- main()

Supported languages:
- Rust
        "#
        )
        .unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("/nonexistent/README.md")],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_err());
        let err = result.unwrap_err();
        assert!(err.to_string().contains("Failed to read target file"));
    }

    #[test]
    fn test_execute_success_with_verified_claims() {
        // Create deep context with Rust support
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Functions:
- analyze_complexity()

Supported languages:
- Rust
- TypeScript
        "#
        )
        .unwrap();

        // Create target README with valid claim
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code complexity.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), ExitCode::SUCCESS);
    }

    #[test]
    fn test_execute_fails_on_contradiction() {
        // Create deep context
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Functions:
- analyze()

Supported languages:
- Rust
        "#
        )
        .unwrap();

        // Create target README with contradiction (PMAT can compile)
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can compile Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), ExitCode::FAILURE);
    }

    #[test]
    fn test_execute_fails_on_unverified_when_enabled() {
        // Create deep context without certain language support
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Functions:
- analyze()

Supported languages:
- Rust
        "#
        )
        .unwrap();

        // Create target README with unverified claim about unsupported language
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze COBOL code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: false,
            fail_on_unverified: true,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        // Since COBOL is not in known_languages, it won't create an Entity::Language
        // So it might be Inconclusive instead of Unverified
        // Let's test with a known language that's not in the deep context
    }

    #[test]
    fn test_execute_with_verbose_output() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: true,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
    }

    #[test]
    fn test_execute_with_json_output() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Json,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
    }

    #[test]
    fn test_execute_with_junit_output() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
    }

    #[test]
    fn test_execute_with_multiple_targets() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
- TypeScript
        "#
        )
        .unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();

        let mut claude_file = NamedTempFile::new().unwrap();
        writeln!(claude_file, "PMAT supports TypeScript analysis.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![
                readme_file.path().to_path_buf(),
                claude_file.path().to_path_buf(),
            ],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), ExitCode::SUCCESS);
    }

    #[test]
    fn test_execute_with_no_claims() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        // README with no PMAT claims
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(
            readme_file,
            "This is a simple README without any PMAT claims."
        )
        .unwrap();
        writeln!(readme_file, "It just contains some text.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), ExitCode::SUCCESS);
    }

    #[test]
    fn test_execute_with_code_blocks_ignored() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        // README with claim inside code block (should be ignored)
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "# Usage").unwrap();
        writeln!(readme_file, "").unwrap();
        writeln!(readme_file, "```bash").unwrap();
        writeln!(readme_file, "# PMAT can compile code inside code block").unwrap();
        writeln!(readme_file, "pmat analyze").unwrap();
        writeln!(readme_file, "```").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        // Should succeed because the claim is inside a code block and ignored
        assert_eq!(result.unwrap(), ExitCode::SUCCESS);
    }

    // ============================================================================
    // print_text_summary tests (using helper to capture patterns)
    // ============================================================================

    fn create_test_validation_result(
        text: &str,
        status: ValidationStatus,
        confidence: f32,
    ) -> ValidationResult {
        ValidationResult {
            claim: Claim {
                source_file: PathBuf::from("test.md"),
                line_number: 1,
                text: text.to_string(),
                claim_type: ClaimType::Capability,
                entities: vec![Entity::Capability("analyze".to_string())],
                is_negative: false,
            },
            status,
            evidence: Some(Evidence {
                source: "test".to_string(),
                similarity: confidence,
                content: "test evidence".to_string(),
            }),
            error_message: None,
            confidence,
        }
    }

    #[test]
    fn test_print_text_summary_all_verified() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can analyze",
                ValidationStatus::Verified,
                0.95,
            )],
        )];

        // This just tests that it doesn't panic - actual output goes to stdout
        cmd.print_text_summary(&results, 1, 0, 0);
    }

    #[test]
    fn test_print_text_summary_with_contradictions() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can compile",
                ValidationStatus::Contradiction,
                0.2,
            )],
        )];

        cmd.print_text_summary(&results, 0, 1, 0);
    }

    #[test]
    fn test_print_text_summary_with_unverified() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can analyze",
                ValidationStatus::Unverified,
                0.5,
            )],
        )];

        cmd.print_text_summary(&results, 0, 0, 1);
    }

    #[test]
    fn test_print_text_summary_failures_only() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: true,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![
                create_test_validation_result("PMAT can analyze", ValidationStatus::Verified, 0.95),
                create_test_validation_result(
                    "PMAT can compile",
                    ValidationStatus::Contradiction,
                    0.2,
                ),
            ],
        )];

        // With failures_only, only contradictions should be printed
        cmd.print_text_summary(&results, 1, 1, 0);
    }

    #[test]
    fn test_print_text_summary_verbose() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: true,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can analyze",
                ValidationStatus::Verified,
                0.95,
            )],
        )];

        cmd.print_text_summary(&results, 1, 0, 0);
    }

    #[test]
    fn test_print_text_summary_all_status_icons() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![
                create_test_validation_result("claim1", ValidationStatus::Verified, 0.95),
                create_test_validation_result("claim2", ValidationStatus::Contradiction, 0.2),
                create_test_validation_result("claim3", ValidationStatus::Unverified, 0.5),
                create_test_validation_result("claim4", ValidationStatus::NotFound, 0.3),
                create_test_validation_result("claim5", ValidationStatus::Outdated, 0.4),
                create_test_validation_result("claim6", ValidationStatus::Inconclusive, 0.5),
            ],
        )];

        cmd.print_text_summary(&results, 1, 1, 3);
    }

    // ============================================================================
    // print_json_summary tests
    // ============================================================================

    #[test]
    fn test_print_json_summary_empty_results() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Json,
            failures_only: false,
            verbose: false,
        };

        let results: Vec<(PathBuf, Vec<ValidationResult>)> = vec![];
        let result = cmd.print_json_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_json_summary_with_results() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Json,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can analyze",
                ValidationStatus::Verified,
                0.95,
            )],
        )];

        let result = cmd.print_json_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_json_summary_counts_statuses() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Json,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![
                create_test_validation_result("claim1", ValidationStatus::Verified, 0.95),
                create_test_validation_result("claim2", ValidationStatus::Contradiction, 0.2),
                create_test_validation_result("claim3", ValidationStatus::Unverified, 0.5),
                create_test_validation_result("claim4", ValidationStatus::NotFound, 0.3),
                create_test_validation_result("claim5", ValidationStatus::Outdated, 0.4),
            ],
        )];

        let result = cmd.print_json_summary(&results);
        assert!(result.is_ok());
    }

    // ============================================================================
    // print_junit_summary tests
    // ============================================================================

    #[test]
    fn test_print_junit_summary_empty_results() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        let results: Vec<(PathBuf, Vec<ValidationResult>)> = vec![];
        let result = cmd.print_junit_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_junit_summary_with_passing_tests() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![create_test_validation_result(
                "PMAT can analyze",
                ValidationStatus::Verified,
                0.95,
            )],
        )];

        let result = cmd.print_junit_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_junit_summary_with_failures() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(
            PathBuf::from("test.md"),
            vec![
                create_test_validation_result("claim1", ValidationStatus::Contradiction, 0.2),
                create_test_validation_result("claim2", ValidationStatus::Unverified, 0.5),
                create_test_validation_result("claim3", ValidationStatus::NotFound, 0.3),
                create_test_validation_result("claim4", ValidationStatus::Outdated, 0.4),
            ],
        )];

        let result = cmd.print_junit_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_junit_summary_with_special_chars_in_claim() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        // Create result with special XML characters in the claim text
        let mut result_with_special_chars = create_test_validation_result(
            "PMAT can analyze <Rust> & 'TypeScript' code",
            ValidationStatus::Contradiction,
            0.2,
        );
        result_with_special_chars.evidence = Some(Evidence {
            source: "test".to_string(),
            similarity: 0.2,
            content: "Evidence with <special> & \"chars\"".to_string(),
        });

        let results = vec![(PathBuf::from("test.md"), vec![result_with_special_chars])];

        let result = cmd.print_junit_summary(&results);
        assert!(result.is_ok());
    }

    #[test]
    fn test_print_junit_summary_long_claim_text_truncation() {
        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Junit,
            failures_only: false,
            verbose: false,
        };

        // Create result with very long claim text (> 50 chars)
        let long_claim = "PMAT can analyze very complex Rust code with many features and capabilities that span multiple lines";
        let result = create_test_validation_result(long_claim, ValidationStatus::Verified, 0.95);

        let results = vec![(PathBuf::from("test.md"), vec![result])];

        let result = cmd.print_junit_summary(&results);
        assert!(result.is_ok());
    }

    // ============================================================================
    // Edge case tests
    // ============================================================================

    #[test]
    fn test_validation_result_without_evidence() {
        let result = ValidationResult {
            claim: Claim {
                source_file: PathBuf::from("test.md"),
                line_number: 1,
                text: "PMAT can analyze".to_string(),
                claim_type: ClaimType::Capability,
                entities: vec![],
                is_negative: false,
            },
            status: ValidationStatus::Inconclusive,
            evidence: None,
            error_message: Some("No evidence available".to_string()),
            confidence: 0.5,
        };

        let cmd = ValidateReadmeCmd {
            targets: vec![PathBuf::from("test.md")],
            deep_context: PathBuf::from("dc.md"),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let results = vec![(PathBuf::from("test.md"), vec![result])];

        // Test all output formats with no evidence
        cmd.print_text_summary(&results, 0, 0, 0);
        assert!(cmd.print_json_summary(&results).is_ok());
        assert!(cmd.print_junit_summary(&results).is_ok());
    }

    #[test]
    fn test_negative_claim_handling() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
        "#
        )
        .unwrap();

        // Negative claim (PMAT cannot compile)
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT cannot compile Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        // Negative claims about compile should be fine (it's correct that PMAT cannot compile)
    }

    #[test]
    fn test_supports_pattern() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Supported languages:
- Rust
- TypeScript
        "#
        )
        .unwrap();

        // Using "supports" pattern
        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT supports Rust and TypeScript analysis.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
    }

    #[test]
    fn test_empty_deep_context() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(deep_context_file, "# Empty context").unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
    }

    #[test]
    fn test_multiple_claims_mixed_results() {
        let mut deep_context_file = NamedTempFile::new().unwrap();
        writeln!(
            deep_context_file,
            r#"
Functions:
- analyze()
- parse()

Supported languages:
- Rust
- TypeScript
        "#
        )
        .unwrap();

        let mut readme_file = NamedTempFile::new().unwrap();
        writeln!(readme_file, "PMAT can analyze Rust code.").unwrap();
        writeln!(readme_file, "PMAT can compile TypeScript.").unwrap();
        writeln!(readme_file, "PMAT supports JavaScript analysis.").unwrap();

        let cmd = ValidateReadmeCmd {
            targets: vec![readme_file.path().to_path_buf()],
            deep_context: deep_context_file.path().to_path_buf(),
            verified_threshold: 0.9,
            contradiction_threshold: 0.3,
            fail_on_contradiction: true,
            fail_on_unverified: false,
            output: OutputFormat::Text,
            failures_only: false,
            verbose: false,
        };

        let result = cmd.execute();
        assert!(result.is_ok());
        // Should fail due to "compile" contradiction
        assert_eq!(result.unwrap(), ExitCode::FAILURE);
    }

    #[test]
    fn test_claim_type_debug_formatting() {
        let claim = Claim {
            source_file: PathBuf::from("test.md"),
            line_number: 1,
            text: "test".to_string(),
            claim_type: ClaimType::Capability,
            entities: vec![Entity::Language("Rust".to_string())],
            is_negative: false,
        };

        // Test debug formatting works
        let debug_output = format!("{:?}", claim.claim_type);
        assert_eq!(debug_output, "Capability");
    }

    #[test]
    fn test_validation_status_debug_formatting() {
        assert_eq!(format!("{:?}", ValidationStatus::Verified), "Verified");
        assert_eq!(
            format!("{:?}", ValidationStatus::Contradiction),
            "Contradiction"
        );
        assert_eq!(format!("{:?}", ValidationStatus::Unverified), "Unverified");
        assert_eq!(format!("{:?}", ValidationStatus::NotFound), "NotFound");
        assert_eq!(format!("{:?}", ValidationStatus::Outdated), "Outdated");
        assert_eq!(
            format!("{:?}", ValidationStatus::Inconclusive),
            "Inconclusive"
        );
    }

    #[test]
    fn test_entity_debug_formatting() {
        let entities = vec![
            Entity::Language("Rust".to_string()),
            Entity::Function("main".to_string()),
            Entity::File("test.rs".to_string()),
            Entity::Module("cli".to_string()),
            Entity::Capability("analyze".to_string()),
        ];

        for entity in &entities {
            // Just verify debug formatting doesn't panic
            let _ = format!("{:?}", entity);
        }
    }
}
