use std::sync::Arc;

use async_trait::async_trait;
use serde_json::json;

use crate::tools::traits::{Tool, ToolResult};
use crate::work::{TaskPlan, WorkManager};

pub struct TodoTool {
    work_manager: Arc<WorkManager>,
}

impl TodoTool {
    pub fn new(work_manager: Arc<WorkManager>) -> Self {
        Self { work_manager }
    }

    fn session_id(context: &crate::tools::ToolExecutionContext) -> anyhow::Result<String> {
        context
            .agent
            .as_ref()
            .map(|agent| agent.root_session_id.clone())
            .or_else(|| context.session_id.clone())
            .ok_or_else(|| anyhow::anyhow!("todo requires a session-bound context"))
    }
}

#[async_trait]
impl Tool for TodoTool {
    fn name(&self) -> &str {
        "todo"
    }

    fn description(&self) -> &str {
        "管理当前 session 的复杂任务计划。仅用于明确需要多步骤、跨轮次或并行委托的任务；闲聊、问答和单步操作不要创建计划。"
    }

    fn parameters_schema(&self) -> serde_json::Value {
        json!({
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "enum": ["create", "view", "append", "update", "close"]
                },
                "objective": { "type": "string", "description": "create 时的总体目标" },
                "items": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "create 时的有序子项"
                },
                "item_id": { "type": "string", "description": "update 时的 T1/T2..." },
                "title": { "type": "string", "description": "append 时的新子项标题" },
                "status": {
                    "type": "string",
                    "enum": ["pending", "in_progress", "completed", "blocked", "cancelled"],
                    "description": "update 的子项状态或 close 的计划状态"
                },
                "summary": { "type": "string", "description": "完成结果或阻塞原因" },
                "expected_version": { "type": "integer", "description": "可选的计划版本并发校验" }
            },
            "required": ["action"]
        })
    }

    fn read_only(&self) -> bool {
        false
    }

    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {
        self.execute_with_context(&crate::tools::ToolExecutionContext::default(), args)
            .await
            .map(|output| output.result)
    }

    async fn execute_with_context(
        &self,
        context: &crate::tools::ToolExecutionContext,
        args: serde_json::Value,
    ) -> anyhow::Result<crate::tools::ToolOutput> {
        let action = args["action"]
            .as_str()
            .ok_or_else(|| anyhow::anyhow!("missing action"))?;
        let session_id = Self::session_id(context)?;
        let expected = args["expected_version"].as_i64();
        let result = match action {
            "create" => {
                let objective = required_str(&args, "objective")?;
                let items = args["items"]
                    .as_array()
                    .ok_or_else(|| anyhow::anyhow!("create requires items"))?
                    .iter()
                    .filter_map(|value| value.as_str().map(str::to_string))
                    .collect::<Vec<_>>();
                self.work_manager
                    .create_plan(&session_id, objective, &items)
                    .await
            }
            "view" => match self.work_manager.active_plan(&session_id).await? {
                Some(plan) => Ok(plan),
                None => {
                    return Ok(ToolResult {
                        success: true,
                        output: "当前 session 没有 active plan".to_string(),
                        error: None,
                    }
                    .into());
                }
            },
            "append" => {
                self.work_manager
                    .append_item(&session_id, required_str(&args, "title")?, expected)
                    .await
            }
            "update" => {
                self.work_manager
                    .update_item(
                        &session_id,
                        required_str(&args, "item_id")?,
                        required_str(&args, "status")?,
                        args["summary"].as_str(),
                        expected,
                    )
                    .await
            }
            "close" => {
                self.work_manager
                    .close_plan(&session_id, required_str(&args, "status")?, expected)
                    .await
            }
            _ => return Err(anyhow::anyhow!("unknown todo action: {action}")),
        };

        match result {
            Ok(plan) => Ok(ToolResult {
                success: true,
                output: render_plan(&plan),
                error: None,
            }
            .into()),
            Err(error) => Ok(ToolResult {
                success: false,
                output: String::new(),
                error: Some(error.to_string()),
            }
            .into()),
        }
    }
}

fn required_str<'a>(args: &'a serde_json::Value, key: &str) -> anyhow::Result<&'a str> {
    args[key]
        .as_str()
        .filter(|value| !value.trim().is_empty())
        .ok_or_else(|| anyhow::anyhow!("missing required parameter: {key}"))
}

fn render_plan(plan: &TaskPlan) -> String {
    let mut output = format!(
        "计划 {}（{}，version {}）\n目标：{}\n",
        plan.id, plan.status, plan.version, plan.objective
    );
    for item in &plan.items {
        let icon = match item.status.as_str() {
            "completed" => "✓",
            "in_progress" => "●",
            "blocked" => "!",
            _ => "○",
        };
        output.push_str(&format!(
            "{icon} {} [{}] {}",
            item.id, item.status, item.title
        ));
        if let Some(summary) = item.result_summary.as_deref().or(item.error.as_deref()) {
            output.push_str(&format!(" — {summary}"));
        }
        output.push('\n');
    }
    output.trim_end().to_string()
}
