use crate::command::adapter::{AdapterError, InputAdapter, OutputAdapter};
use crate::command::context::AdapterContext;
use crate::command::response::{CommandResponse, MessageKind};
use crate::command::Command;

/// CLI 输入适配器
///
/// 将 CLI 的 "/new title" 等输入格式转换为 Command
pub struct CliInputAdapter;

impl CliInputAdapter {
    /// 创建新的 CLI 输入适配器
    pub fn new() -> Self {
        Self
    }
}

impl Default for CliInputAdapter {
    fn default() -> Self {
        Self::new()
    }
}

impl InputAdapter for CliInputAdapter {
    fn try_parse(
        &self,
        input: &str,
        _ctx: AdapterContext,
    ) -> Result<Option<Command>, AdapterError> {
        let trimmed = input.trim();

        // 解析 /new 命令
        if trimmed == "/new" {
            return Ok(Some(Command::CreateSession { title: None }));
        }

        if let Some(title) = trimmed.strip_prefix("/new ") {
            let title = title.trim();
            return Ok(Some(Command::CreateSession {
                title: Some(title.to_string()),
            }));
        }

        // 解析 /save 命令 - 保存当前话题
        if trimmed == "/save" {
            return Ok(Some(Command::SaveTopic {
                filepath: None,
                include_subagents: false,
            }));
        }

        if let Some(args) = trimmed.strip_prefix("/save ") {
            let args = args.trim();
            let parts: Vec<&str> = args.split_whitespace().collect();

            // 解析参数
            let mut include_subagents = false;
            let mut filepath = None;

            for part in parts {
                if part == "+sub" {
                    include_subagents = true;
                } else if !part.is_empty() {
                    // 非特殊参数视为文件路径
                    filepath = Some(part.to_string());
                }
            }

            return Ok(Some(Command::SaveTopic {
                filepath,
                include_subagents,
            }));
        }

        // 解析 /save-session 命令 - 保存整个会话
        if trimmed == "/save-session" {
            return Ok(Some(Command::SaveSession {
                filepath: None,
                include_all: false,
                include_subagents: false,
            }));
        }

        if let Some(args) = trimmed.strip_prefix("/save-session ") {
            let args = args.trim();
            let parts: Vec<&str> = args.split_whitespace().collect();

            // 解析参数
            let mut include_all = false;
            let mut include_subagents = false;
            let mut filepath = None;

            for part in parts {
                if part == "all" {
                    include_all = true;
                } else if part == "+sub" {
                    include_subagents = true;
                } else if !part.is_empty() {
                    // 非特殊参数视为文件路径
                    filepath = Some(part.to_string());
                }
            }

            return Ok(Some(Command::SaveSession {
                filepath,
                include_all,
                include_subagents,
            }));
        }

        // 解析 /list 命令
        if trimmed == "/list" {
            return Ok(Some(Command::ListSessions {
                include_archived: false,
            }));
        }

        if trimmed == "/list all" {
            return Ok(Some(Command::ListSessions {
                include_archived: true,
            }));
        }

        // 解析 /use 命令 - 切换话题（支持 topic_id 或序号）
        if let Some(topic_id) = trimmed.strip_prefix("/use ") {
            let topic_id = topic_id.trim();
            return Ok(Some(Command::SwitchTopic {
                topic_id: topic_id.to_string(),
            }));
        }

        // 解析 /current 命令 - 获取当前会话信息
        if trimmed == "/current" {
            return Ok(Some(Command::GetCurrentSession));
        }

        // 解析 /stop 命令 - 停止当前执行的 Agent
        if trimmed == "/stop" {
            return Ok(Some(Command::StopExecution));
        }

        // 解析 /help 命令 - 显示所有支持的命令
        if trimmed == "/help" {
            return Ok(Some(Command::Help));
        }

        // 不是命令，返回 None
        Ok(None)
    }
}

/// CLI 输出适配器
///
/// 将 CommandResponse 转换为 CLI 可读的字符串
pub struct CliOutputAdapter;

impl CliOutputAdapter {
    /// 创建新的 CLI 输出适配器
    pub fn new() -> Self {
        Self
    }
}

