//! Git tag tools.

use super::ctx::GitToolCtx;
use agent::{ToolDefinition, ToolHandler, ToolParam, ToolRegistry, ToolSchema};
use std::collections::HashMap;

async fn git_tag_list_exec(ctx: GitToolCtx, args: serde_json::Value) -> Result<serde_json::Value, String> {
    let p: serde_json::Map<String, serde_json::Value> = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let project_name = p.get("project_name").and_then(|v| v.as_str()).ok_or("missing project_name")?;
    let repo_name = p.get("repo_name").and_then(|v| v.as_str()).ok_or("missing repo_name")?;
    let pattern = p.get("pattern").and_then(|v| v.as_str()).map(|s| s.to_string());

    let domain = ctx.open_repo(project_name, repo_name).await?;
    let all_tags = domain.tag_list().map_err(|e| e.to_string())?;

    let result: Vec<_> = match pattern {
        Some(ref pat) => {
            let pat_lower = pat.to_lowercase();
            // Convert glob pattern (only * wildcards) to regex for proper matching.
            // "*" matches any sequence of characters.
            let regex_pat = pat_lower
                .split('*')
                .map(|s| regex::escape(s))
                .collect::<Vec<_>>()
                .join(".*");
            let re = regex::Regex::new(&format!("^{}$", regex_pat))
                .ok();
            all_tags.iter()
                .filter(|t| {
                    let n = t.name.to_lowercase();
                    re.as_ref().map(|r| r.is_match(&n)).unwrap_or(false)
                })
                .map(|t| tag_to_json(t))
                .collect()
        }
        None => all_tags.into_iter().map(|t| tag_to_json(&t)).collect(),
    };

    Ok(serde_json::to_value(result).map_err(|e| e.to_string())?)
}

fn tag_to_json(t: &git::tags::types::TagInfo) -> serde_json::Value {
    serde_json::json!({
        "name": t.name,
        "oid": t.oid.to_string(),
        "target": t.target.to_string(),
        "is_annotated": t.is_annotated,
        "message": t.message.clone(),
        "tagger_name": t.tagger.clone(),
        "tagger_email": t.tagger_email.clone()
    })
}

async fn git_tag_info_exec(ctx: GitToolCtx, args: serde_json::Value) -> Result<serde_json::Value, String> {
    let p: serde_json::Map<String, serde_json::Value> = serde_json::from_value(args).map_err(|e| e.to_string())?;
    let project_name = p.get("project_name").and_then(|v| v.as_str()).ok_or("missing project_name")?;
    let repo_name = p.get("repo_name").and_then(|v| v.as_str()).ok_or("missing repo_name")?;
    let name = p.get("name").and_then(|v| v.as_str()).ok_or("missing name")?;

    let domain = ctx.open_repo(project_name, repo_name).await?;
    let info = domain.tag_get(name).map_err(|e| e.to_string())?;

    Ok(tag_to_json(&info))
}

pub fn register_git_tools(registry: &mut ToolRegistry) {
    // git_tag_list
    let p = HashMap::from([
        ("project_name".into(), ToolParam { name: "project_name".into(), param_type: "string".into(), description: Some("Project name (slug)".into()), required: true, properties: None, items: None }),
        ("repo_name".into(), ToolParam { name: "repo_name".into(), param_type: "string".into(), description: Some("Repository name".into()), required: true, properties: None, items: None }),
        ("pattern".into(), ToolParam { name: "pattern".into(), param_type: "string".into(), description: Some("Filter tags by name pattern (supports * wildcard)".into()), required: false, properties: None, items: None }),
    ]);
    let schema = ToolSchema { schema_type: "object".into(), properties: Some(p), required: Some(vec!["project_name".into(), "repo_name".into()]) };
    registry.register(
        ToolDefinition::new("git_tag_list").description("List all tags in a repository, optionally filtered by a name pattern.").parameters(schema),
        ToolHandler::new(|ctx, args| {
            let gctx = super::ctx::GitToolCtx::new(ctx);
            Box::pin(async move {
                git_tag_list_exec(gctx, args).await.map_err(agent::ToolError::ExecutionError)
            })
        }),
    );

    // git_tag_info
    let p = HashMap::from([
        ("project_name".into(), ToolParam { name: "project_name".into(), param_type: "string".into(), description: Some("Project name (slug)".into()), required: true, properties: None, items: None }),
        ("repo_name".into(), ToolParam { name: "repo_name".into(), param_type: "string".into(), description: Some("Repository name".into()), required: true, properties: None, items: None }),
        ("name".into(), ToolParam { name: "name".into(), param_type: "string".into(), description: Some("Tag name to look up".into()), required: true, properties: None, items: None }),
    ]);
    let schema = ToolSchema { schema_type: "object".into(), properties: Some(p), required: Some(vec!["project_name".into(), "repo_name".into(), "name".into()]) };
    registry.register(
        ToolDefinition::new("git_tag_info").description("Get detailed information about a specific tag including target commit, annotation, and tagger.").parameters(schema),
        ToolHandler::new(|ctx, args| {
            let gctx = super::ctx::GitToolCtx::new(ctx);
            Box::pin(async move {
                git_tag_info_exec(gctx, args).await.map_err(agent::ToolError::ExecutionError)
            })
        }),
    );
}