//! Task handlers — tasks/list, tasks/get, tasks/result, tasks/cancel

use crate::protocol::errors::McpError;
use crate::protocol::types::JsonRpcResponse;
use crate::server::core::Server;
use crate::server::handler::{
    RequestContext, error_response, require_initialization, success_response,
};

impl Server {
    /// Handle tasks/get request
    pub(crate) async fn handle_tasks_get(&self, ctx: RequestContext) -> JsonRpcResponse {
        if let Err(err) = require_initialization(&ctx) {
            return error_response(ctx.request.id, err.to_jsonrpc());
        }

        let params: crate::protocol::types::GetTaskParams = match ctx.params() {
            Some(p) => match serde_json::from_value(p.clone()) {
                Ok(params) => params,
                Err(_) => {
                    return error_response(
                        ctx.request.id,
                        McpError::validation("invalid_params", "Missing or invalid taskId")
                            .to_jsonrpc(),
                    );
                }
            },
            None => {
                return error_response(
                    ctx.request.id,
                    McpError::validation("invalid_params", "Missing taskId parameter").to_jsonrpc(),
                );
            }
        };

        match self
            .task_store
            .get_task_for_session(&params.task_id, &ctx.session.id)
            .await
        {
            Some(task) => success_response(ctx.request.id, serde_json::to_value(task).unwrap()),
            None => error_response(
                ctx.request.id,
                McpError::validation("invalid_params", "Task not found").to_jsonrpc(),
            ),
        }
    }

    /// Handle tasks/result request (blocks until terminal state)
    pub(crate) async fn handle_tasks_result(&self, ctx: RequestContext) -> JsonRpcResponse {
        if let Err(err) = require_initialization(&ctx) {
            return error_response(ctx.request.id, err.to_jsonrpc());
        }

        let params: crate::protocol::types::GetTaskParams = match ctx.params() {
            Some(p) => match serde_json::from_value(p.clone()) {
                Ok(params) => params,
                Err(_) => {
                    return error_response(
                        ctx.request.id,
                        McpError::validation("invalid_params", "Missing or invalid taskId")
                            .to_jsonrpc(),
                    );
                }
            },
            None => {
                return error_response(
                    ctx.request.id,
                    McpError::validation("invalid_params", "Missing taskId parameter").to_jsonrpc(),
                );
            }
        };

        // Verify session owns task
        if self
            .task_store
            .get_task_for_session(&params.task_id, &ctx.session.id)
            .await
            .is_none()
        {
            return error_response(
                ctx.request.id,
                McpError::validation("invalid_params", "Task not found").to_jsonrpc(),
            );
        }

        // Wait for result (5-minute timeout)
        match self
            .task_store
            .wait_for_result(&params.task_id, std::time::Duration::from_secs(300))
            .await
        {
            Ok(result) => success_response(ctx.request.id, result),
            Err(e) => error_response(
                ctx.request.id,
                McpError::internal("task_error", e.to_string()).to_jsonrpc(),
            ),
        }
    }

    /// Handle tasks/list request
    pub(crate) async fn handle_tasks_list(&self, ctx: RequestContext) -> JsonRpcResponse {
        if let Err(err) = require_initialization(&ctx) {
            return error_response(ctx.request.id, err.to_jsonrpc());
        }

        // Parse cursor if present
        let cursor = ctx
            .params()
            .and_then(|p| p.get("cursor"))
            .and_then(|c| c.as_str());

        let (tasks, next_cursor) = self
            .task_store
            .list_tasks(&ctx.session.id, cursor, 100)
            .await;

        success_response(
            ctx.request.id,
            serde_json::json!({
                "tasks": tasks,
                "nextCursor": next_cursor,
            }),
        )
    }

    /// Handle tasks/cancel request
    pub(crate) async fn handle_tasks_cancel(&self, ctx: RequestContext) -> JsonRpcResponse {
        if let Err(err) = require_initialization(&ctx) {
            return error_response(ctx.request.id, err.to_jsonrpc());
        }

        let params: crate::protocol::types::CancelTaskParams = match ctx.params() {
            Some(p) => match serde_json::from_value(p.clone()) {
                Ok(params) => params,
                Err(_) => {
                    return error_response(
                        ctx.request.id,
                        McpError::validation("invalid_params", "Missing or invalid taskId")
                            .to_jsonrpc(),
                    );
                }
            },
            None => {
                return error_response(
                    ctx.request.id,
                    McpError::validation("invalid_params", "Missing taskId parameter").to_jsonrpc(),
                );
            }
        };

        match self
            .task_store
            .cancel_task(&params.task_id, &ctx.session.id)
            .await
        {
            Ok(task) => success_response(ctx.request.id, serde_json::to_value(task).unwrap()),
            Err(e) => {
                let error_msg = match e {
                    crate::managers::task::TaskError::NotFound(_) => {
                        McpError::validation("invalid_params", "Task not found")
                    }
                    crate::managers::task::TaskError::AlreadyTerminal(status) => {
                        McpError::validation(
                            "invalid_params",
                            format!(
                                "Cannot cancel task: already in terminal status '{:?}'",
                                status
                            ),
                        )
                    }
                    _ => McpError::internal("task_error", e.to_string()),
                };
                error_response(ctx.request.id, error_msg.to_jsonrpc())
            }
        }
    }
}
