//! TypeScript 类型定义 — 与 Rust Record 结构体严格对齐

// ============================================================
// 域 ID newtype(纯类型级标记,零运行时开销)
// ============================================================

/** 项目 ID — branded newtype,替代 string */
export type ProjectId = string & { readonly __brand: 'ProjectId' }
/** 任务 ID — branded newtype,替代 string */
export type TaskId = string & { readonly __brand: 'TaskId' }
/** 对话 ID — branded newtype,替代 string */
export type ConvId = string & { readonly __brand: 'ConvId' }
/** 工程/模块 ID — branded newtype,替代 string */
export type ModuleId = string & { readonly __brand: 'ModuleId' }
/** 消息 ID — branded newtype,替代 string */
export type MessageId = string & { readonly __brand: 'MessageId' }

// ============================================================
// 灵感
// ============================================================

// IdeaRecord.status union 类型 — 值集对齐后端 IdeaStatus serde (df-types/src/types.rs:52)
// snake_case: draft | pending_review | approved | rejected | promoted | archived
export type IdeaStatus = 'draft' | 'pending_review' | 'approved' | 'rejected' | 'promoted' | 'archived'

export interface IdeaRecord {
  id: string
  title: string
  description: string
  status: IdeaStatus
  priority: number
  score: number | null
  tags: string | null // JSON 数组字符串
  source: string | null
  promoted_to: string | null
  ai_analysis: string | null
  scores: string | null
  /** 关联灵感 id JSON 数组字符串(对齐后端 related_ids Option<String>),null/空串=无关联 */
  related_ids: string | null
  created_at: string
  updated_at: string
}

export interface CreateIdeaInput {
  title: string
  description?: string
  priority?: number
  tags?: string
  source?: string
}

/**
 * 灵感多条件查询入参(F-260621-02,对齐后端 IdeaQuery)。
 *
 * 所有字段可选;全空 → 后端返回全量(created_at DESC)。
 * - `status`:状态精确匹配(后端 WHERE,取代前端 filter)
 * - `keyword`:title/description LIKE %kw%(后端 LIKE,取代前端 filter)
 * - `order_by`:白名单 created_at/updated_at/priority/status/score(后端白名单校验防注入)
 * - `limit`/`offset`:分页(limit 钳制上限 200)
 */
export interface IdeaQuery {
  status?: string | null
  keyword?: string | null
  order_by?: string | null
  limit?: number | null
  offset?: number | null
}

/**
 * 灵感评估历史记录(后端 list_idea_evaluations 返回)。
 * 每次评估(启发式/LLM/降级)落一行,version 递增,按 version DESC 返回。
 * ai_analysis / scores 为 JSON 字符串(对齐 IdeaRecord 同名字段)。
 */
export interface IdeaEvaluationRecord {
  id: string
  idea_id: string
  version: number
  ai_analysis: string | null
  scores: string | null
  score: number | null
  evaluated_by: string | null
  evaluated_at: string
}

// ============================================================
// 项目
// ============================================================

// ProjectRecord.status union 类型 — 值集对齐后端 ProjectStatus serde (df-types/src/types.rs:90)
// snake_case: planning | in_progress | testing | releasing | completed | paused | cancelled
// 注:前端 constants/dashboard 的 'active' 是 UI 虚拟派生态(非 record 落库值),不进此 union。
export type ProjectStatus =
  | 'planning' | 'in_progress' | 'testing' | 'releasing' | 'completed' | 'paused' | 'cancelled'

export interface ProjectRecord {
  id: ProjectId
  name: string
  description: string
  status: ProjectStatus
  idea_id: string | null
  /** 绑定的本地代码目录绝对路径(null=未绑定) */
  path: string | null
  /** 技术栈 JSON 数组字符串(如 ["rust","vue"],null=未探测) */
  stack: string | null
  created_at: string
  updated_at: string
  /**
   * 最近活跃时间(问题3):COALESCE(project_events 最新事件 created_at, updated_at)。
   * 反映业务活跃(任务/灵感/状态推进等事件),无事件回退 updated_at。
   * 可选(旧后端/回收站等路径不返):消费方需用 ?? updated_at 兜底。
   */
  last_active_at?: string
}

export interface CreateProjectInput {
  name: string
  description?: string
  idea_id?: string
  /** 绑定的本地代码目录(可选) */
  path?: string
  /** 技术栈 JSON 数组字符串(可选,空则后端自动探测) */
  stack?: string
}

