//! 数据模型定义 — 与数据库表对应的 Rust 结构体

use df_ai_core::model::{deserialize_model_configs, ModelConfig};
use serde::{Deserialize, Serialize};

// ============================================================
// 想法相关模型
// ============================================================

/// 想法记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IdeaRecord {
    pub id: String,
    pub title: String,
    pub description: String,
    pub status: String,
    pub priority: i32,
    pub score: Option<f64>,
    pub tags: Option<String>, // JSON 数组
    pub source: Option<String>,
    pub promoted_to: Option<String>,   // 晋升后的 project_id
    pub ai_analysis: Option<String>,   // AI 分析结果 JSON
    pub scores: Option<String>,        // 多维评分 JSON (feasibility/impact/urgency/overall)
    pub created_at: String,
    pub updated_at: String,
}

// ============================================================
// 项目相关模型
// ============================================================

/// 项目记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectRecord {
    pub id: String,
    pub name: String,
    pub description: String,
    pub status: String,
    pub idea_id: Option<String>,
    /// 绑定的本地代码目录(绝对路径,可空=未绑定,第二步导入历史项目时复用)
    pub path: Option<String>,
    /// 技术栈 JSON 数组字符串(如 ["rust","vue","tauri"],由探测填充,可空)
    pub stack: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

// ============================================================
// 任务相关模型
// ============================================================

/// 任务记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskRecord {
    pub id: String,
    pub project_id: String,
    pub title: String,
    pub description: String,
    pub status: String,
    pub priority: i32,
    pub branch_name: Option<String>,
    pub assignee: Option<String>,
    pub workflow_def_id: Option<String>, // 关联的工作流定义 ID
    pub base_branch: Option<String>,     // 基础分支
    /// review 退回累计轮数(in_review→in_progress / testing→in_review 时 +1,
    /// 由 advance_task 原子写入,见 df-nodes::task_advance_node)。
    /// #[serde(default)] 兼容旧前端无该字段的 JSON(老任务记录默认 0)。
    #[serde(default)]
    pub review_rounds: i32,
    /// 任务产出 JSON 字符串(AiNode 自审闭环,决策 a:task 中心,产出跟 task 走)。
    ///
    /// 三方读写约定:ai_execute 写产出 / ai_self_review 读产出做自审 / human_review 展示产出对象。
    /// 经通用 update_field 写白名单(非 status 那种状态机收口字段),TEXT NULL 向后兼容。
    /// #[serde(skip_serializing_if)] 无产出不序列化(省前端字段空值),#[serde(default)] 兼容旧 JSON。
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    pub output_json: Option<String>,
    pub created_at: String,
    pub updated_at: String,
}

/// 分支记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BranchRecord {
    pub id: String,
    pub project_id: String,
    pub task_id: Option<String>,
    pub name: String,
    pub base: String,
    pub status: String,
    pub created_at: String,
    pub updated_at: String,
    pub merged_at: Option<String>,
}

/// 发布记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReleaseRecord {
    pub id: String,
    pub project_id: String,
    pub version: String,
    pub status: String,
    pub task_ids: String, // JSON 数组
    pub changelog: Option<String>,
    pub created_at: String,
    pub released_at: Option<String>,
}

// ============================================================
// 工作流相关模型
// ============================================================

/// 工作流执行记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowRecord {
    pub id: String,
    pub name: String,
    pub dag_json: String, // DAG 的 JSON 序列化
    pub status: String,
    pub triggered_by: Option<String>,
    pub project_id: Option<String>, // 关联项目 ID
    pub task_id: Option<String>,    // 关联任务 ID
    pub created_at: String,
    pub completed_at: Option<String>,
}

/// 节点执行记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeExecutionRecord {
    pub id: String,
    pub workflow_id: String,
    pub node_id: String,
    pub node_type: String,
    pub status: String,
    pub input_json: Option<String>,
    pub output_json: Option<String>,
    pub error_message: Option<String>,
    pub started_at: Option<String>,
    pub completed_at: Option<String>,
}

// ============================================================
// AI 相关模型 (V3)
// ============================================================

