//! Hardcoded authoritative corpus for common security patterns.
//!
//! This builder provides the built-in assertions that Aphoria ships with,
//! covering essential security requirements from RFCs and OWASP guidance.
//! These assertions are always available and don't require network access.

use ed25519_dalek::SigningKey;
use stemedb_core::types::{Assertion, ObjectValue, SourceClass};
use tracing::instrument;

use super::CorpusBuilder;
use crate::config::CorpusConfig;
use crate::episteme::create_authoritative_assertion;
use crate::AphoriaError;

/// Builder for the hardcoded authoritative corpus.
///
/// Contains 19+ built-in assertions covering:
/// - TLS certificate verification (RFC 5246)
/// - TLS version requirements (RFC 8996)
/// - JWT validation (RFC 7519)
/// - Secrets management (OWASP)
/// - CORS security (OWASP)
/// - Rate limiting (OWASP)
/// - Cryptographic failures (OWASP)
/// - Injection prevention (OWASP)
pub struct HardcodedCorpusBuilder;

impl HardcodedCorpusBuilder {
    /// Create a new hardcoded corpus builder.
    pub fn new() -> Self {
        Self
    }
}

impl Default for HardcodedCorpusBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl CorpusBuilder for HardcodedCorpusBuilder {
    fn name(&self) -> &str {
        "Hardcoded"
    }

    fn scheme(&self) -> &str {
        "rfc,owasp"
    }

    fn default_tier(&self) -> u8 {
        0 // Mix of Tier 0 (Regulatory) and Tier 1 (Clinical)
    }

    fn requires_network(&self) -> bool {
        false
    }

    fn source_ids(&self) -> Vec<String> {
        vec![
            "rfc://5246".to_string(),
            "rfc://7519".to_string(),
            "rfc://8996".to_string(),
            "owasp://transport_layer".to_string(),
            "owasp://secrets".to_string(),
            "owasp://cors".to_string(),
            "owasp://rate_limit".to_string(),
            "owasp://crypto".to_string(),
            "owasp://injection".to_string(),
        ]
    }

    #[instrument(skip(self, signing_key, _config), fields(builder = "Hardcoded"))]
    fn build(
        &self,
        signing_key: &SigningKey,
        timestamp: u64,
        _config: &CorpusConfig,
    ) -> Result<Vec<Assertion>, AphoriaError> {
        Ok(build_hardcoded_corpus(signing_key, timestamp))
    }
}