/** AI 扫描项目结果(预览用,用户确认后填入) */
export interface AiScanResult {
  /** 项目摘要(空=LLM 未得出,需手填) */
  description: string
  /** 技术栈(规则 ∪ LLM,去重小写) */
  stack: string[]
  /** 项目类型(web/api/cli/library/desktop/mobile/monorepo/other) */
  project_type: string | null
  /** LLM 原始返回(降级时含错误信息) */
  raw: string | null
}

/** 灵感晋升结果（后端 promote_idea 返回） */
export interface PromotionResult {
  idea_id: string
  project_id: ProjectId
  promoted: boolean
  reason: string
}

// ============================================================
// 任务
// ============================================================

// TaskRecord.status union 类型 — 值集对齐后端 TaskStatus serde (df-types/src/types.rs:131)
// snake_case: todo | in_progress | in_review | testing | done | blocked | cancelled
// 注:constants/project.ts 的 mapLegacyStatus 兜底老 DB 旧态(completed/review_ready/merged/abandoned),
// 仅在 taskStatusLabel/taskStatusClass 辅助函数内映射,record.status 本身经后端 is_valid 拦截无旧态。
export type TaskStatus =
  | 'todo' | 'in_progress' | 'in_review' | 'testing' | 'done' | 'blocked' | 'cancelled'

export interface TaskRecord {
  id: TaskId
  project_id: ProjectId
  title: string
  description: string
  status: TaskStatus
  priority: number // 0=critical, 1=high, 2=medium, 3=low
  branch_name: string | null
  assignee: string | null
  workflow_def_id: string | null
  base_branch: string | null
  /** review 退回累计轮数(in_review→in_progress / testing→in_review 各 +1) */
  review_rounds: number
  /**
   * 任务产出 JSON 字符串(决策 a:task 中心,产出跟 task 走)。
   * schema: { text: string, model?: string, usage?: {...}, review?: {
   *   verdict: 'pass'|'fail'|'unknown', summary: string, suggestions: string[], ... } }
   * 旧任务无产出时为 undefined。前端 parsedOutput try/catch 兜底解析。
   */
  output_json?: string
  /** 关联灵感 ID(F-260619-01,1对1 单向,任务→灵感)。未关联时为 undefined。 */
  idea_id?: string
  created_at: string
  updated_at: string
}

export interface CreateTaskInput {
  project_id: ProjectId
  title: string
  description?: string
  priority?: number
  branch_name?: string
  assignee?: string
  /** 关联灵感 ID(1对1 单向,可空)。空字符串视为不关联(与后端一致)。 */
  idea_id?: string
}

/**
 * 任务多条件查询入参(F-260621-02,对齐后端 TaskQuery)。
 *
 * 所有字段可选;全空 → 后端返回全量未删任务(created_at DESC,等价改造前 list_active)。
 * - `project_id`:项目精确匹配(命中 idx_tasks_project_id)
 * - `status`:状态精确匹配(P1 下沉,命中 idx_tasks_status,取代前端 filter)
 * - `priority`:优先级精确匹配(0=critical..3=low)
 * - `assignee`:负责人精确匹配
 * - `keyword`:title/description LIKE %kw%(P2,取代前端 filter)
 * - `order_by`:白名单 created_at/updated_at/priority/status(后端白名单校验防注入),恒 DESC
 * - `limit`/`offset`:分页(limit 钳制上限 500)
 *
 * 注:project_id/priority/assignee/order_by/limit/offset 为基建就绪,当前视图仅用
 * status(P1)+keyword(P2);P3 排序分页 UI 待数据量增长。
 */
export interface TaskQuery {
  project_id?: string | null
  status?: string | null
  priority?: number | null
  assignee?: string | null
  keyword?: string | null
  order_by?: string | null
  limit?: number | null
  offset?: number | null
}

// ============================================================
// 工作流
// ============================================================

// WorkflowRecord.status union 类型 — 值集对齐后端 WorkflowStatus serde (df-types/src/types.rs:195)
// snake_case: pending | running | paused | completed | failed | cancelled
export type WorkflowStatus =
  | 'pending' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled'

export interface WorkflowRecord {
  id: string
  name: string
  dag_json: string
  status: WorkflowStatus
  triggered_by: string | null
  project_id: string | null
  task_id: string | null
  created_at: string
  completed_at: string | null
}

