import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import test from 'node:test';

const ROOT = new URL('../', import.meta.url);
const EXPECTED_BASELINE_SITES = 26;
const EXPECTED_TEST_BASELINE_SITES = 22;
const EXPECTED_WAKE_BASELINE_SITES = 26;
const TARGETS = [
  'tools/matrix-presence-harness/run.sh',
  'tools/e2e-install-test.sh',
  'tools/install.sh',
  'scripts/agent/session-start.sh',
  'scripts/analysis/reflect-board-history.sh',
  'scripts/analysis/reflect-git-history.sh',
  'packages/mosaic/framework/templates/repo/scripts/agent/session-start.sh',
  'packages/mosaic/framework/tools/authentik/user-create.sh',
  'packages/mosaic/framework/tools/git/mutate-push-guard.sh',
  'packages/mosaic/framework/tools/orchestrator/session-resume.sh',
  'packages/mosaic/framework/tools/prdy/prdy-status.sh',
  'packages/mosaic/framework/tools/qa/reflect-stop-hook.sh',
  'packages/mosaic/framework/tools/qa/typecheck-hook.sh',
  'packages/mosaic/framework/tools/tmux/send-message.sh',
  'packages/mosaic/framework/tools/wake/detector.sh',
  'packages/mosaic/framework/tools/wake/digest.sh',
  'packages/mosaic/framework/tools/wake/reconcile.sh',
  'packages/mosaic/framework/systemd/user/test-fleet-units.sh',
  'packages/mosaic/framework/tools/git/test-issue-comment-readback.sh',
  'packages/mosaic/framework/tools/git/test-lane-brief-pr-linkage.sh',
  'packages/mosaic/framework/tools/git/test-pr-review-gitea-comment.sh',
  'packages/mosaic/framework/tools/git/test-pr-review-repo-host-override.sh',
  'packages/mosaic/framework/tools/orchestrator/smoke-test.sh',
  'packages/mosaic/framework/tools/orchestrator/test-board-roll.sh',
  'packages/mosaic/framework/tools/quality/scripts/test-upgrade-durable-snapshot.sh',
  'packages/mosaic/framework/tools/quality/scripts/test-upgrade-rollback.sh',
  'packages/mosaic/framework/tools/tmux/test-send-message-socket.sh',
  'packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh',
  'packages/mosaic/framework/tools/wake/test-wake-digest-quarantine.sh',
  'packages/mosaic/framework/tools/wake/test-wake-preimage.sh',
  'packages/mosaic/framework/tools/wake/validate-973/microtest-wake-assert.sh',
  'packages/mosaic/framework/tools/wake/validate-973/validate-973.sh',
];

// These statuses are explicitly non-load-bearing or unreachable at designed input.
// They remain inventoried until the final #1099 tranche records every verdict.
const ACCEPTED = [
  ['tools/install.sh', 'mosaic-bak-', '|| true'],
  ['tools/install.sh', 'mosaicstack-mosaic-*.tgz', 'head -1'],
  ['tools/install.sh', 'mosaicstack-gateway-*.tgz', 'head -1'],
  ['scripts/agent/session-start.sh', 'docs/scratchpads/*.md', '|| true'],
  [
    'packages/mosaic/framework/templates/repo/scripts/agent/session-start.sh',
    'docs/scratchpads/*.md',
    '|| true',
  ],
];

const earlyExit =
  /(?<!\|)\|(?!\|)[^;\n]*(?:grep\b[^;\n]*(?:-[A-Za-z]*q|--quiet|-m\s*1)|head\b(?:\s|$))/;

function scan(sources) {
  const found = [];
  for (const [file, rawSource] of sources) {
    const source = rawSource.replace(/\\\n\s*/g, ' ');
    for (const rawLine of source.split('\n')) {
      const line = rawLine.trim();
      if (!earlyExit.test(line)) continue;
      const accepted = ACCEPTED.some(
        ([acceptedFile, ...fragments]) =>
          acceptedFile === file && fragments.every((item) => line.includes(item)),
      );
      if (!accepted) found.push(`${file}:${line}`);
    }
  }
  return found;
}

async function currentSources() {
  return Promise.all(
    TARGETS.map(async (file) => [file, await readFile(new URL(file, ROOT), 'utf8')]),
  );
}

async function assertBaselineFixture(file, expectedCount, expectedUnique = expectedCount) {
  const baseline = JSON.parse(await readFile(new URL(file, ROOT), 'utf8'));
  assert.equal(baseline.length, expectedCount);
  assert.equal(new Set(baseline).size, expectedUnique);
  const fixtureSources = baseline.map((site) => {
    const separator = site.indexOf(':');
    assert.ok(separator > 0, `invalid baseline site: ${site}`);
    return [site.slice(0, separator), site.slice(separator + 1)];
  });
  assert.deepEqual(scan(fixtureSources), baseline);
}

