//! Vendor authoritative corpus.
//!
//! Provides assertions from vendor documentation (PostgreSQL, Redis, AWS, etc.).
//! These are typically Tier 2 (Observational) because they are recommendations
//! rather than regulatory requirements.

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 vendor authoritative corpus.
pub struct VendorCorpusBuilder;

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

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

impl CorpusBuilder for VendorCorpusBuilder {
    fn name(&self) -> &str {
        "VendorDocs"
    }

    fn scheme(&self) -> &str {
        "vendor"
    }

    fn default_tier(&self) -> u8 {
        2 // Observational (Tier 2)
    }

    fn requires_network(&self) -> bool {
        false // Currently hardcoded, could fetch from online docs later
    }

    fn source_ids(&self) -> Vec<String> {
        vec![
            "vendor://postgresql".to_string(),
            "vendor://redis".to_string(),
            "vendor://aws".to_string(),
            "vendor://rust/reqwest".to_string(),
            "vendor://rust/hyper".to_string(),
            "vendor://go/net_http".to_string(),
            "vendor://unreal".to_string(),
        ]
    }

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

/// Build the vendor authoritative corpus.
#[allow(clippy::vec_init_then_push)]
fn build_vendor_corpus(signing_key: &SigningKey, timestamp: u64) -> Vec<Assertion> {
    let mut assertions = Vec::new();

    // PostgreSQL
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://postgresql/pool_size",
        "max_connections",
        ObjectValue::Number(100.0), // Default safe limit
        SourceClass::Observational,
        "PostgreSQL: max_connections default is 100",
        timestamp,
    ));

    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://postgresql/ssl_mode",
        "value",
        ObjectValue::Text("verify-full".to_string()),
        SourceClass::Expert, // Tier 3 - strong recommendation
        "PostgreSQL: sslmode should be 'verify-full' in production",
        timestamp,
    ));

    // Redis
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://redis/timeout",
        "value",
        ObjectValue::Number(5000.0), // 5s reasonable default
        SourceClass::Observational,
        "Redis: Connection timeout should be set (e.g. 5000ms)",
        timestamp,
    ));

    // Rust reqwest
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://rust/reqwest/connect_timeout",
        "enabled",
        ObjectValue::Boolean(true),
        SourceClass::Expert,
        "reqwest: Connect timeout should be set to prevent hangs",
        timestamp,
    ));

    // AWS
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://aws/s3/public_access",
        "enabled",
        ObjectValue::Boolean(false),
        SourceClass::Regulatory, // Tier 0 - nearly always a compliance violation
        "AWS S3: Block Public Access should be enabled by default",
        timestamp,
    ));

    // Unreal Engine - Security
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/security/exec_function",
        "exposed",
        ObjectValue::Boolean(false),
        SourceClass::Expert, // Tier 3 - Security best practice
        "Unreal Engine: Exec functions are callable by clients/console and should NOT contain sensitive logic or cheats in shipping builds.",
        timestamp,
    ));

    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/security/api_key",
        "storage_method",
        ObjectValue::Text("environment_or_vault".to_string()),
        SourceClass::Expert,
        "Unreal Engine: Never store API keys in Default*.ini files. Use runtime injection or secure storage.",
        timestamp,
    ));

    // Unreal Engine - Network
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/network/max_client_rate",
        "value",
        ObjectValue::Number(15000.0), // Default is often 15000-20000
        SourceClass::Observational,
        "Unreal Engine: MaxClientRate typically defaults to 15000. Higher values increase bandwidth usage.",
        timestamp,
    ));

    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/network/https_enforcement",
        "protocol",
        ObjectValue::Text("https".to_string()),
        SourceClass::Regulatory,
        "Unreal Engine: All API communication MUST use HTTPS to prevent data interception.",
        timestamp,
    ));

    // Unreal Engine - Performance
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/performance/sync_loading",
        "sync_load",
        ObjectValue::Boolean(false),
        SourceClass::Expert,
        "Unreal Engine: Synchronous loading blocks the game thread and causes hitches. Use AsyncLoad or SoftObjectPtr.",
        timestamp,
    ));

    // Unreal Engine - Assets
    assertions.push(create_authoritative_assertion(
        signing_key,
        "vendor://unreal/assets/hardcoded_path",
        "exposed",
        ObjectValue::Boolean(false),
        SourceClass::Expert,
        "Unreal Engine: Hardcoded asset paths (/Game/...) in C++ are fragile. Use SoftObjectPtr or UPROPERTY(Config) to reference assets.",
        timestamp,
    ));

    assertions
}

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

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

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

        assert!(!assertions.is_empty());
        assert!(assertions.iter().any(|a| a.subject.contains("postgresql")));
        assert!(assertions.iter().any(|a| a.subject.contains("unreal")));
    }
}