/** 工作流事件载荷（后端 emit 的结构） */
/** 工作流事件类型字面量联合(对应后端 WorkflowEvent serde tag=type rename_all=snake_case，R7收窄防写错 type 字符串) */
export type WorkflowEventType =
  | 'node_started' | 'node_progress' | 'node_output' | 'node_completed' | 'node_failed' | 'node_cancelled'
  | 'workflow_paused' | 'workflow_completed' | 'workflow_failed'
  | 'human_approval_request' | 'human_approval_response'

export interface WorkflowEventPayload {
  execution_id: string
  event: {
    type: WorkflowEventType
    [key: string]: unknown
  }
}

// ============================================================
// 通用
// ============================================================

export type UpdateField = {
  id: string
  field: string
  value: string
}

// ============================================================
// 数据变更联动刷新(AR-11 方案A)
// ============================================================

/**
 * 后端 AI 工具(create/update/delete/restore/purge/bind_directory 等)执行成功后
 * emit 的 "df-data-changed" 事件负载。前端 store listen 后按 entity 调对应 load 刷新列表。
 */
export interface DfDataChangedPayload {
  /** 变更实体:project / task / idea */
  entity: 'project' | 'task' | 'idea'
  /** 变更动作:create / update / delete */
  action: 'create' | 'update' | 'delete'
}

// ============================================================
// AI 聊天
// ============================================================

export interface AiProviderConfig {
  id: string
  name: string
  provider_type: string
  api_key: string
  base_url: string
  default_model: string
  models: string | null
  /** 模型能力配置数组(F-01:4 维度 + 路由控制;DB TEXT 列 JSON 解析,老库可能缺失) */
  model_configs?: ModelConfig[]
  is_default: boolean
  config: string | null
  created_at: string
  updated_at: string
  /** provider 是否进入负载均衡池(F-260614-04c)。false=仅配置存在,不参与主链路由/选池。老库默认 true。 */
  enabled?: boolean
  /** provider 在负载均衡池中的选择权重(0-100,F-260614-04c)。高权重优先被选为主;同权重近似轮询。老库默认 50。 */
  weight?: number
}

// ============================================================
// F-01 模型能力系统(ModelConfig,与 crates/df-ai-core/src/model.rs 严格对齐)
// ============================================================

/** 维度 1 — 模态(模型能接收什么输入)。serde snake_case 字面量。 */
export type Modality = 'text' | 'vision' | 'audio' | 'video'

/** 维度 2 — 能力(模型能做什么)。serde snake_case 字面量。 */
export type Capability = 'tool_use' | 'embedding' | 'code_gen'

/** 维度 3 — 价格分级(成本)。serde snake_case 字面量。'free' 已删(B-260618-05 死档,预设/启发式从不赋值)。 */
export type CostTier = 'low' | 'medium' | 'high'

/** 维度 4 — 智力分级。serde snake_case 字面量。CR-260618-11#3:与 CostTier 同,cost/intel 已从路由硬过滤(B-260618-03)及前端标签(UX-260618-04)去除,字段保留仅 DB 兼容,不再参与路由选模型。 */
export type IntelligenceTier = 'lite' | 'standard' | 'plus' | 'ultra'

/** 探测来源(只读,由后端探测器填充)。serde snake_case 字面量。 */
export type ProbeSource = 'user_set' | 'preset_table' | 'heuristic' | 'default'

/** 单模型完整配置(4 维度 + 路由控制 + 探测元数据)。 */
export interface ModelConfig {
  /** 模型名(如 "glm-4v-flash") */
  model_id: string
  /** 启用/禁用(false=配了但不参与路由) */
  enabled: boolean
  /** 用户自定义别名(可选) */
  label?: string
  /** 模态集合 */
  modalities: Modality[]
  /** 能力集合 */
  capabilities: Capability[]
  /** 价格分级 */
  cost_tier: CostTier
  /** 智力分级 */
  intelligence: IntelligenceTier
  /** 权重(0-100,同能力候选中优先选权重高的) */
  weight: number
  /** 上下文窗口大小(tokens) */
  context_window: number
  /** 探测来源(可选) */
  probe_source?: ProbeSource
}

/**
 * AI 错误分类字面量集(B-260615-42)。
 * 与后端 `commands::ai::ErrorType` 的 serde(rename_all = "snake_case") 严格对齐。
 * 前端消费方 switch 于此常量集做差异化提示(auth 引导填 key / network 提示连接 / 等)。
 */
export type AiErrorType = 'auth' | 'network' | 'timeout' | 'provider_config' | 'unknown'

