#!/usr/bin/env node
/**
 * 将 MVFrame 的 Codex 规则写入宿主项目 AGENTS.md。
 *
 * Codex 不会自动读取 Cursor 的 `.cursor/rules/*.mdc`，因此宿主项目需要
 * `AGENTS.md` 明确告诉 Codex：优先使用 MVFrame 全局组件、全局方法和样式工具类。
 *
 * 用法：
 *   node path/to/mvframe/scripts/install-codex-agents.js
 *   node path/to/mvframe/scripts/install-codex-agents.js /abs/path/to/your-project
 *
 * 环境变量（可选）：
 *   MVFRAME_CODEX_AGENTS_OUT=/path/to/project  等价于第一个参数
 */

const fs = require("fs");
const path = require("path");

const BEGIN = "<!-- MVFRAME-CODEX-RULES:BEGIN -->";
const END = "<!-- MVFRAME-CODEX-RULES:END -->";
const STYLE_RULES_FILE = path.join(__dirname, "..", ".cursor", "rules", "style-system.mdc");

function stripFrontmatter(markdown) {
  if (!markdown.startsWith("---")) {
    return markdown;
  }
  const end = markdown.indexOf("\n---", 3);
  if (end < 0) {
    return markdown;
  }
  return markdown.slice(end + 4).replace(/^\s*\n/, "");
}

function shiftMarkdownHeadings(markdown, level = 1) {
  return markdown.replace(/^(#{1,6})\s+/gm, (_all, hashes) => {
    const nextLevel = Math.min(6, hashes.length + level);
    return `${"#".repeat(nextLevel)} `;
  });
}

function getSharedStyleRulesForCodex() {
  const raw = fs.readFileSync(STYLE_RULES_FILE, "utf8");
  const withoutFrontmatter = stripFrontmatter(raw).trim();
  const withoutRootTitle = withoutFrontmatter.replace(/^#\s+mvframe\s+样式系统\s*\n*/i, "");
  return shiftMarkdownHeadings(withoutRootTitle, 1).trim();
}

function renderCodexAgentsSection() {
  return `${BEGIN}
# MVFrame Codex 规则

本项目使用 MVFrame。在该宿主项目中编辑 Vue、JS、TS、SCSS 或 CSS 时，新增本地实现前，优先检查并复用框架已有的全局能力。

## 全局组件

- 模板内优先直接使用 MVFrame 全局组件，不要重复本地 import：\`Frame\`、\`Page\`、\`Table\`、\`Form\`、\`Input\`、\`InputNumber\`、\`Textarea\`、\`Mention\`、\`Select\`、\`SelectV2\`、\`Tabs\`、\`BtnGroup\`、\`Icon\`、\`Loading\`、\`Drawer\`、\`DrawerArea\`、\`Login\`、\`Lang\`。
- 除非 MVFrame 组件确实无法表达该交互，否则不要用原生 DOM、\`el-*\` 组合或第三方组件去重造等价控件。
- 遇到分段切换、单选按钮组、登录表单、页面外壳、表格、抽屉、加载遮罩、框架导航等场景，先检查 MVFrame 组件是否已经覆盖。

## 全局样式工具类

${getSharedStyleRulesForCodex()}

## 全局方法

- 优先使用 MVFrame 全局方法，不要重复 import 或本地封装等价 helper：\`globalThis.$d\`、\`$l\`、\`$fa\`、\`$fu\`、\`$pm\`、\`$db\`、\`$copy\`、\`$deepClone\`、\`$getLang\`、\`$getImg\`、\`$sc\`、\`$c.info\`。
- 在模板里，如果这些方法已经通过 Vue globalProperties 注入，直接调用即可。
- 对普通 JS 模块，优先使用 \`globalThis.$xxx\`；只有确实需要显式 import 时，再使用 MVFrame 的子路径导出。
- 多语言变量统一使用 \`$l("helloUser", { name: userName })\`，字典文案写作 \`"Hello {name}"\`；变量名仅使用字母、数字、下划线、点、短横线或 \`$\`，缺失变量会保留原 \`{name}\` 占位。

## 路由、Store 与 Maps

- 路由跳转优先使用 route \`name\`，不要优先写死 \`path\`。
- 使用项目已经接好的 MVFrame store factory 模式：组件内用 \`inject("store")\`，setup 代码或守卫里用 \`import { store, pinia } from "mvframe/store"\`。
- 涉及 MVFrame maps / i18n maps 时，优先使用 \`useMap\`、\`getMaps\`、\`patchMaps\`、\`mapLang\`、\`mapLangPath\`，来源为 \`mvframe/maps\`。

## 编辑检查清单

- 新增结构前，先判断是否已有合适的 MVFrame 全局组件。
- 新增 CSS 前，先判断是否已有合适的 MVFrame 工具类。
- 引入新的 helper 库前，先判断 MVFrame 是否已经提供等价全局方法。
- 如果最终仍需新增本地 CSS 或 helper，保持小而专，限定在当前组件范围内。

## 完成后通知

- 每次完成一个开发任务后，都要在宿主项目根目录发送一条完成通知：\`yarn exec mvframe-notify --once --message "<标题>\n<正文>"\`。
- 通知内容必须使用中文。
- 标题写为“当前对话请求内容”的简短概括，单独一行，不要展开成长句。
- 正文写为本次执行反馈的简短概括；需要包含本次实际完成了什么、改到了哪里、当前结果或验证结论（如果已有）。
- 如果本次明显执行了多个动作，或完成了彼此不同的内容，正文按 \`1.\`、\`2.\`、\`3.\` 依次编号；每个序号之间必须换行成独立段落，不要挤在同一段里。
- 文案保持简短、可投递、可扫读，不写寒暄，不写无信息量套话。
- 如果缺少 \`.env.mvframe-notify\`、钉钉 notify 未配置，或命令执行失败，不要伪造成功；需要在最终回复里明确说明通知未发送成功。
${END}
`;
}

function upsertCodexAgents(projectRoot) {
  const targetRoot = path.resolve(projectRoot);
  const fp = path.join(targetRoot, "AGENTS.md");
  const section = renderCodexAgentsSection();

  let next;
  if (fs.existsSync(fp)) {
    const current = fs.readFileSync(fp, "utf8");
    const start = current.indexOf(BEGIN);
    const end = current.indexOf(END);
    if (start >= 0 && end >= start) {
      next = `${current.slice(0, start)}${section}${current.slice(end + END.length)}`;
    } else {
      const trimmed = current.replace(/\s*$/, "");
      next = `${trimmed}\n\n${section}`;
    }
  } else {
    next = `${section}`;
  }

  fs.writeFileSync(fp, next.endsWith("\n") ? next : `${next}\n`, "utf8");
  console.log("[mvframe] 已写入 Codex 规则：");
  console.log("  ", fp);
}

function main() {
  const argPath = process.argv.find((a, i) => i >= 2 && !a.startsWith("--"));
  const projectRoot = path.resolve(
    process.env.MVFRAME_CODEX_AGENTS_OUT || argPath || process.cwd(),
  );

  if (!fs.existsSync(projectRoot)) {
    console.error("[mvframe] 目录不存在:", projectRoot);
    process.exit(1);
  }

  upsertCodexAgents(projectRoot);
  console.log("[mvframe] Codex 打开该项目后会读取 AGENTS.md，并优先使用 MVFrame 全局能力。");
}

if (require.main === module) {
  main();
}

module.exports = {
  upsertCodexAgents,
  renderCodexAgentsSection,
};
