import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";

const root = resolve(import.meta.dir, "../..");
const skill = readFileSync(resolve(root, ".agents/skills/unidesk-cicd/SKILL.md"), "utf8");
const reference = readFileSync(
  resolve(root, ".agents/skills/unidesk-cicd/references/gitea-pac.md"),
  "utf8",
);
const platform = readFileSync(resolve(root, "docs/reference/platform-infra.md"), "utf8");

describe("PR 合并驱动的自动交付文档合同", () => {
  test("权威文档声明唯一触发、完整自动链和故障修复边界", () => {
    for (const document of [skill, reference, platform]) {
      expect(document).toContain("GitHub PR merge");
      expect(document).toMatch(/唯一.*触发/);
      expect(document).toMatch(
        /GitHub webhook[\s\S]*Gitea[\s\S]*immutable snapshot[\s\S]*Gitea webhook[\s\S]*(?:PaC|Pipelines-as-Code)[\s\S]*Tekton[\s\S]*GitOps\/Argo[\s\S]*(?:runtime|运行面)/,
      );
      expect(document).toMatch(/自动链.*修复|修复.*自动链/);
    }
  });

  test("主代理、子代理和操作者不得在 PR 合并后补齐交付", () => {
    for (const document of [skill, reference, platform]) {
      expect(document).toContain("主代理");
      expect(document).toContain("子代理");
      expect(document).toMatch(
        /apply[\s\S]*closeout[\s\S]*trigger[\s\S]*sync[\s\S]*flush/,
      );
      expect(document).toMatch(/不得|禁止/);
    }
  });

  test("状态与单步入口只读，自动链不通时不得人工恢复", () => {
    expect(skill).toContain(
      "status/history/events/logs/debug-step 可用于定位，但不得改变交付状态",
    );
    expect(skill).toContain("`closeout` 只属于显式 compatibility diagnostics");
    expect(skill).toContain("PaC migrated consumer 禁止执行 `trigger-current`");
    expect(skill).not.toContain("需要保留的旧命令只能标为 debug/test/recovery");
    expect(reference).toContain("`closeout` 只保留为可选的只读历史/诊断兼容入口");
    expect(reference).toContain("禁止输出或执行人工 `REPAIR`");
    expect(reference).not.toContain("run the row's `REPAIR` command");
    expect(reference).not.toContain("manual recovery");
  });

  test("migrated consumer 默认观察与覆盖矩阵不再引导人工 closeout", () => {
    const coverage = reference.slice(
      reference.indexOf("## 覆盖矩阵"),
      reference.indexOf("## 按需只读调查"),
    );
    const diagnosis = reference.slice(
      reference.indexOf("## 按需只读调查"),
      reference.indexOf("GitHub webhook delivery"),
    );

    expect(coverage).toContain("pipelines-as-code status");
    expect(coverage).not.toContain("pipelines-as-code closeout");
    expect(diagnosis).toContain("不是 PR 合并后的默认顺序、交付前置或“下一步”");
    expect(diagnosis).not.toContain("pipelines-as-code closeout");
  });

  test("源码制品写入仅属于合并前，不得成为合并后触发器", () => {
    expect(reference).toContain(
      "`source-artifact plan|check|write` 只能在 source PR 合并前",
    );
    expect(reference).toContain("不是合并后的 CI/CD 触发、同步、恢复或补跑入口");
  });

  test("delivery authority 由两份 YAML 组合，unknown 与 migrated 都禁止 mutation", () => {
    for (const document of [skill, reference, platform]) {
      expect(document).toContain("config/platform-infra/gitea.yaml");
      expect(document).toContain("config/platform-infra/pipelines-as-code.yaml");
      expect(document).toMatch(/unknown[\s\S]*mutation=false|unknown[\s\S]*`mutation=false`/);
      expect(document).toMatch(/legacy-(?:manual|cicd)|legacy\/manual/);
    }
  });

  test("durable inbox 只证明 accepted，同 delivery refs proof 才能 committed", () => {
    for (const document of [skill, reference, platform]) {
      expect(document).toContain("202 Accepted");
      expect(document).toContain("accepted");
      expect(document).toContain("processing");
      expect(document).toContain("committed");
      expect(document).toContain("failed");
      expect(document).toContain("deliveryId");
      expect(document).toMatch(/fsync[\s\S]*atomic (?:rename|write)/);
      expect(document).toMatch(/immutable snapshot[\s\S]*authority branch|authority branch[\s\S]*immutable snapshot/);
      expect(document).toMatch(/重新读取 refs|refs proof/);
      expect(document).toMatch(/不是.*(?:source|源码).*第二份真相|不是业务 source\/ref 的第二份真相/);
      expect(document).not.toMatch(/只有 HTTP 200|返回 HTTP 200 后.*committed/);
    }
  });

  test("可调整预算继续归属 YAML，长期规则不固化当前数值", () => {
    expect(skill).toContain("wall-clock 目标及预算只由 owning YAML 声明");
    expect(skill).not.toContain("低于 2 分钟");
    expect(skill).not.toContain("120s 端到端预算");
  });
});
