/**
 * PR-D Production Check — Architecture Test
 * 
 * Run: node --test test/architecture/production-check.test.mjs
 * 
 * Tests:
 *   1. production-check.sh file exists
 *   2. production-check.sh is executable
 *   3. smoke-test.mjs file exists
 *   4. package.json contains production-check script
 *   5. Smoke test runs independently
 *   6. production-check runs end-to-end and exits 0
 */

import { describe, it, before } from "node:test";
import assert from "node:assert";
import { existsSync, statSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { execSync, spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";

const __dirname = join(fileURLToPath(import.meta.url), "..", "..", "..");
const ROOT = __dirname;
const SCRIPTS = join(ROOT, "scripts");

// ─── Helpers ──────────────────────────────────────────

function isExecutable(path) {
  try {
    const mode = statSync(path).mode;
    // Check owner execute bit
    return (mode & 0o100) !== 0;
  } catch {
    return false;
  }
}

// ─── Tests ────────────────────────────────────────────

describe("PR-D: Production Check Architecture", () => {
  // Test 1
  it("production-check.sh file exists", () => {
    const path = join(SCRIPTS, "production-check.sh");
    assert.ok(existsSync(path), `Missing: ${path}`);
  });

  // Test 2
  it("production-check.sh is executable", () => {
    const path = join(SCRIPTS, "production-check.sh");
    assert.ok(existsSync(path), `Missing: ${path}`);
    assert.ok(isExecutable(path), `Not executable: ${path}. Run: chmod +x ${path}`);
  });

  // Test 3
  it("smoke-test.mjs file exists", () => {
    const path = join(SCRIPTS, "smoke-test.mjs");
    assert.ok(existsSync(path), `Missing: ${path}`);
  });

  // Test 4
  it("package.json contains production-check, smoke, check:deprecations, test:baseline, guard scripts", () => {
    const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8"));
    const scripts = pkg.scripts || {};
    
    assert.ok(typeof scripts["production-check"] === "string",
      "Missing scripts.production-check in package.json");
    assert.ok(typeof scripts["smoke"] === "string",
      "Missing scripts.smoke in package.json");
    assert.ok(typeof scripts["check:deprecations"] === "string",
      "Missing scripts.check:deprecations in package.json");
    assert.ok(typeof scripts["test:baseline"] === "string",
      "Missing scripts.test:baseline in package.json");
    assert.ok(typeof scripts["guard"] === "string",
      "Missing scripts.guard in package.json");
  });

  // Test 5
  it("smoke test runs independently and exits 0", { timeout: 30000 }, () => {
    const script = join(SCRIPTS, "smoke-test.mjs");
    const result = spawnSync("node", [script], {
      cwd: ROOT,
      encoding: "utf8",
      timeout: 25000,
      maxBuffer: 1024 * 1024,
    });
    
    const output = result.stdout + result.stderr;
    console.log(output.slice(-800));
    
    assert.equal(result.status, 0,
      `Smoke test failed (exit ${result.status}):\n${output.slice(-500)}`);
    assert.ok(output.includes("Smoke test PASSED") || output.includes("PASS"),
      `Expected "Smoke test PASSED" in output:\n${output.slice(-300)}`);
  });

  // Test 6
  it("production-check runs end-to-end and exits 0", { timeout: 120000 }, () => {
    const script = join(SCRIPTS, "production-check.sh");
    const result = spawnSync("bash", [script], {
      cwd: ROOT,
      encoding: "utf8",
      timeout: 110000,
      maxBuffer: 2 * 1024 * 1024,
    });
    
    const output = result.stdout + result.stderr;
    console.log(output.slice(-1200));
    
    assert.equal(result.status, 0,
      `Production check failed (exit ${result.status}):\n${output.slice(-800)}`);
    
    // Verify all 6 steps ran
    const steps = [
      "Step 1: Environment Check",
      "Step 2: Baseline Tests",
      "Step 3: Architecture Guards",
      "Step 4: Deprecation Check",
      "Step 5: Smoke Test",
      "Step 6: Summary Report",
    ];
    
    for (const step of steps) {
      assert.ok(output.includes(step),
        `Missing step in output: "${step}"`);
    }
    
    assert.ok(output.includes("Overall:"),
      "Missing Overall summary");
    assert.ok(output.includes("Duration:"),
      "Missing Duration in summary");
  });
});
