//! Public MCP ticket tools.
//!
//! The public surface says `ticket`, while the provider behind this trait maps
//! to the application/domain `Issue` use cases.

use async_trait::async_trait;
use domain::Project;
use serde_json::{json, Value};

use super::tools::ToolDef;

/// Error returned by an MCP ticket tool provider.
#[derive(Debug, Clone, thiserror::Error)]
#[error("{code}: {message}")]
pub struct TicketToolError {
    /// Stable machine-readable code.
    pub code: &'static str,
    /// Human-readable message.
    pub message: String,
}

impl TicketToolError {
    /// Builds a typed ticket-tool error.
    #[must_use]
    pub fn new(code: &'static str, message: impl Into<String>) -> Self {
        Self {
            code,
            message: message.into(),
        }
    }

    /// Serialises the error as a camelCase JSON object.
    #[must_use]
    pub fn to_value(&self) -> Value {
        json!({ "code": self.code, "message": self.message })
    }
}

/// Provider injected by the composition root to execute public ticket tools.
#[async_trait]
pub trait TicketToolProvider: Send + Sync {
    /// Executes one public ticket/sprint planning tool for `project`.
    async fn handle_ticket_tool(
        &self,
        project: &Project,
        requester: &str,
        name: &str,
        arguments: Value,
    ) -> Result<Value, TicketToolError>;
}

/// Returns true when `name` is one of the public ticket tools.
#[must_use]
pub fn is_ticket_tool(name: &str) -> bool {
    matches!(
        name,
        "idea_ticket_create"
            | "idea_ticket_read"
            | "idea_ticket_list"
            | "idea_ticket_update"
            | "idea_ticket_update_status"
            | "idea_ticket_update_priority"
            | "idea_ticket_bulk_update_status"
            | "idea_ticket_bulk_update_priority"
            | "idea_ticket_bulk_delete"
            | "idea_ticket_read_carnet"
            | "idea_ticket_update_carnet"
            | "idea_ticket_link"
            | "idea_ticket_unlink"
            | "idea_sprint_list"
    )
}

/// Public ticket tool definitions advertised by `tools/list`.
#[must_use]
pub fn catalogue() -> Vec<ToolDef> {
    let ticket_ref = json!({ "type": "string", "pattern": "^#[1-9][0-9]*$" });
    let status = json!({ "type": "string", "enum": ["open", "inProgress", "QA", "closed"] });
    let priority = json!({ "type": "string", "enum": ["low", "medium", "high", "critical"] });
    let refs = json!({
        "type": "array",
        "minItems": 1,
        "uniqueItems": true,
        "items": ticket_ref.clone()
    });
    let created_by = json!({
        "oneOf": [
            {
                "type": "object",
                "properties": { "kind": { "const": "user" } },
                "required": ["kind"],
                "additionalProperties": false
            },
            {
                "type": "object",
                "properties": {
                    "kind": { "const": "agent" },
                    "agentId": { "type": "string", "format": "uuid" }
                },
                "required": ["kind", "agentId"],
                "additionalProperties": false
            }
        ]
    });
    let sort = json!({
        "type": "object",
        "properties": {
            "field": { "type": "string", "enum": ["number", "priority", "status", "title"] },
            "direction": { "type": "string", "enum": ["asc", "desc"] }
        },
        "required": ["field", "direction"],
        "additionalProperties": false
    });
    let link_kind = json!({
        "type": "string",
        "enum": ["relatesTo", "blocks", "blockedBy", "duplicates", "dependsOn"]
    });
    let link = json!({
        "type": "object",
        "properties": {
            "targetRef": ticket_ref.clone(),
            "kind": link_kind.clone()
        },
        "required": ["targetRef", "kind"],
        "additionalProperties": false
    });

    vec![
        ToolDef {
            name: "idea_ticket_create",
            description: "Create an IdeA ticket in the current project and return it as JSON.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "title": { "type": "string" },
                    "description": { "type": "string" },
                    "priority": priority.clone(),
                    "status": status.clone(),
                    "assignedAgentIds": { "type": "array", "items": { "type": "string", "format": "uuid" } },
                    "links": { "type": "array", "items": link.clone() }
                },
                "required": ["title"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_read",
            description: "Read one IdeA ticket by public reference (#N).",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "includeCarnet": { "type": "boolean" }
                },
                "required": ["ref"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_list",
            description: "List IdeA tickets in the current project.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "statuses": {
                        "type": "array",
                        "items": status.clone(),
                        "uniqueItems": true
                    },
                    "priorities": {
                        "type": "array",
                        "items": priority.clone(),
                        "uniqueItems": true
                    },
                    "assignedAgentId": { "type": "string", "format": "uuid" },
                    "createdBy": created_by,
                    "text": { "type": "string" },
                    "sort": sort.clone(),
                    "limit": { "type": "integer", "minimum": 1 },
                    "cursor": { "type": "string" }
                },
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_update",
            description: "Update ticket fields using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "title": { "type": "string" },
                    "description": { "type": "string" },
                    "status": status.clone(),
                    "priority": priority.clone(),
                    "assignedAgentIds": { "type": "array", "items": { "type": "string", "format": "uuid" } },
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_update_status",
            description: "Update a ticket status using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "status": status.clone(),
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "status", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_update_priority",
            description: "Update a ticket priority using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "priority": priority.clone(),
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "priority", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_bulk_update_status",
            description:
                "Update the status of several IdeA tickets and return one result per ticket.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "refs": refs.clone(),
                    "status": status.clone()
                },
                "required": ["refs", "status"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_bulk_update_priority",
            description:
                "Update the priority of several IdeA tickets and return one result per ticket.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "refs": refs.clone(),
                    "priority": priority.clone()
                },
                "required": ["refs", "priority"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_bulk_delete",
            description: "Delete several IdeA tickets and return one result per ticket.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "refs": refs.clone()
                },
                "required": ["refs"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_read_carnet",
            description: "Read the editable carnet attached to a ticket.",
            input_schema: json!({
                "type": "object",
                "properties": { "ref": ticket_ref.clone() },
                "required": ["ref"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_update_carnet",
            description: "Update a ticket carnet using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "carnet": { "type": "string" },
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "carnet", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_attachment_add",
            description: "Attach a local file to a ticket using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "path": { "type": "string" },
                    "mime": { "type": "string" },
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "path", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_attachment_read",
            description: "Read one ticket attachment as base64 content.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "attachmentId": { "type": "string" }
                },
                "required": ["ref", "attachmentId"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_attachment_mark_summarized",
            description: "Mark a ticket attachment as summarized in the carnet.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "attachmentId": { "type": "string" },
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "attachmentId", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_link",
            description: "Add a link from one ticket to another using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "targetRef": ticket_ref.clone(),
                    "kind": link_kind.clone(),
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "targetRef", "kind", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_ticket_unlink",
            description: "Remove a link from one ticket to another using optimistic concurrency.",
            input_schema: json!({
                "type": "object",
                "properties": {
                    "ref": ticket_ref.clone(),
                    "targetRef": ticket_ref,
                    "kind": link_kind,
                    "expectedVersion": { "type": "integer", "minimum": 1 }
                },
                "required": ["ref", "targetRef", "expectedVersion"],
                "additionalProperties": false
            }),
        },
        ToolDef {
            name: "idea_sprint_list",
            description: "List IdeA sprints in execution order. Read-only.",
            input_schema: json!({
                "type": "object",
                "properties": {},
                "additionalProperties": false
            }),
        },
    ]
}