/// Build the hardcoded authoritative corpus.
///
/// This is the same corpus that was previously in `create_authoritative_corpus()`,
/// now encapsulated in a CorpusBuilder for consistency.
#[allow(clippy::vec_init_then_push)]
fn build_hardcoded_corpus(signing_key: &SigningKey, timestamp: u64) -> Vec<Assertion> {
    let mut assertions = Vec::new();

    // TLS verification requirements
    assertions.push(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,
    ));

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

    // TLS minimum version (RFC 8996)
    // RFC 8996 deprecates TLS 1.0 and 1.1 - minimum should be TLS 1.2
    assertions.push(create_authoritative_assertion(
        signing_key,
        "rfc://8996/tls/min_version",
        "version",
        ObjectValue::Text("1.2".to_string()),
        SourceClass::Regulatory, // Tier 0 - this is now a regulatory requirement
        "RFC 8996: TLS 1.0 and 1.1 are deprecated; minimum version MUST be TLS 1.2",
        timestamp,
    ));

    // JWT audience validation (RFC 7519)
    assertions.push(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,
    ));

    // JWT expiry validation
    assertions.push(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,
    ));

    // JWT signature verification
    assertions.push(create_authoritative_assertion(
        signing_key,
        "rfc://7519/jwt/signature_verification",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Regulatory,
        "JWT signatures MUST be verified (RFC 7519)",
        timestamp,
    ));

    // JWT algorithm restriction
    assertions.push(create_authoritative_assertion(
        signing_key,
        "rfc://7519/jwt/algorithm_restriction",
        "config_value",
        ObjectValue::Text("explicit_list".to_string()),
        SourceClass::Regulatory,
        "JWT algorithm MUST be explicitly specified, 'none' algorithm forbidden",
        timestamp,
    ));

    // OWASP secrets management
    assertions.push(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.push(create_authoritative_assertion(
        signing_key,
        "owasp://secrets/password",
        "storage_method",
        ObjectValue::Text("environment_or_vault".to_string()),
        SourceClass::Clinical,
        "OWASP: Never hardcode passwords in source code",
        timestamp,
    ));

    // CORS security
    assertions.push(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,
    ));

    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://cors/credentials_with_wildcard",
        "enabled",
        ObjectValue::Boolean(false),
        SourceClass::Regulatory,
        "CORS credentials MUST NOT be allowed with wildcard origin (security vulnerability)",
        timestamp,
    ));

    // Rate limiting
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://rate_limit/enabled",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Clinical,
        "OWASP: Rate limiting SHOULD be enabled for API endpoints",
        timestamp,
    ));

    // ============================================
    // Weak Cryptography (Phase 2 - Week 2)
    // ============================================

    // MD5 is cryptographically broken - OWASP Cryptographic Failures
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://crypto/hashing/algorithm",
        "algorithm",
        ObjectValue::Text("secure".to_string()), // Expected: sha256, sha3, blake3, etc.
        SourceClass::Clinical,
        "OWASP: MD5 is cryptographically broken and MUST NOT be used for security purposes",
        timestamp,
    ));

    // SHA1 is deprecated for cryptographic use
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://crypto/hashing/sha1_prohibited",
        "prohibited",
        ObjectValue::Boolean(true),
        SourceClass::Clinical,
        "OWASP: SHA-1 is deprecated and SHOULD NOT be used for cryptographic purposes",
        timestamp,
    ));

    // Weak symmetric ciphers (DES, RC4, Blowfish with small keys)
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://crypto/symmetric/algorithm",
        "algorithm",
        ObjectValue::Text("aes_256_gcm".to_string()), // Modern authenticated encryption
        SourceClass::Clinical,
        "OWASP: DES, RC4, and other weak ciphers MUST NOT be used",
        timestamp,
    ));

    // ============================================
    // SQL Injection Prevention (Phase 2 - Week 2)
    // ============================================

    // SQL queries MUST use parameterized queries
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://injection/db/query/construction",
        "construction",
        ObjectValue::Text("parameterized".to_string()),
        SourceClass::Regulatory, // Tier 0 - this is critical
        "OWASP A03:2021 Injection: SQL queries MUST use parameterized statements, never string concatenation",
        timestamp,
    ));

    // String interpolation in SQL is a vulnerability
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://injection/sql/interpolation",
        "prohibited",
        ObjectValue::Boolean(true),
        SourceClass::Regulatory,
        "OWASP: String interpolation in SQL queries leads to SQL injection vulnerabilities",
        timestamp,
    ));

    // ============================================
    // Command Injection Prevention (Phase 2 - Week 2)
    // ============================================

    // Command inputs MUST be sanitized
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://injection/os/command/input",
        "input_source",
        ObjectValue::Text("sanitized".to_string()),
        SourceClass::Regulatory, // Tier 0 - critical vulnerability
        "OWASP A03:2021 Injection: OS command inputs MUST be sanitized; never pass untrusted data to shell",
        timestamp,
    ));

    // Shell=True in subprocess is dangerous
    assertions.push(create_authoritative_assertion(
        signing_key,
        "owasp://injection/os/shell_mode",
        "enabled",
        ObjectValue::Boolean(false),
        SourceClass::Clinical,
        "OWASP: Avoid shell=True or equivalent; use direct command execution with argument arrays",
        timestamp,
    ));

    assertions
}

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

    #[test]
    fn test_hardcoded_builder_builds() {
        let builder = HardcodedCorpusBuilder::new();
        let key = generate_signing_key();
        let config = CorpusConfig::default();

        let assertions = builder.build(&key, 1706832000, &config).expect("build");

        // 11 original + 1 RFC 8996 TLS version + 3 crypto + 2 SQL injection + 2 command injection = 19
        assert_eq!(assertions.len(), 19);
    }

    #[test]
    fn test_hardcoded_builder_no_network() {
        let builder = HardcodedCorpusBuilder::new();
        assert!(!builder.requires_network());
    }

    #[test]
    fn test_hardcoded_assertions_content() {
        let key = generate_signing_key();
        let assertions = build_hardcoded_corpus(&key, 1706832000);

        // Check TLS assertion
        let tls_assertion = assertions.iter().find(|a| a.subject.contains("tls/cert_verification"));
        assert!(tls_assertion.is_some());
        let tls = tls_assertion.expect("tls assertion");
        assert_eq!(tls.predicate, "enabled");
        assert_eq!(tls.object, ObjectValue::Boolean(true));

        // Check JWT assertion
        let jwt_assertion =
            assertions.iter().find(|a| a.subject.contains("jwt/audience_validation"));
        assert!(jwt_assertion.is_some());
        let jwt = jwt_assertion.expect("jwt assertion");
        assert_eq!(jwt.predicate, "enabled");
        assert_eq!(jwt.source_class, SourceClass::Regulatory);
    }

    #[test]
    fn test_hardcoded_source_ids() {
        let builder = HardcodedCorpusBuilder::new();
        let ids = builder.source_ids();

        assert!(ids.iter().any(|id| id.contains("rfc://5246")));
        assert!(ids.iter().any(|id| id.contains("rfc://7519")));
        assert!(ids.iter().any(|id| id.contains("owasp://")));
    }
}
