//! Corpus builder for items created via `aphoria corpus create` CLI.
//!
//! These are user-authored corpus items stored in the shared corpus database
//! with metadata flag "source": "cli_create". This builder makes CLI-created
//! items visible in `aphoria corpus build` and `aphoria corpus list`.

use std::sync::Arc;

use ed25519_dalek::SigningKey;
use stemedb_core::types::Assertion;
use stemedb_storage::{HybridStore, KVStore};
use tracing::{info, instrument};

use crate::config::CorpusConfig;
use crate::AphoriaError;

/// Corpus builder for CLI-created items.
///
/// Items created with `aphoria corpus create` are stored in the corpus database
/// with metadata `"source": "cli_create"`. This builder:
/// 1. Queries the corpus store (passed in from registry)
/// 2. Scans all items with "subject:" prefix
/// 3. Filters for items with `source == "cli_create"` in metadata
/// 4. Returns them as corpus assertions
///
/// This makes CLI-created items visible in:
/// - `aphoria corpus build` (they get included in the build)
/// - Dashboard corpus queries (they appear in the corpus list)
pub struct CliCreatedBuilder {
    /// Reference to the corpus store for querying CLI-created items.
    corpus_store: Arc<HybridStore>,
}

impl CliCreatedBuilder {
    /// Create a new CLI-created corpus builder.
    ///
    /// # Arguments
    ///
    /// * `corpus_store` - The corpus database store (from LocalEpisteme::open_corpus_db)
    pub fn new(corpus_store: Arc<HybridStore>) -> Self {
        Self { corpus_store }
    }
}

#[async_trait::async_trait]
impl super::AsyncCorpusBuilder for CliCreatedBuilder {
    fn name(&self) -> &str {
        "CLI-Created Items"
    }

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

    fn default_tier(&self) -> u8 {
        3 // Community tier by default (individual items may override)
    }

    #[instrument(skip(self, _signing_key, _config), fields(builder = "CLI-Created"))]
    async fn build(
        &self,
        _signing_key: &SigningKey,
        _timestamp: u64,
        _config: &CorpusConfig,
    ) -> Result<Vec<Assertion>, AphoriaError> {
        info!("Building corpus from CLI-created items");

        // Scan all items with "subject:" prefix
        let all_items = self
            .corpus_store
            .scan_prefix(b"subject:")
            .await
            .map_err(|e| AphoriaError::Storage(format!("Failed to scan corpus database: {e}")))?;

        info!(total_items = all_items.len(), "Scanned corpus database for CLI-created items");

        // Filter for CLI-created items by checking metadata
        let mut assertions = Vec::new();
        for (_key, value) in all_items {
            let assertion: Assertion = stemedb_core::serde::deserialize(&value)
                .map_err(|e| AphoriaError::Storage(format!("Failed to deserialize assertion: {e}")))?;

            // Check metadata for "source": "cli_create"
            if let Some(ref meta_bytes) = assertion.source_metadata {
                if let Ok(meta_json) = serde_json::from_slice::<serde_json::Value>(meta_bytes) {
                    if meta_json.get("source").and_then(|v| v.as_str()) == Some("cli_create") {
                        assertions.push(assertion);
                    }
                }
            }
        }

        info!(
            cli_created_count = assertions.len(),
            "Found {} CLI-created corpus items",
            assertions.len()
        );

        Ok(assertions)
    }

    fn requires_network(&self) -> bool {
        false // CLI items are local only
    }

    fn source_ids(&self) -> Vec<String> {
        vec![] // No specific source IDs for CLI-created items
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::corpus::AsyncCorpusBuilder;
    use stemedb_storage::HybridStore;
    use tempfile::TempDir;

    #[test]
    fn test_builder_metadata() {
        let temp_dir = TempDir::new().unwrap();
        let store = Arc::new(HybridStore::open(temp_dir.path()).unwrap());
        let builder = CliCreatedBuilder::new(store);

        assert_eq!(builder.name(), "CLI-Created Items");
        assert_eq!(builder.scheme(), "cli");
        assert_eq!(builder.default_tier(), 3);
        assert!(!builder.requires_network());
        assert!(builder.source_ids().is_empty());
    }
}
