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

/// RelayCtx: package and hand off agent context to another agent session via EnvelopeBroker.
pub struct RelayCtxSkill;

impl Skill for RelayCtxSkill {
    fn id(&self) -> SkillId {
        SkillId("relay_ctx")
    }
    fn display_name(&self) -> &str {
        "RelayCtx"
    }

    fn input_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "context_summary": { "type": "string", "description": "Summary of current context to hand off" },
                "target_agent": { "type": "string", "description": "Target agent ID or session name" },
                "files": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Key file paths to include in the handoff"
                },
                "task": { "type": "string", "description": "Task description for the receiving agent" },
                "compress": { "type": "boolean", "default": true, "description": "Compress the bundle before relay" }
            },
            "required": ["context_summary", "target_agent"]
        })
    }

    fn output_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "envelope_id": { "type": "string" },
                "delivered": { "type": "boolean" },
                "tokens": { "type": "integer" },
                "bundle_path": { "type": "string" }
            }
        })
    }

    fn execute(&self, input: SkillInput, _ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let summary = input.get_str("context_summary").unwrap_or("").to_string();
        let target = input.get_str("target_agent").unwrap_or("").to_string();
        let files = input.get_str_array("files").unwrap_or_default();
        let task = input.get_str("task").unwrap_or("").to_string();
        let compress = input.get_bool("compress").unwrap_or(true);

        // Build the envelope payload
        let mut file_contents = Vec::new();
        for f in &files {
            if let Ok(c) = std::fs::read_to_string(f) {
                let content = if compress {
                    use weave::lenses::{
                        clarity::ClarityLens, narrow::NarrowLens, Lens, LensContext,
                    };
                    let ctx = LensContext::new(1000);
                    let c2 = ClarityLens.apply(&c, &ctx);
                    NarrowLens.apply(&c2.content, &ctx).content
                } else {
                    c
                };
                file_contents.push(json!({ "path": f, "content": content }));
            }
        }

        let envelope = json!({
            "target_agent": target,
            "task": task,
            "context_summary": summary,
            "files": file_contents,
            "timestamp": chrono::Utc::now().to_rfc3339()
        });

        let envelope_str = serde_json::to_string_pretty(&envelope)?;
        let tokens = TokenEstimator::count(&envelope_str);

        // Write to local relay directory
        let envelope_id = format!(
            "{:x}",
            std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap_or_default()
                .as_millis()
        );

        let relay_dir = std::env::var("HOME")
            .map(|h| std::path::PathBuf::from(h).join(".bctx").join("relay"))
            .unwrap_or_else(|_| std::path::PathBuf::from("/tmp/bctx-relay"));
        let _ = std::fs::create_dir_all(&relay_dir);
        let bundle_path = relay_dir.join(format!("{envelope_id}.json"));
        let delivered = std::fs::write(&bundle_path, &envelope_str).is_ok();

        Ok(SkillOutcome::success(
            "relay_ctx",
            json!({
                "envelope_id": envelope_id,
                "delivered": delivered,
                "tokens": tokens,
                "bundle_path": bundle_path.to_string_lossy()
            }),
        )
        .with_tokens(tokens))
    }
}
