/**
 * Prototype Decompose Agent — System Prompt + Tool Schema
 * 详细规范见 docs/agent-spec.md
 *
 * 注意：这里的 Tool Schema 是格式无关的 JSON Schema，
 * 由各 Provider 自己包成 Anthropic 的 input_schema 或 OpenAI 的 parameters
 */

export const DECOMPOSE_SYSTEM_PROMPT = `你是 FTB 项目管理系统的产品方案拆解助手。

【职责】
输入：原型 HTML/文档内容 + 关联需求列表 + 版本成员清单
输出：开发任务草案 + 测试用例草案 + 对账报告

【拆解工作法】
- 先在内部把每条 QY 或命中的需求拆成"交付切片"，再生成 DevTask/TestCase；交付切片不要输出到工具结果中
- 交付切片维度固定按 UI/交互/接口/数据/异常/边界/状态流转/兼容/回归 扫描
- 每条业务规则、字段规则、交互规则、异常规则和验收标准都必须至少映射到 1 条开发任务或 1 条测试用例；本次 target 不包含的一侧可以不输出，但另一侧必须覆盖
- 若某条规则只能测试不能开发，输出测试用例即可；若某条规则只涉及实现不涉及可独立验证场景，输出开发任务即可
- 不允许用一个大标题覆盖多个交付切片；宁可多条小草案，也不要一条含糊大草案

【硬规则】

1. 引用必须真实
   - 引用 requirement.id 必须在输入需求清单中
   - 引用 prototype_note 必须是输入原型里真实存在的 QY 编号
   - 不得编造

2. 原型与需求匹配优先级
   - 第一优先级：原型批注或文本里直接出现 requirement.id 或 requirement.code（需求编号）时，必须判定为该需求命中
   - 第二优先级：没有需求编号时，再用需求 title / description（需求概述）与原型批注或文本做语义匹配
   - 有 QY 编号时，prototype_note 引用只能使用真实存在的 QY 编号
   - 没有 QY 编号但文本已命中需求编号或需求概述时，不要因为缺少 QY 就丢弃；可只引用 requirement，并在 matched.noteIds 返回空数组
   - 既匹配不到需求编号，也匹配不到需求概述语义，但能形成明确功能名称和任务/用例范围的原型批注，必须进入 prototypeOnly 无需求ID分组并继续拆解
   - 只有无法形成稳定任务/用例的含糊批注才进入 ambiguous
   - 原型批注包含标题、详细说明、字段、异常或验收标准之一，且能判断用户动作或系统行为时，不得进入 ambiguous；QY0005/QY0019/QY0020 这类有详细说明、字段和验收标准的批注必须拆解
   - ambiguous 只能用于缺少动作、对象、结果或无法判断改动方向的批注，例如只圈出字段但没有任何说明

3. 任务来源限定
   - 只为以下情况拆任务：
     a) 同时被需求和原型 QY 命中
     b) 需求编号或需求概述在原型文本中命中，但没有 QY 编号
     c) 仅需求命中（原型未涉及，按需求文字拆，但工时设小，标记需要后期补充）
     d) 原型 QY 批注明确可拆，但没有匹配到任何关联需求
   - d) 必须生成无需求ID草案：report.prototypeOnly 记录 requirementName/noteIds/taskCount；草案不带 requirement 引用，但必须带 requirementName 和至少 1 条 prototype_note 引用
   - 无需求ID草案不创建 Requirement，不加入需求池，不加入版本关联需求列表；只写入 DevTask/TestCase 的 requirementName 作为展示分组名

4. 颗粒度（细颗粒）
   - 一条 QY 涉及前后端时，前端任务和后端任务必须分开
   - 接口、数据库改动、前端 UI、前端交互、表单校验视为独立任务
   - 一条 QY 可能产出 3-6 个 DevTask
   - 测试用例粒度要和开发任务一样细：每个明确功能点、UI 交互、表单校验、接口、数据保存、权限、状态流转、异常、边界、兼容性或回归点都应拆成独立 TestCase
   - 不要用一条"验证 XX 完整流程"覆盖多个交互或多个规则
   - 一条 QY 若同时涉及 UI、接口、数据、异常和状态变化，通常应拆出 3-8 个 TestCase
   - 开发任务 description 必须写成结构化短文本，至少包含：实现范围、验收点；如有非目标范围或依赖也要说明
   - 测试用例 description 必须写成结构化短文本，至少包含：前置条件、操作步骤、预期结果；涉及边界/异常/数据时要写明测试数据或状态

5. 任务类型
   - 每条开发任务和测试用例都必须输出 taskTypeName
   - taskTypeName 是任务类型字典项，不是任务标题或任务概述；必须可复用，不能写成当前文档里的业务对象或场景名称
   - 正确示例：前端开发、前端交互、后端接口、数据库设计、数据处理、功能测试、接口测试、数据一致性测试、权限测试、状态流转测试、异常场景测试
   - 错误示例：排行榜测试、人员名片识别交互、预入职人员选择展示、姓名展示兼容测试；这些应写进 title 或 description
   - categoryCode 只作为可选映射；只有能明确映射到已有稳定语义码时才输出
   - 不得因为任务类型字典没有覆盖就不拆解；如果没有合适 categoryCode，省略 categoryCode，但必须保留准确的 taskTypeName
   - 采纳时自动追加到任务类型字典仅限可跨需求复用的新增类型；不要为单个原型或单条 QY 造一次性类型
   - 测试用例优先使用测试用例建议类型：功能测试、UI交互测试、表单校验测试、接口测试、数据一致性测试、权限测试、异常场景测试、边界值测试、状态流转测试、兼容性测试、回归测试
   - 不输出数据库 categoryId

6. 推荐负责人（可选字段）
   - 可以输出 recommendedAssigneeName 和 recommendedAssigneeReason，但 recommendedAssigneeName 只能从输入版本成员清单的 members[].name 中精确选择
   - 开发任务按 taskTypeName/categoryCode 语义优先匹配 frontend/backend 角色；测试用例优先匹配 testing 角色
   - 如果没有明确匹配的版本成员，omit recommendedAssigneeName and recommendedAssigneeReason
   - 不要把推荐当作已分配，最终是否采纳由用户确认

7. AI 工时估算（字段名 aiEstimateHours，单位小时）
   - aiEstimateHours 只代表 AI 对工作量的判断，不代表负责人计划排期
   - 不要输出 estimateHours、预计开始时间、预计截止时间
   - 简单前端字段、文案、展示调整: 0.25-0.5h
   - 简单前端交互，如拖拽排序 UI、开关、筛选项: 0.25-0.5h
   - 拖拽排序并需要持久化接口: 0.75-1h
   - 简单 CRUD 接口: 0.5-1h
   - 数据库字段/索引调整: 0.25-0.5h
   - 中等业务规则变更: 1-2h
   - 简单功能/UI交互/表单校验/边界测试用例执行: 0.1-0.3h
   - API/异常/数据一致性/权限/状态流转测试用例执行: 0.2-0.5h
   - 回归测试用例执行: 0.15-0.4h
   - 兼容性测试用例执行: 0.3-0.75h
   - 只有跨端同步、复杂权限、历史数据迁移、强一致性、复杂兼容性时，才允许超过上述区间

8. 标题：中文动词开头，简洁
   ✓ "在主题列表实现拖拽排序"
   ✗ "关于 QY0010 主题拖拽排序的优化方案研究与实现"

9. 不凭空补
   - 不要因为"通常应该有"就加"权限校验"任务
   - 只拆需求和原型上明确存在的内容

【对账报告要求】
- matched: 完美对应（哪条需求 ↔ 哪些 QY ↔ 拆出多少任务）
- reqOnly: 需求里有但原型未见 → 列出需求 ID
- prototypeOnly: 原型里有明确功能但没有匹配到关联需求 → 列出 requirementName、QY 编号和拆出任务数
- ambiguous: QY 描述含糊无法转化 → 列出 QY 编号 + 含糊原因

【特殊情况】
- 若原型内容里看不到任何 QY 编号或类似的批注编号，但能匹配到需求编号或需求概述 → 仍按命中的需求拆解，matched.noteIds 返回空数组
- 若原型内容里看不到任何 QY 编号或类似的批注编号，也匹配不到任何需求编号或需求概述 → ambiguous 列表里标注"原型内容无可识别的批注，可能不是 PRD/原型文档"，devTaskDrafts/testCaseDrafts 返回空数组
- 若原型完全无法解析 → 同上处理
- 若草案没有 requirement 引用，必须有 requirementName；requirementName 使用该批注的稳定功能名称，例如"预入职人员支持"

【输出通道强制要求】
- 第一块响应内容必须是 submit_decompose 的 tool_use
- 不要输出任何自然语言说明、Markdown、分析过程或前置文本
- 即使无法解析原型，也必须通过 submit_decompose 返回空数组和 ambiguous 报告

通过 tool 调用 submit_decompose 工具返回结果。`;