impl Default for CliOutputAdapter {
    fn default() -> Self {
        Self::new()
    }
}

impl OutputAdapter for CliOutputAdapter {
    type Output = String;

    fn adapt(&self, response: CommandResponse) -> String {
        if let Some(error) = response.error {
            return format!("Error [{}]: {}", error.code, error.message);
        }

        if !response.success {
            return "Error: Unknown error".to_string();
        }

        let mut lines = Vec::new();

        for msg in &response.messages {
            match msg.kind {
                MessageKind::Text | MessageKind::Notification => {
                    lines.push(msg.content.clone());
                }
                MessageKind::Error => {
                    lines.push(format!("Error: {}", msg.content));
                }
                _ => {
                    // 其他类型在 CLI 中简单显示
                    lines.push(msg.content.clone());
                }
            }
        }

        if lines.is_empty() {
            "Success".to_string()
        } else {
            lines.join("\n")
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_cli_input_adapter_new_without_title() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/new", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(cmd, Command::CreateSession { title: None }));
    }

    #[test]
    fn test_cli_input_adapter_new_with_title() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/new my session", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(
            cmd,
            Command::CreateSession {
                title: Some(ref t)
            } if t == "my session"
        ));
    }

    #[test]
    fn test_cli_input_adapter_not_command() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("hello world", ctx).unwrap();

        assert!(result.is_none());
    }

    #[test]
    fn test_cli_output_adapter_success() {
        let adapter = CliOutputAdapter::new();
        let request_id = uuid::Uuid::new_v4();
        let response = CommandResponse::success(request_id)
            .with_message(MessageKind::Notification, "Session created: abc123");

        let output = adapter.adapt(response);

        assert!(output.contains("Session created: abc123"));
    }

    #[test]
    fn test_cli_output_adapter_error() {
        let adapter = CliOutputAdapter::new();
        let request_id = uuid::Uuid::new_v4();
        let response = CommandResponse::error(
            request_id,
            crate::command::response::CommandError::new("TEST_ERROR", "something failed"),
        );

        let output = adapter.adapt(response);

        assert!(output.contains("Error [TEST_ERROR]"));
        assert!(output.contains("something failed"));
    }

    #[test]
    fn test_cli_input_adapter_save_topic_without_path() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(cmd, Command::SaveTopic { filepath: None, .. }));
    }

    #[test]
    fn test_cli_input_adapter_save_topic_with_path() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save ./debug/topic.md", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(
            cmd,
            Command::SaveTopic {
                filepath: Some(ref p),
                ..
            } if p == "./debug/topic.md"
        ));
    }

    #[test]
    fn test_cli_input_adapter_save_session_without_path() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save-session", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(cmd, Command::SaveSession { filepath: None, include_all: false, .. }));
    }

    #[test]
    fn test_cli_input_adapter_save_session_with_path() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save-session ./debug/session.md", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(
            cmd,
            Command::SaveSession {
                filepath: Some(ref p),
                include_all: false,
                ..
            } if p == "./debug/session.md"
        ));
    }

    #[test]
    fn test_cli_input_adapter_save_session_all() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save-session all", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(cmd, Command::SaveSession { filepath: None, include_all: true, .. }));
    }

    #[test]
    fn test_cli_input_adapter_save_session_all_with_path() {
        let adapter = CliInputAdapter::new();
        let ctx = AdapterContext::new("test");

        let result = adapter.try_parse("/save-session all ./debug/session.md", ctx).unwrap();

        assert!(result.is_some());
        let cmd = result.unwrap();
        assert!(matches!(
            cmd,
            Command::SaveSession {
                filepath: Some(ref p),
                include_all: true,
                ..
            } if p == "./debug/session.md"
        ));
    }

    #[test]
    fn test_cli_output_adapter_save_success() {
        let adapter = CliOutputAdapter::new();
        let request_id = uuid::Uuid::new_v4();
        let response = CommandResponse::success(request_id)
            .with_message(MessageKind::Notification, "Topic saved to: topic.md")
            .with_metadata("filepath", "topic.md");

        let output = adapter.adapt(response);

        assert!(output.contains("Topic saved to: topic.md"));
    }
}
