'use strict';

/**
 * Tests for v6.3.0 Level 3 — native tool registration.
 *
 * codex adapter:
 *  1.  write() injects ## Tools JSON block into AGENTS.md
 *  2.  block contains exactly 5 sigmap tool entries
 *  3.  all 5 expected tool names are present
 *  4.  each tool has name, description, and command fields
 *  5.  idempotent — second write does not duplicate the block
 *  6.  human content above the tools block is preserved
 *  7.  ## Tools block appears before ## Auto-generated signatures
 *
 * claude adapter:
 *  8.  write() injects ## Bash allowlist into CLAUDE.md
 *  9.  block contains sigmap Bash permission patterns
 * 10.  idempotent — second write does not duplicate the block
 * 11.  human content is preserved
 * 12.  ## Bash allowlist appears before ## Auto-generated signatures
 * 13.  block includes node gen-context.js* pattern
 *
 * bundled factories (gen-context.js):
 * 14.  bundled codex write() injects ## Tools block
 * 15.  bundled claude write() injects ## Bash allowlist
 */

const path   = require('fs');
const fs     = require('fs');
const assert = require('assert');
const os     = require('os');

const ROOT  = require('path').resolve(__dirname, '../../..');

const codex = require(require('path').join(ROOT, 'packages', 'adapters', 'codex'));
const claude = require(require('path').join(ROOT, 'packages', 'adapters', 'claude'));

let passed = 0;
let failed = 0;

function test(name, fn) {
  try {
    fn();
    console.log(`  PASS  ${name}`);
    passed++;
  } catch (err) {
    console.log(`  FAIL  ${name}: ${err.message}`);
    failed++;
  }
}

function withTempDir(fn) {
  const dir = fs.mkdtempSync(require('path').join(os.tmpdir(), 'sigmap-l3-'));
  try { fn(dir); } finally { fs.rmSync(dir, { recursive: true, force: true }); }
}

const CTX = '## src\n\n### src/api.js\n```\nfunction getUser(id)\n```';

// ── codex adapter ─────────────────────────────────────────────────────────────

// v7.0: the redundant ## Tools JSON block was removed from codex/AGENTS.md.
// The single canonical "## SigMap commands" guidance block now comes from
// formatOutput (shared by every adapter) — see context-consistency.test.js.
test('1. codex write() no longer emits the ## Tools JSON block', () => {
  withTempDir((dir) => {
    codex.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'AGENTS.md'), 'utf8');
    assert.ok(!content.includes('<!-- sigmap-tools -->'), 'stale sigmap-tools marker present');
    assert.ok(!content.includes('"sigmap_ask"'), 'stale tools JSON present');
  });
});

test('2. codex write() preserves human content above the marker', () => {
  withTempDir((dir) => {
    const agentsPath = require('path').join(dir, 'AGENTS.md');
    fs.writeFileSync(agentsPath, '# My Project\n\nHuman instructions here.\n');
    codex.write(CTX, dir);
    const content = fs.readFileSync(agentsPath, 'utf8');
    assert.ok(content.includes('# My Project'), 'human header missing');
    assert.ok(content.includes('Human instructions here.'), 'human content missing');
  });
});

// ── claude adapter ────────────────────────────────────────────────────────────

test('8. claude write() injects ## Bash allowlist into CLAUDE.md', () => {
  withTempDir((dir) => {
    claude.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'CLAUDE.md'), 'utf8');
    assert.ok(content.includes('## Bash allowlist'), '## Bash allowlist section missing');
    assert.ok(content.includes('<!-- sigmap-bash-allowlist -->'), 'allowlist marker missing');
  });
});

test('9. ## Bash allowlist contains sigmap Bash permission patterns', () => {
  withTempDir((dir) => {
    claude.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'CLAUDE.md'), 'utf8');
    assert.ok(content.includes('Bash(sigmap ask*)'), 'sigmap ask* pattern missing');
    assert.ok(content.includes('Bash(sigmap validate*)'), 'sigmap validate* pattern missing');
    assert.ok(content.includes('Bash(sigmap judge*)'), 'sigmap judge* pattern missing');
    assert.ok(content.includes('"permissions"'), 'permissions key missing');
    assert.ok(content.includes('"allow"'), 'allow key missing');
  });
});