/**
 * L2 统一状态机 — 对话生命周期状态字面量(对齐后端 ConvState serde rename_all=snake_case,
 * crates/df-ai/.../agentic/conv_state.rs)。5 态:
 * - idle:空闲,可接新请求
 * - generating:生成中(含审批挂起期,审批是 loop 内暂停点非独立态)
 * - stopping:停中(用户已点停止,loop 收尾中,瞬态)
 * - error:出错(用户可重试回 generating)
 * - compressed:压缩中(Generating/Idle 期间瞬态派生,压缩完成回原态)
 *
 * 批4 双轨收口后(2026-06-25):convStates(enum Map)是「会话是否生成中」的唯一真相源,
 * 旧 generatingConvs bool 轨已退役。CONV_STATE_ENABLED=off 或老后端不发 AiConvStateChanged 时,
 * useAiEvents.handleEvent 活跃事件兜底写 setConvState('generating') 作为 enum 写入口
 * (替代旧 bool 轨 add),消费方不再回退 bool 判断。streaming 单值是另一条过渡态
 * (F-09 per-conv streaming 收口前保留),不在本状态机口径内。
 */
export type ConvState = 'idle' | 'generating' | 'stopping' | 'error' | 'compressed'

/** AI 聊天事件（后端 emit 的结构，conversation_id 用于多对话流式路由） */
export type AiChatEvent = ({
  type: 'AiTextDelta'; delta: string
} | {
  type: 'AiToolCallStarted'; id: string; name: string; args: unknown
} | {
  type: 'AiToolCallCompleted'; id: string; result: unknown
} | {
  // AE-2025-04 会话级信任:同会话已批准过同类操作(同工具+同目录)自动放行,前端显示轻量 toast。
  // 不写消息/不动 pending(Started/Completed 仍独立发),仅提示性事件。
  type: 'AiToolAutoApproved'; id: string; tool: string; dir: string
} | {
  // path_auth 审批链阶段3b(统一审批模型):AiApprovalRequired 携带 kind 字段区分
  // 'path'(F-260619-03 Phase B 路径授权挂起,走 once/session/always/deny)vs 'risk'(普通 RiskLevel 审批,
  // 走 approve/reject)。后端阶段3a 未在 wire 上给该事件加 kind(老 path 挂起仍走独立
  // AiDirAuthRequired 事件),前端 useAiEvents 入口处据 event.type 归一打标:risk 类默认 'risk',
  // path 类(AiDirAuthRequired 归一)打 'path'。故此处 kind 为可选(老后端不传时前端默认 'risk')。
  // 开关 df-ai-unified-approval:true=归一进 pendingApprovals 带 kind;false=回退 DirAuthDialog 老链路。
  type: 'AiApprovalRequired'; id: string; name: string; args: unknown; reason: string; diff?: string
  kind?: 'path' | 'risk'
} | {
  type: 'AiApprovalResult'; id: string; approved: boolean
} | {
  // UX-2025-04 / CR-30-2 / 决策 F-260616-07 a1: incomplete 标记流中途失败保文(网络中断),
  // 前端据此差异化展示(如系统提示「⚠ 响应因网络中断不完整」)。正常完成/停止均为 undefined。
  type: 'AiCompleted'; total_tokens: number; prompt_tokens: number; completion_tokens: number; incomplete?: boolean; pinned_goals?: GoalEntry[]
} | {
  type: 'AiError'; error: string; error_type?: AiErrorType
} | {
  // F-260622-02 跨端用户消息同步:远程(miniapp)发来的用户消息,后端 route_send_message
  // 放行后 publish_event 广播。桌面 useAiEvents 收到后补 user 气泡(桌面本地 sendMessage 是
  // 乐观渲染不发此事件)。handleEvent 去重防双气泡(末条已是同 content user 跳过)。
  type: 'AiUserMessage'; message: string
} | {
  type: 'AiAgentRound'; round: number
} | {
  type: 'AiHeartbeat'
} | {
  // F-260616-03: 达 max_iterations 暂停态(后端仍 generating=true),前端展示操作卡询问继续/停止
  type: 'AiMaxRoundsReached'
} | {
  // F-260619-03 Phase B: 路径授权弹窗(LLM 想访问白名单外目录,后端挂起 loop 等用户决定)。
  // 前端弹窗四选项:"本次"(once 执行后清)/"当前会话"(session 切会话清)/"始终放行"(persistent)/"拒绝" → ai_authorize_dir IPC。
  type: 'AiDirAuthRequired'; id: string; tool: string; path: string; dir: string
} | {
  // L1 求助协议(aichat 体验与 agent 能力系统化重构 §2.3,2026-06-21):
  // agent 断路器熔断 / 自省时发,结构化求助(区别于 prompt 教 AI 主动问用户——LLM 不可靠)。
  // 字段对齐后端 AiChatEvent::AiHelpRequired:reason(原因摘要)/context(已试情况)/options(建议选项)。
  // 前端渲染求助卡显 reason + options 按钮供用户选,与 AiApprovalRequired(工具执行前审批)/
  // AiMaxRoundsReached(达 max 被动截断)语义区分——求助=AI 主动「我搞不定」。
  type: 'AiHelpRequired'; reason: string; context: string; options: string[]
} | {
  // L2 统一状态机(批2 1b/1c):ConvState 经 AiChatEvent 推前端,供 status union 消费。
  // conv_state 值为 idle|generating|stopping|error|compressed(snake_case,对齐后端 ConvState serde)。
  // 后端在 conv_state 变化时(入口→generating / reset·drop→idle)emit;conversation_id 标识
  // 哪个会话的状态变了(F-09 多会话并发下前端按 convId 路由)。批4 双轨收口后:CONV_STATE_ENABLED=off
  // 或老后端不发本事件时,useAiEvents.handleEvent 活跃事件兜底写 setConvState('generating') 作为
  // enum 写入口(替代旧 bool 轨 add),消费方不再回退 streaming/generating bool 判断。
  type: 'AiConvStateChanged'; conv_state: ConvState
} | {
  // F-260616-07: 流式调用自动重试提示(前端可在错误气泡内显示「重试 n/m」)
  type: 'AiStreamRetry'; attempt: number; max_attempts: number
} | {
  // F-15 上下文管理生命周期事件(原 useAiContext 独立监听器,现合入统一分发器)
  // 后端在手动/自动压缩、清空上下文时 emit,前端据此复位 loading + toast/刷新。
  type: 'AiCompressing'
} | {
  // 手动压缩成功(IPC compressContext 完成后 emit):带摘要供前端回填 system 消息
  type: 'AiManualCompressed'; summary: string
} | {
  // 自动压缩成功(loop 内超预算压缩):前端静默复位 loading(不弹 toast,不打断流)
  type: 'AiAutoCompressed'; summary: string
} | {
  // 上下文已清空:前端刷新消息列表 + toast 提示
  type: 'AiContextCleared'
}) & {
  conversation_id?: ConvId
}