test('the registered runtime baseline denominator is exactly 26 unsafe sites', async () => {
  await assertBaselineFixture(
    'scripts/fixtures/pipefail-early-exit-baseline.json',
    EXPECTED_BASELINE_SITES,
  );
});

test('the registered test baseline denominator is exactly 22 unsafe sites', async () => {
  await assertBaselineFixture(
    'scripts/fixtures/pipefail-early-exit-test-baseline.json',
    EXPECTED_TEST_BASELINE_SITES,
    21,
  );
});

test('the registered wake baseline denominator is exactly 26 unsafe sites', async () => {
  await assertBaselineFixture(
    'scripts/fixtures/pipefail-early-exit-wake-baseline.json',
    EXPECTED_WAKE_BASELINE_SITES,
    25,
  );
});

test('load-bearing pipefail paths do not pipe into early-exiting consumers', async () => {
  assert.deepEqual(scan(await currentSources()), []);
});

test('gateway verify capability preserves the complete help-probe truth table', async () => {
  const directory = await mkdtemp(path.join(tmpdir(), 'gateway-help-probe-'));
  const mosaic = path.join(directory, 'mosaic');
  const probe = new URL('tools/e2e-gateway-verify-supported.sh', ROOT).pathname;
  try {
    await writeFile(
      mosaic,
      '#!/usr/bin/env bash\nprintf \'%s\\n\' "${MOCK_HELP_OUTPUT:-}"\nexit "${MOCK_HELP_RC:-0}"\n',
    );
    await chmod(mosaic, 0o755);
    const run = (rc, output) =>
      spawnSync('bash', [probe], {
        env: {
          ...process.env,
          PATH: `${directory}:${process.env.PATH}`,
          MOCK_HELP_RC: String(rc),
          MOCK_HELP_OUTPUT: output,
        },
      }).status;

    assert.equal(run(0, 'commands: verify'), 0);
    assert.equal(run(0, 'commands: install'), 1);
    assert.equal(run(1, 'commands: verify'), 1);
  } finally {
    await rm(directory, { recursive: true, force: true });
  }
});

test('wake JSONL selectors take the first match across the complete input stream', async () => {
  const source = await readFile(
    new URL('packages/mosaic/framework/tools/wake/test-wake-preimage.sh', ROOT),
    'utf8',
  );
  assert.equal((source.match(/jq -nr 'first\(inputs \| select\(/g) ?? []).length, 4);

  const directory = await mkdtemp(path.join(tmpdir(), 'wake-jsonl-first-'));
  const input = path.join(directory, 'pending.jsonl');
  const filter = 'first(inputs | select(.locators.kind == "preimage") | .observed_seq) // empty';
  try {
    await writeFile(
      input,
      '{"locators":{"kind":"repo"},"observed_seq":1}\n' +
        '{"locators":{"kind":"preimage"},"observed_seq":4}\n' +
        '{"locators":{"kind":"preimage"},"observed_seq":9}\n',
    );
    let result = spawnSync('jq', ['-nr', filter, input], { encoding: 'utf8' });
    assert.equal(result.status, 0, result.stderr);
    assert.equal(result.stdout, '4\n');

    await writeFile(input, '{"locators":{"kind":"repo"},"observed_seq":1}\n');
    result = spawnSync('jq', ['-nr', filter, input], { encoding: 'utf8' });
    assert.equal(result.status, 0, result.stderr);
    assert.equal(result.stdout, '');

    await writeFile(input, '{invalid json}\n');
    result = spawnSync('jq', ['-nr', filter, input], { encoding: 'utf8' });
    assert.notEqual(result.status, 0);
  } finally {
    await rm(directory, { recursive: true, force: true });
  }
});

test('board-history preserves non-git data-dir as a non-detectable result', async () => {
  const directory = await mkdtemp(path.join(tmpdir(), 'reflect-board-non-git-'));
  try {
    await writeFile(path.join(directory, 'task.json'), '{}\n');
    const result = spawnSync(
      'bash',
      [
        new URL('scripts/analysis/reflect-board-history.sh', ROOT).pathname,
        '--data-dir',
        directory,
      ],
      { encoding: 'utf8' },
    );
    assert.equal(result.status, 0, result.stderr);
    assert.match(result.stdout, /"done_tasks": 1/);
    assert.match(result.stdout, /"detectable_outcomes": 0/);
  } finally {
    await rm(directory, { recursive: true, force: true });
  }
});