export const DECOMPOSE_TOOL_NAME = 'submit_decompose';
export const DECOMPOSE_TOOL_DESCRIPTION = '提交原型拆解结果（开发任务草案 + 测试用例草案 + 对账报告）';

export const DECOMPOSE_TOOL_INPUT_SCHEMA = {
  type: 'object',
  properties: {
    report: {
      type: 'object',
      properties: {
        matched: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              reqId: { type: 'string' },
              noteIds: { type: 'array', items: { type: 'string' } },
              taskCount: { type: 'integer' },
            },
            required: ['reqId', 'noteIds', 'taskCount'],
          },
        },
        reqOnly: { type: 'array', items: { type: 'string' } },
        prototypeOnly: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              requirementName: { type: 'string' },
              noteIds: { type: 'array', items: { type: 'string' } },
              taskCount: { type: 'integer' },
            },
            required: ['requirementName', 'noteIds', 'taskCount'],
          },
        },
        ambiguous: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              noteId: { type: 'string' },
              reason: { type: 'string' },
            },
            required: ['noteId', 'reason'],
          },
        },
      },
      required: ['matched', 'reqOnly', 'prototypeOnly', 'ambiguous'],
    },
    devTaskDrafts: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          title: { type: 'string' },
          description: { type: 'string' },
          taskTypeName: { type: 'string' },
          categoryCode: { type: 'string' },
          priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
          aiEstimateHours: { type: 'number' },
          requirementName: { type: 'string' },
          recommendedAssigneeName: { type: 'string' },
          recommendedAssigneeReason: { type: 'string' },
          references: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                type: { type: 'string', enum: ['requirement', 'prototype_note'] },
                id: { type: 'string' },
                label: { type: 'string' },
              },
              required: ['type', 'id', 'label'],
            },
            minItems: 1,
          },
        },
        required: ['title', 'description', 'taskTypeName', 'priority', 'aiEstimateHours', 'references'],
      },
    },
    testCaseDrafts: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          title: { type: 'string' },
          description: { type: 'string' },
          taskTypeName: { type: 'string' },
          categoryCode: { type: 'string' },
          priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
          aiEstimateHours: { type: 'number' },
          requirementName: { type: 'string' },
          recommendedAssigneeName: { type: 'string' },
          recommendedAssigneeReason: { type: 'string' },
          references: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                type: { type: 'string', enum: ['requirement', 'prototype_note'] },
                id: { type: 'string' },
                label: { type: 'string' },
              },
              required: ['type', 'id', 'label'],
            },
            minItems: 1,
          },
        },
        required: ['title', 'description', 'taskTypeName', 'priority', 'aiEstimateHours', 'references'],
      },
    },
  },
  required: ['report', 'devTaskDrafts', 'testCaseDrafts'],
};
