// tests/lib/manifest-schema-extensions.test.mjs
// Cover the OPTIONAL_KEYS extension to lib/parsers/manifest-yaml.mjs:
//   - skip_commit_check  (boolean, default false)
//   - memory_write       (boolean, default false)
//
// Defaults must NOT break the REQUIRED_KEYS contract.
// Non-boolean values must produce MANIFEST_OPTIONAL_TYPE error.

import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { parseManifest, OPTIONAL_KEYS } from '../../lib/parsers/manifest-yaml.mjs';

const BASE = `### Step 1: Cover
- Manifest:
  \`\`\`yaml
  manifest:
    expected_paths:
      - lib/foo.mjs
    min_file_count: 1
    commit_message_pattern: "^feat:"
    bash_syntax_check: []
    forbidden_paths: []
    must_contain: []`;

function bodyWithExtras(extras) {
  return `${BASE}\n${extras}\n  \`\`\`\n`;
}

function bodyOnlyRequired() {
  return `${BASE}\n  \`\`\`\n`;
}

test('OPTIONAL_KEYS exports skip_commit_check + memory_write', () => {
  assert.deepEqual(
    [...OPTIONAL_KEYS].sort(),
    ['memory_write', 'skip_commit_check'].sort(),
    'OPTIONAL_KEYS export drift — pin contract',
  );
});

test('absence of optional keys → defaults to false (both fields)', () => {
  const r = parseManifest(bodyOnlyRequired());
  assert.equal(r.valid, true, JSON.stringify(r.errors));
  assert.equal(r.parsed.skip_commit_check, false);
  assert.equal(r.parsed.memory_write, false);
});

test('skip_commit_check: true honored', () => {
  const r = parseManifest(bodyWithExtras('    skip_commit_check: true'));
  assert.equal(r.valid, true, JSON.stringify(r.errors));
  assert.equal(r.parsed.skip_commit_check, true);
  assert.equal(r.parsed.memory_write, false);
});

test('memory_write: true honored', () => {
  const r = parseManifest(bodyWithExtras('    memory_write: true'));
  assert.equal(r.valid, true, JSON.stringify(r.errors));
  assert.equal(r.parsed.memory_write, true);
  assert.equal(r.parsed.skip_commit_check, false);
});

test('both optional fields together — both honored', () => {
  const r = parseManifest(bodyWithExtras('    skip_commit_check: true\n    memory_write: true'));
  assert.equal(r.valid, true, JSON.stringify(r.errors));
  assert.equal(r.parsed.skip_commit_check, true);
  assert.equal(r.parsed.memory_write, true);
});

test('skip_commit_check: non-boolean rejected with MANIFEST_OPTIONAL_TYPE', () => {
  const r = parseManifest(bodyWithExtras('    skip_commit_check: "yes"'));
  assert.equal(r.valid, false);
  const found = r.errors.find(e => e.code === 'MANIFEST_OPTIONAL_TYPE');
  assert.ok(found, `expected MANIFEST_OPTIONAL_TYPE, got: ${JSON.stringify(r.errors)}`);
  assert.match(found.message, /skip_commit_check/);
});

test('memory_write: numeric rejected with MANIFEST_OPTIONAL_TYPE', () => {
  const r = parseManifest(bodyWithExtras('    memory_write: 1'));
  assert.equal(r.valid, false);
  const found = r.errors.find(e => e.code === 'MANIFEST_OPTIONAL_TYPE');
  assert.ok(found, `expected MANIFEST_OPTIONAL_TYPE, got: ${JSON.stringify(r.errors)}`);
  assert.match(found.message, /memory_write/);
});

test('extension does NOT break REQUIRED_KEYS contract', () => {
  const r = parseManifest(bodyOnlyRequired());
  assert.equal(r.valid, true);
  for (const k of ['expected_paths', 'min_file_count', 'commit_message_pattern',
                   'bash_syntax_check', 'forbidden_paths', 'must_contain']) {
    assert.ok(k in r.parsed, `required key ${k} missing after extension`);
  }
});
