use std::path::Path;
use std::path::PathBuf;
use bevy_brp_mcp_macros::ParamStruct;
use bevy_brp_mcp_macros::ResultStruct;
use bevy_brp_mcp_macros::ToolFn;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
use super::constants::MANIFEST_PATH_FIELD;
use super::targets;
use crate::error::Result;
use crate::tool::HandlerContext;
use crate::tool::HandlerResult;
use crate::tool::ToolFn;
use crate::tool::ToolResult;
#[derive(Clone, Deserialize, Serialize, JsonSchema, ParamStruct)]
pub struct ListBevyParams {
#[serde(default)]
#[to_metadata(skip_if_none)]
pub path: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ResultStruct)]
pub struct ListBevyResult {
#[to_metadata]
count: usize,
#[to_result]
targets: Vec<Value>,
#[to_message(message_template = "Found {count} Bevy targets")]
message_template: String,
}
#[derive(ToolFn)]
#[tool_fn(params = "ListBevyParams", output = "ListBevyResult")]
pub struct ListBevy;
#[allow(
clippy::unused_async,
reason = "ToolFn trait requires async handler signature"
)]
async fn handle_impl(params: ListBevyParams) -> Result<ListBevyResult> {
let search_paths = targets::resolve_search_paths(params.path.as_deref())?;
let mut items = targets::collect_all_bevy_targets(&search_paths);
if let Some(ref path) = params.path {
let scope = std::fs::canonicalize(path).unwrap_or_else(|_| PathBuf::from(path));
items.retain(|item| {
item.get(MANIFEST_PATH_FIELD)
.and_then(serde_json::Value::as_str)
.is_some_and(|mp| {
let manifest_dir = Path::new(mp).parent().unwrap_or_else(|| Path::new(mp));
let canonical = std::fs::canonicalize(manifest_dir)
.unwrap_or_else(|_| manifest_dir.to_path_buf());
canonical.starts_with(&scope)
})
});
}
Ok(ListBevyResult::new(items.len(), items))
}