use crate::{
    invocation::{SkillContext, SkillInput},
    outcome::SkillOutcome,
    skill::{Skill, SkillId},
};
use serde_json::json;

/// Meridian: snapshot the current agent context — active files, recent signals, open Vault facts.
pub struct MeridianSkill;

impl Skill for MeridianSkill {
    fn id(&self) -> SkillId {
        SkillId("meridian")
    }
    fn display_name(&self) -> &str {
        "Meridian"
    }

    fn input_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "include_vault": { "type": "boolean", "default": true },
                "include_signals": { "type": "boolean", "default": true },
                "recent_n": { "type": "integer", "default": 10 }
            }
        })
    }

    fn output_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "cwd": { "type": "string" },
                "recent_executions": { "type": "array" },
                "vault_fact_count": { "type": "integer" },
                "timestamp": { "type": "string" }
            }
        })
    }

    fn execute(&self, input: SkillInput, _ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let recent_n = input.get_u64("recent_n").unwrap_or(10) as usize;
        let include_signals = input.get_bool("include_signals").unwrap_or(true);

        let cwd = std::env::current_dir()
            .map(|p| p.to_string_lossy().to_string())
            .unwrap_or_default();

        let recent_executions: Vec<serde_json::Value> = if include_signals {
            read_recent_executions(recent_n)
        } else {
            vec![]
        };

        let vault_fact_count = count_vault_facts();
        let timestamp = chrono::Utc::now().to_rfc3339();

        Ok(SkillOutcome::success(
            "meridian",
            json!({
                "cwd": cwd,
                "recent_executions": recent_executions,
                "vault_fact_count": vault_fact_count,
                "timestamp": timestamp
            }),
        ))
    }
}

fn bctx_dir() -> std::path::PathBuf {
    std::env::var("HOME")
        .map(std::path::PathBuf::from)
        .unwrap_or_default()
        .join(".bctx")
}

fn read_recent_executions(n: usize) -> Vec<serde_json::Value> {
    let db_path = bctx_dir().join("executions.db");
    let Ok(conn) = rusqlite::Connection::open(&db_path) else {
        return vec![];
    };

    let Ok(mut stmt) = conn.prepare(
        "SELECT program, tokens_before, tokens_after, timestamp \
         FROM executions ORDER BY timestamp DESC LIMIT ?1",
    ) else {
        return vec![];
    };

    let Ok(rows) = stmt.query_map([n as i64], |row| {
        Ok(json!({
            "program": row.get::<_, String>(0)?,
            "tokens_before": row.get::<_, i64>(1)?,
            "tokens_after": row.get::<_, i64>(2)?,
            "recorded_at": row.get::<_, String>(3)?
        }))
    }) else {
        return vec![];
    };
    rows.filter_map(|r| r.ok()).collect()
}

fn count_vault_facts() -> i64 {
    let vault_dir = bctx_dir().join("vault");
    let mut count = 0i64;
    for name in &["crystallized.json", "resonant.json"] {
        let path = vault_dir.join(name);
        let Ok(data) = std::fs::read_to_string(&path) else {
            continue;
        };
        if let Ok(arr) = serde_json::from_str::<serde_json::Value>(&data) {
            count += arr.as_array().map(|a| a.len() as i64).unwrap_or(0);
        }
    }
    count
}
