use crate::command::context::CommandContext;
use crate::command::handler::{CommandHandler, CommandMetadata};
use crate::command::handlers::list_topics::TopicSummary;
use crate::command::response::{CommandError, CommandResponse, MessageKind};
use crate::command::Command;
use crate::gateway::session::SessionManager;
use crate::storage::SessionStore;
use async_trait::async_trait;
use std::sync::Arc;

/// 会话命令处理器
///
/// 处理与会话管理相关的命令
pub struct SessionCommandHandler {
    store: Arc<SessionStore>,
    session_manager: Option<SessionManager>,
}

impl SessionCommandHandler {
    /// 创建新的会话命令处理器
    ///
    /// # Arguments
    /// * `store` - Session 存储
    pub(crate) fn new(store: Arc<SessionStore>) -> Self {
        Self {
            store,
            session_manager: None,
        }
    }

    /// 设置 SessionManager（用于 CreateSession 命令自动切换话题）
    pub fn with_session_manager(mut self, session_manager: SessionManager) -> Self {
        self.session_manager = Some(session_manager);
        self
    }
}

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

    fn metadata(&self) -> Option<CommandMetadata> {
        Some(CommandMetadata {
            name: "new",
            description: "创建新话题",
            usage: "/new [title]",
        })
    }

    async fn handle(
        &self,
        cmd: Command,
        ctx: CommandContext,
    ) -> Result<CommandResponse, CommandError> {
        match cmd {
            Command::CreateSession { title } => handle_create_session(self, title, ctx).await,
            Command::SaveSession { .. } => unreachable!("SaveSession should be handled by SaveSessionCommandHandler"),
            _ => unreachable!("Other commands should be handled by other handlers"),
        }
    }
}

/// 处理创建会话命令
async fn handle_create_session(
    handler: &SessionCommandHandler,
    title: Option<String>,
    ctx: CommandContext,
) -> Result<CommandResponse, CommandError> {
    // 获取当前 session_id，如果没有则报错
    let session_id = ctx.session_id.as_deref()
        .ok_or_else(|| CommandError::new("NO_SESSION", "No active session. Please ensure a session exists first."))?;

    // 创建新话题（在同一个 Session 内）
    let topic_title = title.unwrap_or_else(|| {
        format!("Topic {}", &uuid::Uuid::new_v4().to_string()[..8])
    });

    let topic = handler
        .store
        .create_topic(session_id, &topic_title, None)
        .map_err(|e| CommandError::new("CREATE_TOPIC_ERROR", e.to_string()))?;

    // 获取 chat_id
    let chat_id = ctx.chat_id.as_deref()
        .ok_or_else(|| CommandError::new("NO_CHAT_ID", "No chat_id in context"))?;

    // 如果有 SessionManager，自动切换到新话题
    if let Some(ref session_manager) = handler.session_manager {
        if let Some(session) = session_manager.get(&ctx.channel_name).await {
            let mut session_guard = session.lock().await;
            session_guard.switch_topic(chat_id, &topic.id)
                .map_err(|e| CommandError::new("SWITCH_TOPIC_ERROR", e.to_string()))?;
        }
    }

    // Query the full topic list so the frontend sidebar can update
    let topics = handler
        .store
        .list_topics(session_id)
        .map_err(|e| CommandError::new("LIST_TOPICS_ERROR", e.to_string()))?;

    let topic_summaries: Vec<TopicSummary> = topics
        .into_iter()
        .map(|t| TopicSummary {
            topic_id: t.id,
            session_id: t.session_id,
            title: t.title,
            description: t.description.filter(|d| !d.is_empty()),
            message_count: t.message_count,
            created_at: t.created_at,
            last_active_at: t.last_active_at,
        })
        .collect();

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

    Ok(CommandResponse::success(ctx.request_id)
        .with_message(MessageKind::Notification, &topic.title)
        .with_metadata("topics", &topics_json)
        .with_metadata("topic_id", &topic.id)
        .with_metadata("session_id", &topic.session_id)
        .with_metadata("message_count", &topic.message_count.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::storage::SessionStore;
    use std::sync::Arc;

    fn create_test_handler() -> SessionCommandHandler {
        let store = Arc::new(SessionStore::in_memory().unwrap());
        SessionCommandHandler::new(store)
    }

    #[tokio::test]
    async fn test_create_session_with_title() {
        let handler = create_test_handler();
        // 需要先创建一个 session
        let store = handler.store.clone();
        let session = store.create_session("cli", Some("test session")).unwrap();

        let ctx = CommandContext::new("test", "cli")
            .with_session_id(&session.id)
            .with_chat_id(&session.id);
        let cmd = Command::CreateSession {
            title: Some("my topic".to_string()),
        };

        let result = handler.handle(cmd, ctx).await;

        assert!(result.is_ok());
        let resp = result.unwrap();
        assert!(resp.success);
        assert!(resp.metadata.contains_key("topic_id"));
    }

    #[tokio::test]
    async fn test_create_session_without_title() {
        let handler = create_test_handler();
        let store = handler.store.clone();
        let session = store.create_session("cli", Some("test session")).unwrap();

        let ctx = CommandContext::new("test", "cli")
            .with_session_id(&session.id)
            .with_chat_id(&session.id);
        let cmd = Command::CreateSession { title: None };

        let result = handler.handle(cmd, ctx).await;

        assert!(result.is_ok());
        let resp = result.unwrap();
        assert!(resp.success);
    }

    #[test]
    fn test_can_handle() {
        let handler = create_test_handler();

        assert!(handler.can_handle(&Command::CreateSession { title: None }));
    }
}
