use crate::agent::{SystemPrompt, SystemPromptContext, SystemPromptProvider};
use crate::bus::ChatMessage;
use crate::command::context::CommandContext;
use crate::command::handler::{CommandHandler, CommandMetadata};
use crate::command::handlers::{
    escape_yaml_string, format_timestamp, generate_messages_markdown,
    generate_subagent_tasks_markdown, generate_system_prompt_markdown,
    get_messages_from_session, load_subagent_data, SubagentTaskData,
};
use crate::command::response::{CommandError, CommandResponse, MessageKind};
use crate::command::Command;
use crate::gateway::session::SessionManager;
use crate::storage::{SessionStore, TopicRecord};
use crate::tools::task::repository::TaskRepository;
use async_trait::async_trait;
use chrono::Local;
use std::path::PathBuf;
use std::sync::Arc;

/// 保存话题到文件
pub async fn save_topic_to_file(
    topic_id: &str,
    filepath: Option<String>,
    include_subagents: bool,
    store: &SessionStore,
    task_repository: Option<&dyn TaskRepository>,
    system_prompt_provider: &dyn SystemPromptProvider,
    messages: &[ChatMessage],
) -> Result<PathBuf, String> {
    // 获取话题记录
    let topic = store
        .get_topic(topic_id)
        .map_err(|e| format!("Failed to get topic: {}", e))?
        .ok_or_else(|| "Topic not found".to_string())?;

    // 获取 session 信息（用于系统提示词）
    let session = store
        .get_session(&topic.session_id)
        .map_err(|e| format!("Failed to get session: {}", e))?;

    // 构建系统提示词
    let user_message_count = messages.iter().filter(|m| m.role == "user").count();
    let system_prompt = build_system_prompt(system_prompt_provider, &session, user_message_count);

    // 加载子智能体消息（如果启用）
    let subagent_data = if include_subagents {
        load_subagent_data(&topic.session_id, Some(topic_id), store, task_repository).await
    } else {
        Vec::new()
    };

    // 生成 Markdown 内容
    let markdown = generate_topic_markdown(&topic, &system_prompt, messages, &subagent_data);

    // 确定输出路径
    let output_path = resolve_topic_filepath(filepath, &topic);

    // 创建父目录
    if let Some(parent) = output_path.parent() {
        if !parent.as_os_str().is_empty() && !parent.exists() {
            std::fs::create_dir_all(parent)
                .map_err(|e| format!("Failed to create directory: {}", e))?;
        }
    }

    // 写入文件
    std::fs::write(&output_path, markdown)
        .map_err(|e| format!("Failed to write file: {}", e))?;

    Ok(output_path)
}

/// 构建系统提示词
fn build_system_prompt(
    provider: &dyn SystemPromptProvider,
    session: &Option<crate::storage::SessionRecord>,
    user_message_count: usize,
) -> Option<SystemPrompt> {
    let session = session.as_ref()?;
    let context = SystemPromptContext {
        session_id: Some(session.id.clone()),
        chat_id: session.chat_id.clone(),
        user_message_count,
    };
    provider.build(&context)
}

/// 生成话题 Markdown 内容（复用公共函数）
fn generate_topic_markdown(
    topic: &TopicRecord,
    system_prompt: &Option<SystemPrompt>,
    messages: &[crate::bus::ChatMessage],
    subagent_data: &[SubagentTaskData],
) -> String {
    let mut output = String::new();

    // YAML frontmatter（Topic 特有）
    output.push_str("---\n");
    output.push_str(&format!("title: {}\n", escape_yaml_string(&topic.title)));
    output.push_str(&format!("topic_id: {}\n", topic.id));
    output.push_str(&format!("session_id: {}\n", topic.session_id));
    if let Some(ref desc) = topic.description {
        output.push_str(&format!("description: {}\n", escape_yaml_string(desc)));
    }
    output.push_str(&format!(
        "created_at: {}\n",
        format_timestamp(topic.created_at)
    ));
    output.push_str(&format!(
        "updated_at: {}\n",
        format_timestamp(topic.updated_at)
    ));
    output.push_str(&format!(
        "last_active_at: {}\n",
        format_timestamp(topic.last_active_at)
    ));
    output.push_str(&format!("message_count: {}\n", messages.len()));
    if !subagent_data.is_empty() {
        output.push_str(&format!("subagent_count: {}\n", subagent_data.len()));
    }
    output.push_str("---\n\n");

    // 系统提示词（复用公共函数）
    output.push_str(&generate_system_prompt_markdown(system_prompt));

    // 子智能体任务（如果有）
    if !subagent_data.is_empty() {
        output.push_str(&generate_subagent_tasks_markdown(subagent_data));
    }

    // 消息历史（复用公共函数）
    output.push_str(&generate_messages_markdown(messages));

    output
}