/**
 * 多模态消息内容片(F-260614-05 Phase 2b 前端类型,对齐后端 df-ai-core ContentPart)。
 *
 * 后端 serde:`#[serde(tag = "type", rename_all = "snake_case")]`,
 * 前端 discriminator 用字面量 `type` 字段('text' | 'image'),与后端 wire 格式严格对齐。
 * Image 片:url / base64 二选一(base64 非空时 url 忽略),media_type 仅 base64 模式必填。
 */
export type ContentPart =
  | { type: 'text'; text: string }
  | {
      type: 'image'
      url?: string | null
      base64?: string | null
      /** base64 模式必填(image/png|jpeg|webp|gif);url 模式可空 */
      media_type?: string | null
      /** 可选 alt(vision 模型/降级文本时用) */
      alt?: string | null
    }

/** AI 消息（前端渲染用，isError 标记错误消息用于差异化样式） */
export interface AiMessage {
  id: MessageId
  role: 'user' | 'assistant' | 'tool' | 'system'
  content: string
  isError?: boolean
  /**
   * 消息上下文状态(F-15 手动上下文管理)。
   *   null | undefined | 'active'  → 正常消息
   *   'archived_segment'            → 清空上下文归档标记(前端折叠成"已归档 N 条"分隔条)
   *   'compressed'                  → 压缩标记(后端不再发给 LLM;前端照常展开)
   *   'truncated'                   → switchConversation 已过滤,前端不渲染
   * 字面量联合:改 status 取值时编译器拦截,避免散布 string cast 失去类型校验。
   */
  status?: 'active' | 'archived_segment' | 'compressed' | 'truncated' | null
  toolCalls?: AiToolCallInfo[]
  /** 生成该消息的 model(仅 assistant 消息,历史消息从 DB 读) */
  model?: string
  /**
   * 多模态内容片(F-260614-05 Phase 2b)。
   * undefined/空=纯文本消息(content 即全部载荷);非空含 Image 片=多模态消息,
   * 用户气泡内渲染 <img>(base64 data URI 或 url)。仅 user 消息有(parts 来自粘贴/拖拽输入)。
   * 历史消息从 DB JSON 反序列化时透传(useAiConversations switchConversation)。
   */
  parts?: ContentPart[]
  /**
   * Input Augmentation:@ mention 区间元数据(仅 user 消息)。
   *
   * 用户选中 @项目/@任务/@灵感/`/技能` 时按选区记 {start,length,kind,refId,label},
   * 随消息透传到后端 ai_chat_send 的 mention_spans 参数(后端 resolve 投影成 Augmentation 注入)。
   * 前端 MessageList 据此精确切区间渲染 chip(替代正则,防误匹配)。
   *
   * undefined/空=无 mention(纯文本消息零回归);历史消息从 DB 反序列化时透传。
   */
  mentionSpans?: MentionSpan[]
  /**
   * Input Augmentation:resolve 后的增强上下文(仅展示用,后端 resolve 的回传或落库快照)。
   *
   * serde 镜像后端 df-types Augmentation(tag=kind, snake_case 变体名)。
   * 当前透传链路仅传 mentionSpans,augmentations 主要用于落库消息回显/调试;前端宽容对待
   * (不强制校验变体字段,未知 kind 忽略,对齐后端「新增变体向后兼容」设计)。
   */
  augmentations?: Augmentation[]
  /**
   * 这一轮对话的 token 用量(仅 assistant 消息,每轮 AiCompleted 时回填)。
   * undefined=未记录(历史消息/未启用 token 显示)。
   */
  tokenUsage?: { prompt: number; completion: number }
  /**
   * 本轮输入 token(消息级持久化,后端 ChatMessage.prompt_tokens 镜像)。
   * reload 时由 switchConversation 映射回 tokenUsage(历史 assistant 消息 token 回显)。
   * 仅 assistant 消息有;undefined=老消息(无此列时 DB 返 NULL)。
   */
  prompt_tokens?: number
  /** 本轮输出 token(语义同 prompt_tokens)。 */
  completion_tokens?: number
  timestamp: number
}

