use serde::{Deserialize, Serialize};

/// 全局统一的记忆 scope_key，所有渠道共享同一份记忆空间
pub const GLOBAL_SCOPE_KEY: &str = "default";

/// 允许的记忆命名空间列表
///
/// 每个命名空间代表一类记忆内容，用于分类管理和检索。
/// 禁止使用未在此列表中的 namespace 创建记忆。
pub const ALLOWED_MEMORY_NAMESPACES: &[(&str, &str)] = &[
    ("user", "用户记忆：存储用户长期偏好、身份背景和历史协作信息，实现跨会话的个性化服务与持续协作"),
    ("semantic", "语义记忆：存储结构化或非结构化知识内容，支持知识检索、问答增强和长期知识积累"),
    ("episodic", "情景记忆：记录历史对话、任务执行过程及关键事件，支持经验回溯、案例复用和行为追踪"),
    ("skill", "技能记忆：存储技能定义、工作流、工具调用策略及最佳实践，支持能力复用与自动化执行"),
    ("environment", "环境记忆：存储外部系统状态、运行环境配置和实时资源信息，为智能决策提供环境感知能力"),
    ("reflection", "反思记忆：沉淀任务执行过程中的成功经验、失败原因和优化建议，支持智能体持续学习与自我改进"),
    ("other", "其他记忆：不属于以上分类的其他记忆内容"),
];

/// 验证 namespace 是否在允许列表中
pub fn is_valid_namespace(namespace: &str) -> bool {
    ALLOWED_MEMORY_NAMESPACES.iter().any(|(name, _)| *name == namespace)
}

/// 获取 namespace 的中文描述
pub fn get_namespace_description(namespace: &str) -> Option<&'static str> {
    ALLOWED_MEMORY_NAMESPACES
        .iter()
        .find(|(name, _)| *name == namespace)
        .map(|(_, desc)| *desc)
}

/// 获取所有允许的 namespace 名称列表（用于 JSON schema enum）
pub fn allowed_namespace_names() -> Vec<&'static str> {
    ALLOWED_MEMORY_NAMESPACES.iter().map(|(name, _)| *name).collect()
}

#[derive(Debug, Clone)]
pub struct TodoRecord {
    pub id: String,
    pub scope_key: String,
    pub session_id: String,
    pub topic_id: Option<String>,
    pub content: String,
    pub status: String,
    pub priority: String,
    pub created_at: i64,
    pub updated_at: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillEventRecord {
    pub id: String,
    pub session_id: Option<String>,
    pub event_type: String,
    pub skill_name: Option<String>,
    pub payload: serde_json::Value,
    pub created_at: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionRecord {
    pub id: String,
    pub title: String,
    pub channel_name: String,
    pub chat_id: String,
    pub summary: Option<String>,
    pub created_at: i64,
    pub updated_at: i64,
    pub last_active_at: i64,
    pub archived_at: Option<i64>,
    pub deleted_at: Option<i64>,
    pub message_count: i64,
    pub user_turn_count: i64,
    pub agent_prompt_reinjection_count: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicRecord {
    pub id: String,
    pub session_id: String,
    pub title: String,
    pub description: Option<String>,
    pub created_at: i64,
    pub updated_at: i64,
    pub last_active_at: i64,
    pub message_count: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryRecord {
    pub id: String,
    pub scope_kind: String,
    pub scope_key: String,
    pub namespace: String,
    pub memory_key: String,
    pub content: String,
    pub source_type: String,
    pub source_session_id: Option<String>,
    pub source_message_id: Option<String>,
    pub source_message_seq: Option<i64>,
    pub source_channel_name: Option<String>,
    pub source_chat_id: Option<String>,
    pub created_at: i64,
    pub updated_at: i64,
}

#[derive(Debug, Clone)]
pub struct MemoryUpsert {
    pub scope_kind: String,
    pub scope_key: String,
    pub namespace: String,
    pub memory_key: String,
    pub content: String,
    pub source_type: String,
    pub source_session_id: Option<String>,
    pub source_message_id: Option<String>,
    pub source_message_seq: Option<i64>,
    pub source_channel_name: Option<String>,
    pub source_chat_id: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SchedulerJobState {
    Scheduled,
    Running,
    Paused,
    Completed,
}

impl SchedulerJobState {
    pub fn as_str(&self) -> &'static str {
        match self {
            SchedulerJobState::Scheduled => "scheduled",
            SchedulerJobState::Running => "running",
            SchedulerJobState::Paused => "paused",
            SchedulerJobState::Completed => "completed",
        }
    }

    pub fn from_str(value: &str) -> Option<Self> {
        match value {
            "scheduled" => Some(Self::Scheduled),
            "running" => Some(Self::Running),
            "paused" => Some(Self::Paused),
            "completed" => Some(Self::Completed),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SchedulerJobStatus {
    Ok,
    Error,
    Skipped,
}

impl SchedulerJobStatus {
    pub fn as_str(&self) -> &'static str {
        match self {
            SchedulerJobStatus::Ok => "ok",
            SchedulerJobStatus::Error => "error",
            SchedulerJobStatus::Skipped => "skipped",
        }
    }

    pub fn from_str(value: &str) -> Option<Self> {
        match value {
            "ok" => Some(Self::Ok),
            "error" => Some(Self::Error),
            "skipped" => Some(Self::Skipped),
            _ => None,
        }
    }
}

impl Default for SchedulerJobState {
    fn default() -> Self {
        Self::Scheduled
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchedulerJobRecord {
    pub id: String,
    pub kind: String,
    pub schedule: serde_json::Value,
    pub interval_secs: i64,
    pub startup_delay_secs: i64,
    pub target: serde_json::Value,
    pub payload: serde_json::Value,
    pub enabled: bool,
    pub state: SchedulerJobState,
    pub last_status: Option<SchedulerJobStatus>,
    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 paused_at: Option<i64>,
    pub completed_at: Option<i64>,
    pub created_at: i64,
    pub updated_at: i64,
}

#[derive(Debug, Clone)]
pub struct SchedulerJobUpsert {
    pub id: String,
    pub kind: String,
    pub schedule: serde_json::Value,
    pub interval_secs: i64,
    pub startup_delay_secs: i64,
    pub target: serde_json::Value,
    pub payload: serde_json::Value,
    pub enabled: bool,
    pub state: SchedulerJobState,
    pub last_status: Option<SchedulerJobStatus>,
    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 paused_at: Option<i64>,
    pub completed_at: Option<i64>,
}