/// 解析话题文件路径（Topic 特有）
fn resolve_topic_filepath(filepath: Option<String>, topic: &TopicRecord) -> PathBuf {
    match filepath {
        Some(path) => PathBuf::from(path),
        None => {
            let safe_title = topic
                .title
                .replace(' ', "_")
                .replace('/', "_")
                .replace('\\', "_")
                .replace(':', "_")
                .replace('<', "_")
                .replace('>', "_")
                .replace('|', "_")
                .replace('?', "_")
                .replace('*', "_")
                .replace('"', "_");

            let base_name = if safe_title.is_empty() {
                format!("topic_{}", &topic.id[..8.min(topic.id.len())])
            } else {
                safe_title
            };

            let timestamp = Local::now().format("%Y%m%d_%H%M%S");
            let filename = format!("{}_{}.md", base_name, timestamp);

            dirs::home_dir()
                .unwrap_or_else(|| PathBuf::from("."))
                .join(".picobot")
                .join("topics")
                .join(filename)
        }
    }
}

/// 保存话题命令处理器
pub struct SaveTopicCommandHandler {
    store: Arc<SessionStore>,
    task_repository: Arc<dyn TaskRepository>,
    system_prompt_provider: Arc<dyn SystemPromptProvider>,
    session_manager: Option<SessionManager>,
}

impl SaveTopicCommandHandler {
    pub fn new(
        store: Arc<SessionStore>,
        task_repository: Arc<dyn TaskRepository>,
        system_prompt_provider: Arc<dyn SystemPromptProvider>,
    ) -> Self {
        Self {
            store,
            task_repository,
            system_prompt_provider,
            session_manager: None,
        }
    }

    pub fn with_session_manager(mut self, session_manager: SessionManager) -> Self {
        self.session_manager = Some(session_manager);
        self
    }
}

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

    fn metadata(&self) -> Option<CommandMetadata> {
        Some(CommandMetadata {
            name: "save",
            description: "保存当前话题到 Markdown 文件",
            usage: "/save [filepath]",
        })
    }

    async fn handle(
        &self,
        cmd: Command,
        ctx: CommandContext,
    ) -> Result<CommandResponse, CommandError> {
        match cmd {
            Command::SaveTopic { filepath, include_subagents } => {
                handle_save_topic(self, filepath, include_subagents, ctx).await
            }
            _ => unreachable!(),
        }
    }
}

async fn handle_save_topic(
    handler: &SaveTopicCommandHandler,
    filepath: Option<String>,
    include_subagents: bool,
    ctx: CommandContext,
) -> Result<CommandResponse, CommandError> {
    tracing::debug!(
        ctx_topic_id = ?ctx.topic_id,
        ctx_session_id = ?ctx.session_id,
        channel = %ctx.channel_name,
        include_subagents = include_subagents,
        "SaveTopic command received"
    );

    let topic_id = ctx
        .topic_id
        .as_deref()
        .ok_or_else(|| CommandError::new("NO_TOPIC", "No active topic".to_string()))?;

    let chat_id = ctx
        .chat_id
        .as_deref()
        .ok_or_else(|| CommandError::new("NO_CHAT_ID", "No chat id".to_string()))?;

    tracing::debug!(topic_id = %topic_id, chat_id = %chat_id, "Attempting to save topic");

    // 从 Session 获取当前 history（包含已压缩的消息）
    let messages = get_messages_from_session(
        &handler.session_manager,
        &ctx.channel_name,
        chat_id,
    ).await?;

    tracing::debug!(message_count = messages.len(), "Got messages from session");

    // 调用保存函数
    let output_path = save_topic_to_file(
        topic_id,
        filepath,
        include_subagents,
        &*handler.store,
        Some(handler.task_repository.as_ref()),
        &*handler.system_prompt_provider,
        &messages,
    )
    .await
    .map_err(|e| CommandError::new("SAVE_ERROR", e))?;

    let message_count = messages.len();

    Ok(CommandResponse::success(ctx.request_id)
        .with_message(
            MessageKind::Notification,
            &format!("Topic saved to: {}", output_path.display()),
        )
        .with_metadata("filepath", output_path.to_string_lossy().as_ref())
        .with_metadata("message_count", &message_count.to_string()))
}