test('10. claude write() is idempotent — no duplicate allowlist', () => {
  withTempDir((dir) => {
    claude.write(CTX, dir);
    claude.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'CLAUDE.md'), 'utf8');
    const count = (content.match(/<!-- sigmap-bash-allowlist -->/g) || []).length;
    assert.strictEqual(count, 1, `expected 1 allowlist marker, got ${count}`);
  });
});

test('11. claude write() preserves human content', () => {
  withTempDir((dir) => {
    const claudePath = require('path').join(dir, 'CLAUDE.md');
    fs.writeFileSync(claudePath, '# My CLAUDE.md\n\nProject-specific instructions.\n');
    claude.write(CTX, dir);
    const content = fs.readFileSync(claudePath, 'utf8');
    assert.ok(content.includes('# My CLAUDE.md'), 'human header missing');
    assert.ok(content.includes('Project-specific instructions.'), 'human content missing');
  });
});

test('12. ## Bash allowlist appears before ## Auto-generated signatures', () => {
  withTempDir((dir) => {
    claude.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'CLAUDE.md'), 'utf8');
    const allowPos = content.indexOf('## Bash allowlist');
    const sigPos   = content.indexOf('## Auto-generated signatures');
    assert.ok(allowPos !== -1, '## Bash allowlist not found');
    assert.ok(sigPos !== -1, '## Auto-generated signatures not found');
    assert.ok(allowPos < sigPos, '## Bash allowlist must appear before ## Auto-generated signatures');
  });
});

test('13. allowlist includes node gen-context.js* pattern', () => {
  withTempDir((dir) => {
    claude.write(CTX, dir);
    const content = fs.readFileSync(require('path').join(dir, 'CLAUDE.md'), 'utf8');
    assert.ok(content.includes('Bash(node gen-context.js*)'), 'gen-context.js pattern missing');
  });
});

// ── bundled factories ─────────────────────────────────────────────────────────

test('14. bundled codex write() does not emit the ## Tools block', () => {
  withTempDir((dir) => {
    const { spawnSync } = require('child_process');
    const script = `
      const path = require('path');
      const codex = require(path.join('${ROOT}', 'packages', 'adapters', 'codex'));
      codex.write('## src\\n### src/a.js\\n\\'\\'\\'\\nfn()\\n\\'\\'\\'', '${dir}');
      const content = require('fs').readFileSync(path.join('${dir}', 'AGENTS.md'), 'utf8');
      if (content.includes('<!-- sigmap-tools -->')) { process.stderr.write('STALE-TOOLS'); process.exit(1); }
    `;
    const result = spawnSync('node', ['-e', script], { encoding: 'utf8', timeout: 5000 });
    assert.ok(result.status === 0, `stale codex tools block present: ${result.stderr}`);
  });
});

test('15. bundled claude write() injects ## Bash allowlist', () => {
  withTempDir((dir) => {
    const { spawnSync } = require('child_process');
    const script = `
      const path = require('path');
      const claude = require(path.join('${ROOT}', 'packages', 'adapters', 'claude'));
      claude.write('## src\\n### src/a.js\\n\\'\\'\\'\\nfn()\\n\\'\\'\\'', '${dir}');
      const content = require('fs').readFileSync(path.join('${dir}', 'CLAUDE.md'), 'utf8');
      if (!content.includes('<!-- sigmap-bash-allowlist -->')) { process.stderr.write('MISSING'); process.exit(1); }
    `;
    const result = spawnSync('node', ['-e', script], { encoding: 'utf8', timeout: 5000 });
    assert.ok(result.status === 0, `bundled claude allowlist missing: ${result.stderr}`);
  });
});

// ── Summary ───────────────────────────────────────────────────────────────────
console.log('\n--- native-tool-registration ---');
console.log(`${passed} passed, ${failed} failed`);
if (failed > 0) process.exit(1);
