use crate::command::context::CommandContext;
use crate::command::handler::{CommandHandler, CommandMetadata};
use crate::command::response::{CommandError, CommandResponse};
use crate::command::Command;
use crate::protocol::TodoItemSummary;
use crate::storage::SessionStore;
use async_trait::async_trait;
use std::sync::Arc;

pub struct ListTodosCommandHandler {
    store: Arc<SessionStore>,
}

impl ListTodosCommandHandler {
    pub fn new(store: Arc<SessionStore>) -> Self {
        Self { store }
    }
}

#[async_trait]
impl CommandHandler for ListTodosCommandHandler {
    fn can_handle(&self, cmd: &Command) -> bool {
        matches!(cmd, Command::ListTodos { .. })
    }

    fn metadata(&self) -> Option<CommandMetadata> {
        Some(CommandMetadata {
            name: "list_todos",
            description: "列出当前 Todo 列表",
            usage: "/list_todos",
        })
    }

    async fn handle(
        &self,
        cmd: Command,
        ctx: CommandContext,
    ) -> Result<CommandResponse, CommandError> {
        let task_id = match cmd {
            Command::ListTodos { task_id } => task_id,
            _ => None,
        };

        // 子代理：scope_key = sub:{parent_session_id}:{task_id}
        // 主代理：scope_key = topic_id.unwrap_or(session_id)
        let scope_key = if let (Some(tid), Some(parent_sid)) = (task_id.as_deref(), ctx.session_id.as_deref()) {
            format!("sub:{}:{}", parent_sid, tid)
        } else {
            ctx.topic_id
                .as_deref()
                .filter(|t| !t.is_empty())
                .or(ctx.session_id.as_deref())
                .ok_or_else(|| {
                    CommandError::new(
                        "MISSING_CONTEXT",
                        "Cannot list todos: no session_id or topic_id in command context",
                    )
                })?
                .to_string()
        };

        let records = self
            .store
            .list_todos(&scope_key)
            .map_err(|e| CommandError::new("LIST_TODOS_ERROR", e.to_string()))?;

        tracing::info!(
            scope_key = %scope_key,
            record_count = records.len(),
            "list_todos handler: reading from store"
        );

        let summaries: Vec<TodoItemSummary> = records
            .into_iter()
            .map(|r| TodoItemSummary {
                id: r.id,
                content: r.content,
                status: r.status,
            })
            .collect();

        let todos_json = serde_json::to_string(&summaries)
            .map_err(|e| CommandError::new("SERIALIZE_ERROR", e.to_string()))?;

        Ok(CommandResponse::success(ctx.request_id)
            .with_metadata("todos", &todos_json)
            .with_metadata("todos_scope_key", &scope_key))
    }
}
