use crate::{
    invocation::{SkillContext, SkillInput},
    outcome::SkillOutcome,
    skill::{Skill, SkillId},
};
use prism::{
    extract,
    graph::{builder::build_from_symbols, export::to_dot},
    ingestion::scanner::DirectoryScanner,
    parse::ParsedUnit,
};
use serde_json::json;

pub struct SurveyorSkill;

impl Skill for SurveyorSkill {
    fn id(&self) -> SkillId {
        SkillId("surveyor")
    }
    fn display_name(&self) -> &str {
        "Surveyor"
    }

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

    fn output_schema(&self) -> serde_json::Value {
        json!({ "type": "object", "properties": { "graph": { "type": "string" }, "node_count": { "type": "integer" }, "edge_count": { "type": "integer" } } })
    }

    fn execute(&self, input: SkillInput, _ctx: &SkillContext) -> anyhow::Result<SkillOutcome> {
        let root = input.get_str("root").unwrap_or(".");
        let fmt = input.get_str("output_format").unwrap_or("dot");

        let scanner = DirectoryScanner::new();
        let files = scanner.scan(std::path::Path::new(root)).unwrap_or_default();
        let files = &files[..50.min(files.len())];

        let maps: Vec<_> = files
            .iter()
            .map(|path| {
                let content = std::fs::read_to_string(path).unwrap_or_default();
                let unit = ParsedUnit::new(path.to_string_lossy().to_string(), content);
                extract::extract(&unit)
            })
            .collect();

        let graph = build_from_symbols(&maps);
        let output = match fmt {
            "dot" => to_dot(&graph),
            _ => format!(
                "nodes: {}, edges: {}",
                graph.node_count(),
                graph.edge_count()
            ),
        };

        Ok(SkillOutcome::success(
            "surveyor",
            json!({ "graph": output, "node_count": graph.node_count(), "edge_count": graph.edge_count() }),
        ))
    }
}