// ============================================================
// Input Augmentation 层类型(@ mention / / skill 统一增强)
// ============================================================
//
// 与后端 crates/df-types/src/augmentation.rs 严格对齐:
// - MentionSpanDto(start/length/kind/refId/label)→ 前端 MentionSpan
// - Augmentation(serde tag=kind, snake_case)→ 前端 Augmentation 宽松镜像
// - SanitizedPath(String newtype, serde transparent = 裸字符串)→ 前端 type SanitizedPath = string
//
// refId 用 camelCase(后端 serde rename = "refId",与前端 TS 风格一致);
// Augmentation 内部字段沿用后端 snake_case(path/project_name 等,与 wire 严格对齐,不做转译)。

/**
 * 用户消息内 mention 区间的元数据(对齐后端 MentionSpanDto)。
 *
 * 前端按 {start, length} 在原文中切出区间并替换为 chip;区间被编辑破坏(长度/内容不再匹配)
 * 时降级为纯文本展示,避免正则误匹配。
 *
 * 注意字段名:refId(camelCase,后端 serde rename)。
 */
export interface MentionSpan {
  /** 区间起点(字符偏移,前端约定,后端仅透传不解释) */
  start: number
  /** 区间长度 */
  length: number
  /** kind 标签:project / task / idea / skill */
  kind: 'project' | 'task' | 'idea' | 'skill'
  /** 引用稳定标识(Project/Task/Idea 为 id,Skill 为 name),前端用于反查 */
  refId: string
  /** chip 展示文本(项目名/任务标题/技能名) */
  label: string
}

/**
 * 脱敏后的文件系统路径(对齐后端 SanitizedPath newtype)。
 *
 * 后端 serde(transparent)在 wire 上即裸字符串,前端用 string 别名即可。
 * Local provider(localhost/127.0.0.1/...)保留全路径;Remote 仅 basename。
 */
export type SanitizedPath = string

/**
 * Augmentation 变体集合字面量(对齐后端 serde tag=kind, rename_all=snake_case)。
 */
export type AugmentationKind = 'project' | 'task' | 'idea' | 'skill'

