//! Claim extraction types.

use stemedb_core::types::{ObjectValue, SourceClass};

/// A claim extracted from source code.
#[derive(Debug, Clone)]
pub struct ExtractedClaim {
    /// The full ConceptPath for this claim.
    pub concept_path: String,

    /// The predicate describing what aspect this claims.
    pub predicate: String,

    /// The extracted value.
    pub value: ObjectValue,

    /// Source file path relative to project root.
    pub file: String,

    /// Line number in the source file (1-indexed).
    pub line: usize,

    /// The matched source text.
    pub matched_text: String,

    /// Confidence of extraction (0.0 to 1.0).
    pub confidence: f32,

    /// Human-readable description.
    pub description: String,
}

/// A source that conflicts with the code claim.
#[derive(Debug, Clone)]
pub struct ConflictingSource {
    /// The concept path of the authoritative source.
    pub path: String,

    /// The source class (tier).
    pub source_class: SourceClass,

    /// The authoritative value.
    pub value: ObjectValue,

    /// Confidence of the authoritative assertion.
    pub confidence: f32,

    /// RFC/OWASP citation extracted from the source path.
    /// e.g., "RFC 5246", "RFC 7519", "RFC 8996", "OWASP A03:2021"
    pub rfc_citation: Option<String>,

    /// Information about the policy source (Trust Pack) if this came from an imported policy.
    pub policy_source: Option<PolicySourceInfo>,
}

/// Information about a Trust Pack that provided a policy assertion.
///
/// Used to show provenance in conflict reports, e.g.:
/// "Source: Acme Security Standard v0.1.0 (Platform Security Team)"
#[derive(Debug, Clone)]
pub struct PolicySourceInfo {
    /// Name of the Trust Pack (e.g., "Acme Security Standard").
    pub pack_name: String,

    /// Version of the Trust Pack (e.g., "0.1.0").
    pub pack_version: String,

    /// First 8 hex characters of the issuer's public key.
    pub issuer_hex: String,

    /// Human-readable name of the signer (e.g., "Platform Security Team").
    /// Falls back to issuer_hex for display if None.
    pub signer_name: Option<String>,

    /// Contact info for the signer (e.g., "#security-policy", "security@acme.com").
    pub contact: Option<String>,
}

impl ConflictingSource {
    /// Extract an RFC/OWASP citation from a source path.
    ///
    /// # Examples
    /// - `rfc://5246/tls/cert_verification` → `Some("RFC 5246")`
    /// - `rfc://7519/jwt/audience_validation` → `Some("RFC 7519")`
    /// - `rfc://8996/tls/min_version` → `Some("RFC 8996")`
    /// - `owasp://cors/allow_origin` → `Some("OWASP")`
    /// - `owasp://injection/sql` → `Some("OWASP A03:2021")`
    /// - `vendor://aws/config` → `None`
    pub fn extract_citation(path: &str) -> Option<String> {
        if path.starts_with("rfc://") {
            // Extract RFC number: rfc://5246/... → RFC 5246
            let after_scheme = path.strip_prefix("rfc://")?;
            let rfc_num = after_scheme.split('/').next()?;
            Some(format!("RFC {}", rfc_num))
        } else if path.starts_with("owasp://") {
            // OWASP paths - check for specific categories
            let after_scheme = path.strip_prefix("owasp://")?;
            let category = after_scheme.split('/').next().unwrap_or("");

            match category {
                "injection" => Some("OWASP A03:2021".to_string()),
                "crypto" => Some("OWASP A02:2021".to_string()),
                "secrets" => Some("OWASP A07:2021".to_string()),
                "cors" | "transport_layer" => Some("OWASP A05:2021".to_string()),
                "rate_limit" => Some("OWASP".to_string()),
                _ => Some("OWASP".to_string()),
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_extract_citation_rfc() {
        assert_eq!(
            ConflictingSource::extract_citation("rfc://5246/tls/cert_verification"),
            Some("RFC 5246".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("rfc://7519/jwt/audience_validation"),
            Some("RFC 7519".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("rfc://8996/tls/min_version"),
            Some("RFC 8996".to_string())
        );
    }

    #[test]
    fn test_extract_citation_owasp() {
        assert_eq!(
            ConflictingSource::extract_citation("owasp://injection/sql"),
            Some("OWASP A03:2021".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("owasp://crypto/hashing"),
            Some("OWASP A02:2021".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("owasp://secrets/api_key"),
            Some("OWASP A07:2021".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("owasp://cors/allow_origin"),
            Some("OWASP A05:2021".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("owasp://transport_layer/tls"),
            Some("OWASP A05:2021".to_string())
        );
        assert_eq!(
            ConflictingSource::extract_citation("owasp://rate_limit/enabled"),
            Some("OWASP".to_string())
        );
    }

    #[test]
    fn test_extract_citation_other() {
        assert_eq!(ConflictingSource::extract_citation("vendor://aws/config"), None);
        assert_eq!(ConflictingSource::extract_citation("code://rust/myapp/tls"), None);
    }
}