/// AI 提供商配置记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AiProviderRecord {
    pub id: String,
    pub name: String,
    pub provider_type: String,
    pub api_key: String,
    pub base_url: String,
    pub default_model: String,
    pub models: Option<String>,       // JSON array of model names
    /// 模型能力配置数组(F-01 阶段1,4 维度 + 路由控制)。
    /// DB TEXT 列存 JSON 字符串,from_row 经 deserialize_model_configs 解析。
    /// 向后兼容:老库 NULL/空/老字符串数组 → 空 Vec 或转默认 ModelConfig。default_model 保留过渡。
    #[serde(default, deserialize_with = "deserialize_model_configs")]
    pub model_configs: Vec<ModelConfig>,
    pub is_default: bool,
    pub config: Option<String>,       // JSON extra config
    pub created_at: String,
    pub updated_at: String,
    /// provider 是否进入负载均衡池(F-260614-04)。false = 仅作为配置存在,不参与主链路由/选池。
    /// 老库迁移默认 1(单 provider 路径零变化)。
    #[serde(default = "default_enabled")]
    pub enabled: bool,
    /// provider 在负载均衡池中的选择权重(0-100,F-260614-04)。高权重优先被选为主;
    /// 同权重时退化近似轮询。老库迁移默认 50。
    #[serde(default = "default_weight")]
    pub weight: u32,
}

/// AiProviderRecord.enabled 的 serde 默认(true)。老库/缺字段 JSON → enabled。
fn default_enabled() -> bool {
    true
}

/// AiProviderRecord.weight 的 serde 默认(50)。老库/缺字段 JSON → 50。
fn default_weight() -> u32 {
    50
}

/// AI 对话记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AiConversationRecord {
    pub id: String,
    pub title: Option<String>,
    pub messages: String,             // JSON array of ChatMessage
    pub provider_id: Option<String>,
    pub model: Option<String>,
    pub models: Option<String>,             // 用过的所有 model(JSON 数组字符串,去重)
    pub archived: bool,                 // 是否归档(侧栏折叠展示)
    pub pinned: bool,                   // 是否置顶(排序置前;UX-17)
    pub prompt_tokens: Option<i64>,         // 输入 token 累计(流式 usage 落库)
    pub completion_tokens: Option<i64>,     // 输出 token 累计(流式 usage 落库)
    pub created_at: String,
    pub updated_at: String,
}

/// AI 工具执行审计记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AiToolExecutionRecord {
    pub id: String,
    pub conversation_id: Option<String>,
    pub tool_call_id: String,
    pub tool_name: String,
    pub arguments: String,
    pub result: Option<String>,
    pub status: String,               // pending/approved/rejected/executing/completed/failed
    pub risk_level: String,           // low/medium/high
    pub requested_at: String,
    pub executed_at: Option<String>,
    pub decided_by: Option<String>,   // human/auto
}

// ============================================================
// 知识库模型 (V7)
// ============================================================

/// 知识条目记录(经验沉淀基本单元,共享记忆层)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KnowledgeRecord {
    pub id: String,
    pub kind: String,                  // KnowledgeKind snake_case(7 种)
    pub title: String,
    pub content: String,
    pub tags: Option<String>,          // JSON 数组字符串
    pub status: String,                // candidate|pending_review|published|archived
    pub confidence: Option<String>,    // high|medium|low(AI 提炼自评,可空)
    pub reuse_count: i32,              // 唯一客观排序信号
    pub verified: bool,                // 发布审核时一次性人工标
    pub source_project: Option<String>, // 来源项目(仅溯源不过滤)
    pub source_ref: Option<String>,    // 来源实体引用(如 conv:{id})
    pub reasoning: Option<String>,     // AI 提炼判断依据("为何值得沉淀"),手动录入为 None
    pub created_at: String,
    pub updated_at: String,
}

/// 知识生命线事件记录(追加型审计:产生/审核/引用/归档)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KnowledgeEventRecord {
    pub id: String,
    pub knowledge_id: String,
    pub event_type: String,            // created | extracted | status_changed | referenced | archived
    pub source_ref: Option<String>,    // 触发来源: conv:{id} / manual / system
    pub context_json: Option<String>,  // JSON: 因 event_type 而异
    pub timestamp: String,
}
