use crate::{
    invocation::{SkillContext, SkillInput},
    outcome::SkillOutcome,
    skill::{Skill, SkillId},
    vault_store,
};
use serde_json::json;
use vault::fact::{MemoFact, MemoryTier};

pub struct SedimentSkill;

impl Skill for SedimentSkill {
    fn id(&self) -> SkillId {
        SkillId("sediment")
    }
    fn display_name(&self) -> &str {
        "Sediment"
    }

    fn input_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "facts": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "category":   { "type": "string" },
                            "key":        { "type": "string" },
                            "value":      { "type": "string" },
                            "confidence": { "type": "number", "default": 0.8 },
                            "tags":       { "type": "array", "items": { "type": "string" } }
                        },
                        "required": ["key", "value"]
                    }
                },
                "target_tier": {
                    "type": "string",
                    "enum": ["immediate", "resonant", "crystallized"],
                    "default": "resonant"
                }
            },
            "required": ["facts"]
        })
    }

    fn output_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "stored":     { "type": "integer" },
                "merged":     { "type": "integer" },
                "conflicted": { "type": "array" }
            }
        })
    }

    fn execute(&self, input: SkillInput, ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let tier = match input.get_str("target_tier").unwrap_or("resonant") {
            "immediate" => MemoryTier::Immediate,
            "crystallized" => MemoryTier::Crystallized,
            _ => MemoryTier::Resonant,
        };

        let facts_arr = input
            .params
            .get("facts")
            .and_then(|v| v.as_array())
            .cloned()
            .unwrap_or_default();

        let mut stored = 0usize;
        let mut vault = vault_store::vault().lock().unwrap();

        for item in &facts_arr {
            let key = item
                .get("key")
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();
            let value = item
                .get("value")
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();
            let category = item
                .get("category")
                .and_then(|v| v.as_str())
                .unwrap_or("general")
                .to_string();
            let confidence = item
                .get("confidence")
                .and_then(|v| v.as_f64())
                .unwrap_or(0.8) as f32;

            if key.is_empty() || value.is_empty() {
                continue;
            }

            let mut fact = MemoFact::new(tier.clone(), category, key, value, confidence);
            fact.source_session = Some(ctx.session_id.clone());

            if let Some(tags) = item.get("tags").and_then(|v| v.as_array()) {
                fact.tags = tags
                    .iter()
                    .filter_map(|t| t.as_str())
                    .map(|s| s.to_string())
                    .collect();
            }

            vault.insert(fact);
            stored += 1;
        }

        Ok(SkillOutcome::success(
            "sediment",
            json!({
                "stored":     stored,
                "merged":     0,
                "conflicted": []
            }),
        ))
    }
}
