//! Wiki corpus builder
//!
//! Converts WikiPatterns into signed authoritative assertions for the corpus database.
//! Reuses existing helpers from episteme/corpus.rs to handle signing and metadata.

use crate::corpus::authority_parser::{parse_authority, Authority};
use crate::corpus::subject_builder::build_corpus_subject;
use crate::corpus::wiki_importer::WikiPattern;
use crate::episteme::create_authoritative_assertion_with_metadata;
use crate::error::AphoriaError;
use ed25519_dalek::SigningKey;
use serde_json::json;
use stemedb_core::types::SourceClass;
use stemedb_storage::{HybridStore, KVStore};
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use tracing::{info, warn};

/// Promote wiki patterns to corpus database as signed assertions
///
/// This function:
/// 1. Parses authority strings into structured Authority enums
/// 2. Builds proper subject URIs (rfc://, owasp://, cwe://, community://wiki/)
/// 3. Creates signed assertions with rich metadata
/// 4. Stores in corpus database with subject and predicate indexes
///
/// # Arguments
///
/// * `patterns` - WikiPatterns parsed from markdown files
/// * `signing_key` - Ed25519 key for signing assertions
/// * `corpus_store` - Corpus database KV store (NOT project database)
///
/// # Returns
///
/// Number of patterns successfully promoted to corpus
pub async fn promote_wiki_patterns_to_corpus(
    patterns: Vec<WikiPattern>,
    signing_key: &SigningKey,
    corpus_store: Arc<HybridStore>,
) -> Result<usize, AphoriaError> {
    let mut promoted = 0;

    for pattern in patterns {
        // Parse authority (or Unknown if missing)
        let authority = pattern
            .authority
            .as_ref()
            .map(|s| parse_authority(s))
            .unwrap_or_else(|| Authority::Unknown("wiki import".to_string()));

        // Build proper subject URI
        let subject = build_corpus_subject(&pattern, &authority);

        // Determine tier based on authority
        let source_class = match &authority {
            Authority::RFC { .. } | Authority::OWASP { .. } => SourceClass::Regulatory,
            Authority::CWE { .. } => SourceClass::Clinical,
            Authority::Unknown(_) => SourceClass::Community,
        };

        // Get authority source string for metadata
        let authority_source = pattern
            .authority
            .clone()
            .unwrap_or_else(|| "wiki import".to_string());

        // Build rich metadata
        let metadata = json!({
            "description": pattern.statement,
            "authority_source": authority_source,
            "category": infer_category(&pattern.subject),
            "source": "wiki_import"
        });

        // Get current timestamp
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .map_err(|e| AphoriaError::Io(std::io::Error::other(e)))?
            .as_secs();

        // Create signed assertion (REUSE EXISTING HELPER)
        let assertion = create_authoritative_assertion_with_metadata(
            signing_key,
            &subject,
            &pattern.predicate,
            pattern.value.clone().into(),
            source_class,
            &pattern.statement,
            timestamp,
            metadata,
        );

        // Serialize assertion
        let serialized = stemedb_core::serde::serialize(&assertion)
            .map_err(|e| AphoriaError::Storage(format!("Failed to serialize assertion: {}", e)))?;

        // Store with subject prefix for API querying
        let subject_key = format!("subject:{}", subject);
        corpus_store
            .put(subject_key.as_bytes(), &serialized)
            .await
            .map_err(|e| AphoriaError::Storage(format!("Failed to store assertion: {}", e)))?;

        // Also store in predicate index
        let pred_key = format!("predicate:corpus:{}", assertion.predicate);
        corpus_store
            .put(pred_key.as_bytes(), &serialized)
            .await
            .map_err(|e| {
                AphoriaError::Storage(format!("Failed to store predicate index: {}", e))
            })?;

        info!(
            "Promoted wiki pattern to corpus: {} -> {}",
            pattern.subject, subject
        );
        promoted += 1;
    }

    if promoted > 0 {
        info!("Successfully promoted {} wiki patterns to corpus", promoted);
    } else {
        warn!("No wiki patterns were promoted to corpus");
    }

    Ok(promoted)
}

/// Infer category from subject path
///
/// Uses simple keyword matching to categorize patterns into:
/// - security: TLS, JWT, password, auth, crypto
/// - architecture: HTTP, API, REST
/// - quality: test, CI
/// - general: everything else
fn infer_category(subject: &str) -> &str {
    let lower = subject.to_lowercase();
    if lower.contains("tls")
        || lower.contains("jwt")
        || lower.contains("password")
        || lower.contains("auth")
        || lower.contains("crypto")
    {
        "security"
    } else if lower.contains("http") || lower.contains("api") || lower.contains("rest") {
        "architecture"
    } else if lower.contains("test") || lower.contains("ci") {
        "quality"
    } else {
        "general"
    }
}

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

    #[test]
    fn test_infer_category_security() {
        assert_eq!(infer_category("tls/cert_verification"), "security");
        assert_eq!(infer_category("JWT/validation"), "security");
        assert_eq!(infer_category("password/storage"), "security");
        assert_eq!(infer_category("authentication/oauth"), "security");
        assert_eq!(infer_category("crypto/hashing"), "security");
    }

    #[test]
    fn test_infer_category_architecture() {
        assert_eq!(infer_category("http/headers"), "architecture");
        assert_eq!(infer_category("API/versioning"), "architecture");
        assert_eq!(infer_category("rest/endpoints"), "architecture");
    }

    #[test]
    fn test_infer_category_quality() {
        assert_eq!(infer_category("test/coverage"), "quality");
        assert_eq!(infer_category("CI/pipeline"), "quality");
    }

    #[test]
    fn test_infer_category_general() {
        assert_eq!(infer_category("logging/format"), "general");
        assert_eq!(infer_category("config/defaults"), "general");
    }
}
