use crate::{
    invocation::{SkillContext, SkillInput},
    outcome::SkillOutcome,
    skill::{Skill, SkillId},
};
use prism::ingestion::scanner::DirectoryScanner;
use serde_json::json;
use std::collections::HashMap;

pub struct CartographSkill;

impl Skill for CartographSkill {
    fn id(&self) -> SkillId {
        SkillId("cartograph")
    }
    fn display_name(&self) -> &str {
        "Cartograph"
    }

    fn input_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "root": { "type": "string" },
                "depth": { "type": "integer", "default": 3 },
                "output_format": { "type": "string", "enum": ["tree", "json"], "default": "tree" }
            },
            "required": ["root"]
        })
    }

    fn output_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "map": { "type": "string" },
                "file_count": { "type": "integer" },
                "languages": { "type": "object" },
                "estimated_tokens": { "type": "integer" }
            }
        })
    }

    fn execute(&self, input: SkillInput, _ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let root = input.get_str("root").unwrap_or(".").to_string();
        let depth = input.get_u64("depth").unwrap_or(3) as usize;

        let mut scanner = DirectoryScanner::new();
        scanner.max_depth = depth;
        let files = scanner
            .scan(std::path::Path::new(&root))
            .unwrap_or_default();

        let mut lang_counts: HashMap<String, usize> = HashMap::new();
        for f in &files {
            let lang = prism::parse::Language::from_path(&f.to_string_lossy());
            *lang_counts.entry(lang.name().to_string()).or_insert(0) += 1;
        }

        let map = files
            .iter()
            .map(|f| f.to_string_lossy().to_string())
            .take(50)
            .collect::<Vec<_>>()
            .join("\n");
        let est_tokens = files.len() * 200; // rough estimate

        Ok(SkillOutcome::success(
            "cartograph",
            json!({
                "map": map,
                "file_count": files.len(),
                "languages": lang_counts,
                "estimated_tokens": est_tokens
            }),
        ))
    }
}
