pub mod ws_adapter;

use serde::{Deserialize, Serialize};

/// 当前时间戳（秒），用于填充消息的 timestamp 字段
pub fn now_timestamp() -> i64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap_or_default()
        .as_secs() as i64
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionSummary {
    pub session_id: String,
    pub title: String,
    pub channel_name: String,
    pub chat_id: String,
    pub message_count: i64,
    pub last_active_at: i64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub archived_at: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel {
    pub id: String,
    pub name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(rename = "isWritable")]
    pub is_writable: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicSummary {
    pub topic_id: String,
    pub session_id: String,
    pub title: String,
    pub message_count: i64,
    pub created_at: i64,
    pub last_active_at: i64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaSummary {
    pub path: String,
    pub media_type: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mime_type: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub content_base64: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub file_name: Option<String>,
}

/// 定时任务会话查找键（用于前端加载执行对话）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchedulerJobSessionLookup {
    pub channel: String,
    pub chat_id: String,
}

/// Memory 摘要（发送给前端）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemorySummary {
    pub id: String,
    pub namespace: String,
    pub memory_key: String,
    pub content: String,
    pub created_at: i64,
    pub updated_at: i64,
}

/// Skill 摘要（发送给前端）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillSummary {
    pub name: String,
    pub description: String,
    pub source: String,
}

/// Todo item 摘要（发送给前端）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TodoItemSummary {
    pub id: String,
    pub content: String,
    pub status: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchedulerJobSummary {
    pub id: String,
    pub kind: String,
    pub schedule: serde_json::Value,
    pub enabled: bool,
    pub state: String,
    pub last_status: Option<String>,
    pub last_error: Option<String>,
    pub run_count: i64,
    pub max_runs: Option<i64>,
    pub last_fired_at: Option<i64>,
    pub next_fire_at: Option<i64>,
    pub created_at: i64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub session_lookup: Option<SchedulerJobSessionLookup>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WsInbound {
    /// 普通用户消息
    #[serde(rename = "message")]
    Message {
        content: String,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        attachments: Vec<MediaSummary>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        channel: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        chat_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        sender_id: Option<String>,
    },
    /// 命令（JSON 格式）
    #[serde(rename = "command")]
    Command { payload: String },
    #[serde(rename = "ping")]
    Ping,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum WsOutbound {
    #[serde(rename = "assistant_response")]
    AssistantResponse {
        id: String,
        content: String,
        role: String,
        #[serde(default, skip_serializing_if = "Vec::is_empty")]
        attachments: Vec<MediaSummary>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        subagent_task_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        topic_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        timestamp: Option<i64>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        reasoning_content: Option<String>,
    },
    #[serde(rename = "tool_call")]
    ToolCall {
        id: String,
        tool_call_id: String,
        tool_name: String,
        arguments: serde_json::Value,
        content: String,
        role: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        subagent_task_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        topic_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        timestamp: Option<i64>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        reasoning_content: Option<String>,
    },
    #[serde(rename = "tool_result")]
    ToolResult {
        id: String,
        tool_call_id: String,
        tool_name: String,
        content: String,
        role: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        subagent_task_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        topic_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        duration_ms: Option<u64>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        timestamp: Option<i64>,
    },
    #[serde(rename = "tool_pending")]
    ToolPending {
        id: String,
        tool_call_id: String,
        tool_name: String,
        content: String,
        role: String,
        resume_hint: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        subagent_task_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        topic_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        timestamp: Option<i64>,
    },
    #[serde(rename = "error")]
    Error {
        code: String,
        message: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        timestamp: Option<i64>,
    },
    #[serde(rename = "task_started")]
    TaskStarted {
        task_id: String,
        description: String,
        subagent_type: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        topic_id: Option<String>,
    },
    #[serde(rename = "session_established")]
    SessionEstablished { session_id: String },
    #[serde(rename = "session_created")]
    SessionCreated { session_id: String, title: String },
    #[serde(rename = "session_list")]
    SessionList {
        sessions: Vec<SessionSummary>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        current_session_id: Option<String>,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        channel_name: Option<String>,
    },
    #[serde(rename = "channel_list")]
    ChannelList {
        channels: Vec<Channel>,
    },
    #[serde(rename = "topic_list")]
    TopicList {
        topics: Vec<TopicSummary>,
        session_id: String,
    },
    #[serde(rename = "session_loaded")]
    SessionLoaded {
        session_id: String,
        title: String,
        message_count: i64,
    },
    #[serde(rename = "session_saved")]
    SessionSaved { session_id: String, filepath: String },
    #[serde(rename = "task_messages_loaded")]
    TaskMessagesLoaded {
        task_id: String,
        description: String,
        subagent_type: String,
        status: String,
        #[serde(default, skip_serializing_if = "Option::is_none")]
        summary: Option<String>,
    },
    #[serde(rename = "scheduler_job_list")]
    SchedulerJobList {
        jobs: Vec<SchedulerJobSummary>,
    },
    #[serde(rename = "memory_list")]
    MemoryList {
        memories: Vec<MemorySummary>,
    },
    #[serde(rename = "skill_list")]
    SkillList {
        skills: Vec<SkillSummary>,
    },
    #[serde(rename = "execution_cancelled")]
    ExecutionCancelled { message: String },
    #[serde(rename = "todo_list")]
    TodoList {
        todos: Vec<TodoItemSummary>,
        scope_key: String,
    },
    #[serde(rename = "pong")]
    Pong,
}

pub fn parse_inbound(raw: &str) -> Result<WsInbound, serde_json::Error> {
    serde_json::from_str(raw)
}

pub fn serialize_inbound(msg: &WsInbound) -> Result<String, serde_json::Error> {
    serde_json::to_string(msg)
}

pub fn serialize_outbound(msg: &WsOutbound) -> Result<String, serde_json::Error> {
    serde_json::to_string(msg)
}