/**
 * resolve 后的增强上下文(对齐后端 Augmentation)。
 *
 * 宽松镜像:tag=kind 区分变体,各变体字段按需声明(后端新增字段时前端不必同步改,
 * 多余字段 JSON 解析保留不报错)。前端主要读 name/title/path 用于 chip/展示,
 * 需读具体变体字段时用 type narrowing(kind === 'project' 等)。
 */
export type Augmentation = {
  kind: AugmentationKind
  /** 变体特有字段按需读取(用 type narrowing 访问);索引签名容纳后端新增字段 */
  [field: string]: unknown
}

// AiToolCallInfo.status union 类型 — 前端构建(后端无对应 struct,经 audit log/stream event 组装)。
// 值集核验:grep src/composables/ai + src/components 实际使用点 = {running,pending_approval,completed,rejected}。
// 前端为权威源(无后端 enum 约束),保持现状仅抽 alias 便于复用。
export type AiToolCallStatus = 'running' | 'pending_approval' | 'completed' | 'rejected'

/** 工具调用信息 */
export interface AiToolCallInfo {
  id: string
  name: string
  args: unknown
  status: AiToolCallStatus
  result?: unknown
  /** 审批风险说明（AiApprovalRequired 时填充） */
  reason?: string
  /** AE-2025-03：write_file 行级 unified diff（旧文件 vs 新内容），审批卡即时预览。
   *  旧文件不存在（新建）或非 write_file 为 undefined，前端回退显新 content。 */
  diff?: string
  /**
   * path_auth 审批链阶段3b(统一审批模型):审批类型,区分两类挂起。
   * - 'path'(F-260619-03 Phase B 路径授权挂起):ToolCard 显 once/session/always/deny 四选项,
   *   调 aiApi.authorizeDir(once 写 once 层单次执行后清 / session 写会话临时 / always 写持久白名单 / deny 工具返 Err)。
   * - 'risk'(普通 RiskLevel 审批,Med/High 风险工具):ToolCard 显 approve/reject 两选项,
   *   调 aiApi.approve(一次性)。
   * undefined = 未进 pending_approval 态(非挂起)或老后端 risk 类(默认 'risk')。
   * 开关 df-ai-unified-approval 控制 path 类是否归一进 pendingApprovals 带此字段。
   */
  kind?: 'path' | 'risk'
  /**
   * path_auth 审批链阶段3b:'path' 类挂起携带的目录信息(规范化后的待授权目录)。
   * AiDirAuthRequired 归一为 pendingApprovals 项时透传,ToolCard 显提示"LLM 想访问 X 目录"。
   * 'risk' 类为 undefined。
   */
  dir?: string
  /** path_auth 审批链阶段3b:'path' 类挂起携带的原始路径(工具调用参数中的 path)。
   *  ToolCard 审批提示文案展示用(LLM 想访问 path,父目录为 dir)。'risk' 类为 undefined。 */
  path?: string
}

/** 对话列表摘要 */
export interface AiConversationSummary {
  id: ConvId
  title: string | null
  provider_id: string | null
  model: string | null
  pinned_goals?: GoalEntry[]
  archived: boolean
  pinned?: boolean
  prompt_tokens?: number | null
  completion_tokens?: number | null
  created_at: string
  updated_at: string
}

/** G1 目标钉扎:单条目标记录(含状态追踪) */
export interface GoalEntry {
  text: string
  /** "active" | "completed" */
  status: 'active' | 'completed'
}

/** 审批选择类型(F-260615-01: single=单选默认,multiple=多选) */
export type ApprovalSelectType = 'single' | 'multiple'

/** 人工审批请求 */
export interface HumanApprovalRequest {
  execution_id: string
  node_id: string
  title: string
  description: string
  options: string[]
  /** F-260615-01: 缺省 single(向后兼容),multiple 时允许多选 */
  select_type?: ApprovalSelectType
}

/** 人工审批响应 */
export interface HumanApprovalResponse {
  execution_id: string
  node_id: string
  decision: string
  /** F-260615-01: 多选结果(single 时长度=1,multiple 时长度≥1) */
  decisions?: string[]
  comment?: string
}

/** 切换对话返回（含 messages JSON） */
export interface AiConversationDetail {
  id: ConvId
  title: string | null
  messages: string  // JSON string of ChatMessage[]
  /** 生成中返回 true(后端 ai_conversation_switch 在 generating 时置)，前端据此禁编辑(FR-C5) */
  readonly?: boolean
}

