#!/usr/bin/env node

/**
 * Regression Gate — SF-08
 *
 * 执行所有验证 gate，全部通过才允许发布。
 * Exit 0 = PASS, Exit 1 = FAIL.
 *
 * Usage:
 *   node scripts/regression-gate.mjs [--strict]
 *
 * Gates:
 *   1. 10 Domain E2E Benchmark
 *   2. 170 Regression Tests
 *   3. 5 Domain Semantic Spot-Check
 *
 * @module regression-gate
 */

import { execSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(resolve(fileURLToPath(import.meta.url)));
const WORKSPACE = resolve(__dirname, "..");

const STRICT = process.argv.includes("--strict");

// ═══════════════════════════════════════════════════════
// Gate Definitions
// ═══════════════════════════════════════════════════════

const SEMANTIC_SPOTCHECK = [
  { name: "BookShelf", input: "做一个图书管理系统，支持书籍库、阅读状态、阅读进度、书评和统计", expectTables: ["books", "reading_status"] },
  { name: "TeamFlow", input: "做一个团队协作工具，支持看板视图、任务管理、团队成员和活动日志", expectTables: ["boards", "tasks"] },
  { name: "Contract", input: "做一个合同管理工具，支持合同创建、审批流程、到期提醒和合同归档", expectTables: ["contracts", "approvals"] },
  { name: "Inspection", input: "做一个设备巡检系统，支持巡检计划、巡检记录、故障上报和设备台账", expectTables: ["equipment", "faults"] },
  { name: "Warehouse", input: "做一个仓库出入库工具，支持入库登记、出库审批、库存盘点和库存预警", expectTables: ["stock_in", "stock_out"] },
];

// ═══════════════════════════════════════════════════════
// Helpers
// ═══════════════════════════════════════════════════════

function run(cmd, label) {
  const start = Date.now();
  try {
    const out = execSync(cmd, { cwd: WORKSPACE, encoding: "utf8", stdio: "pipe", timeout: 180_000 });
    const ms = Date.now() - start;
    return { pass: true, ms, output: out };
  } catch (e) {
    const ms = Date.now() - start;
    return { pass: false, ms, output: e.stderr || e.stdout || e.message };
  }
}

function gateHeader(n, label) {
  console.log(`\n${"═".repeat(60)}`);
  console.log(`  GATE ${n}: ${label}`);
  console.log(`${"═".repeat(60)}`);
}

// ═══════════════════════════════════════════════════════
// Gate 1: 10 Domain E2E Benchmark
// ═══════════════════════════════════════════════════════

function gateBenchmark() {
  gateHeader(1, "10 Domain E2E Benchmark");
  const r = run("node scripts/e2e-benchmark-v1.mjs", "benchmark");
  const passMatch = r.output.match(/(\d+)\/(\d+) PASS/);
  const passCount = passMatch ? parseInt(passMatch[1]) : 0;
  const total = passMatch ? parseInt(passMatch[2]) : 0;
  const pass = passCount === 10 && total === 10;
  console.log(`  Result: ${passCount}/${total} PASS (${r.ms}ms)`);
  console.log(`  Status: ${pass ? "✅ PASS" : "❌ FAIL"}`);
  return pass;
}

// ═══════════════════════════════════════════════════════
// Gate 2: 170 Regression Tests
// ═══════════════════════════════════════════════════════

function gateRegression() {
  gateHeader(2, "170 Regression Tests");
  const r = run("node --test test/e2e-regression.test.mjs", "regression");
  const passMatch = r.output.match(/pass (\d+)/);
  const failMatch = r.output.match(/fail (\d+)/);
  const passCount = passMatch ? parseInt(passMatch[1]) : 0;
  const failCount = failMatch ? parseInt(failMatch[1]) : 0;
  const pass = passCount === 170 && failCount === 0;
  console.log(`  Result: ${passCount} pass, ${failCount} fail (${r.ms}ms)`);
  console.log(`  Status: ${pass ? "✅ PASS" : "❌ FAIL"}`);
  return pass;
}

// ═══════════════════════════════════════════════════════
// Gate 3: Semantic Spot-Check
// ═══════════════════════════════════════════════════════

function gateSemantic() {
  gateHeader(3, "5 Domain Semantic Spot-Check");
  let allPass = true;

  for (const tc of SEMANTIC_SPOTCHECK) {
    const tmpDir = `/tmp/gate-${tc.name.toLowerCase()}`;
    try {
      execSync(`node scripts/project-intake-agent.mjs --input "${tc.input}" --output ${tmpDir}/prd.json`, { cwd: WORKSPACE, encoding: "utf8", stdio: "pipe" });
      execSync(`node scripts/architecture-agent.mjs --input ${tmpDir}/prd.json --output ${tmpDir}/arch.json`, { cwd: WORKSPACE, encoding: "utf8", stdio: "pipe" });

      const arch = JSON.parse(readFileSync(`${tmpDir}/arch.json`, "utf8"));
      const tables = arch.databaseSchema.map(t => t.table);
      const hasChinese = tables.some(t => /[\u4e00-\u9fff]/.test(t));
      const hasExpected = tc.expectTables.every(et => tables.includes(et));
      const hasDomainFields = arch.databaseSchema.filter(t => t.table !== "users").some(t => {
        const fields = t.fields.filter(f => !["id", "user_id", "created_at", "updated_at"].includes(f.name));
        return fields.some(f => !["title", "description", "status", "data"].includes(f.name));
      });

      const pass = !hasChinese && hasExpected && hasDomainFields;
      console.log(`  ${pass ? "✅" : "❌"} ${tc.name}: tables=[${tables.join(", ")}]${hasChinese ? " [CHINESE!]" : ""}${!hasExpected ? " [MISSING TABLES!]" : ""}${!hasDomainFields ? " [GENERIC FIELDS!]" : ""}`);
      if (!pass) allPass = false;
    } catch (e) {
      console.log(`  ❌ ${tc.name}: ${e.message.split("\n")[0]}`);
      allPass = false;
    }
  }

  console.log(`\n  Status: ${allPass ? "✅ PASS" : "❌ FAIL"}`);
  return allPass;
}

// ═══════════════════════════════════════════════════════
// Main
// ═══════════════════════════════════════════════════════

async function main() {
  console.log("🔒 Regression Gate — v1.1.0-semantic");
  console.log(`   Mode: ${STRICT ? "STRICT" : "NORMAL"}`);
  console.log(`   Time: ${new Date().toISOString()}`);

  const results = {
    benchmark: gateBenchmark(),
    regression: gateRegression(),
    semantic: gateSemantic(),
  };

  console.log(`\n${"═".repeat(60)}`);
  console.log("  SUMMARY");
  console.log(`${"═".repeat(60)}`);
  for (const [name, pass] of Object.entries(results)) {
    console.log(`  ${pass ? "✅" : "❌"} ${name}`);
  }

  const allPass = Object.values(results).every(Boolean);
  console.log(`\n  ${allPass ? "🟢 ALL GATES PASS — Release approved" : "🔴 GATE FAILED — Release blocked"}`);
  console.log("");

  process.exit(allPass ? 0 : 1);
}

main().catch(e => {
  console.error("Gate runner crashed:", e);
  process.exit(1);
});