/** 技能信息（本机 Claude skill，供 `/` 联想 + 注入） */
export interface SkillInfo {
  name: string
  description: string
  argument_hint?: string
  /** skill | command | plugin */
  source: string
  /** SKILL.md 绝对路径（后端注入时读全文） */
  path: string
}

// ============================================================
// 知识库
// ============================================================

/** 知识条目（与 Rust KnowledgeRecord 严格对齐） */
export interface KnowledgeRecord {
  id: string
  kind: string // review_rule | prompt_template | pitfall | architecture_pattern | diagnosis | deployment_note | workflow_optimization
  title: string
  content: string
  tags: string | null // JSON 数组字符串
  status: string // candidate | pending_review | published | archived
  confidence: string | null // high | medium | low
  reuse_count: number
  verified: boolean
  source_project: string | null
  source_ref: string | null
  /** AI 提炼判断依据("为何值得沉淀"),手动录入为 null */
  reasoning: string | null
  created_at: string
  updated_at: string
}

/** 创建知识入参 */
export interface CreateKnowledgeInput {
  kind: string
  title: string
  content: string
  tags?: string
  source_project?: string
  source_ref?: string
  confidence?: string
}

/** 检索知识入参 */
export interface KnowledgeSearchInput {
  query: string
  kind?: string
  limit?: number
}

/** 知识生命线事件记录(产生/审核/引用/归档审计) */
export interface KnowledgeEventRecord {
  id: string
  knowledge_id: string
  /** created | extracted | status_changed | referenced */
  event_type: string
  source_ref: string | null
  /** JSON 字符串,内容因 event_type 而异(见后端 KnowledgeTimeline) */
  context_json: string | null
  timestamp: string
}

/** 知识详情聚合负载(基本信息 + 全部生命线事件) */
export interface KnowledgeDetailPayload {
  knowledge: KnowledgeRecord
  events: KnowledgeEventRecord[]
}

/** 编辑知识入参(部分更新,仅传需改字段) */
export interface UpdateKnowledgeInput {
  title?: string
  content?: string
  tags?: string
  confidence?: string
  reasoning?: string
}

/** 知识库行为配置（提取 + 注入 + 向量检索） */
export interface KnowledgeConfig {
  auto_extract: boolean
  trigger_mode: 'on_complete' | 'manual_only'
  min_messages: number
  auto_inject: boolean
  /** 语义检索(向量)开关,默认 false——关闭时纯 LIKE 零外部依赖 */
  vector_enabled: boolean
  /** embedding 用的 provider id(仅 openai_compat 类型) */
  embedding_provider_id: string | null
  /** embedding 模型名(如 embedding-3) */
  embedding_model: string | null
}

// ============================================================
// 多 Agent 并行执行(Plan/SubTask/Conflict)
// ============================================================

/** Plan 执行状态 */
export type PlanStatus = 'planning' | 'executing' | 'merging' | 'done' | 'error'

/** SubTask 执行状态 */
export type SubTaskStatus = 'pending' | 'running' | 'done' | 'error'

/** 冲突解决状态 */
export type ConflictResolution = 'pending' | 'a' | 'b' | 'merged' | 'manual'

/** 冲突类型 */
export type ConflictType = 'file' | 'semantic'

/** Plan 记录 */
export interface PlanRecord {
  id: string
  conversation_id: string
  user_message_id: string | null
  status: PlanStatus
  subtask_count: number
  created_at: string
  completed_at: string | null
}

/** SubTask 记录 */
export interface SubTaskRecord {
  id: string
  plan_id: string
  persona_id: string | null
  intent: string
  status: SubTaskStatus
  layer: number
  /** 依赖的 SubTask id 列表(JSON 数组字符串,需 parse) */
  deps: string | null
  /** Git worktree 分支名(null=非 Git 工程降级串行) */
  branch: string | null
  created_at: string
  completed_at: string | null
}

/** 冲突记录 */
export interface ConflictRecord {
  id: string
  plan_id: string
  file_path: string
  conflict_type: ConflictType
  subtask_a: string | null
  subtask_b: string | null
  diff_a: string | null
  diff_b: string | null
  resolution: ConflictResolution
  resolved_by: 'reviewer' | 'user' | null
  created_at: string
  resolved_at: string | null
}

/** 冲突信息(AiMergeCompleted 事件载荷) */
export interface ConflictInfo {
  id: string
  file_path: string
  conflict_type: ConflictType
  subtask_a: string | null
  subtask_b: string | null
  diff_a?: string | null
  diff_b?: string | null
}
