#!/usr/bin/env node
// Bazaar listing parity check:
//  - Every endpoint advertised in /.well-known/x402.json MUST exist as a real
//    route file on disk.
//  - Every priced GET route on disk MUST be advertised in x402.json.
// Detects drift in either direction.

import { readFile, readdir, stat } from 'node:fs/promises';
import { join } from 'node:path';

const X402_JSON = 'public/.well-known/x402.json';
const ROUTES_ROOT = 'app/api/x402';

async function listRoutes(dir, prefix = '') {
  const out = [];
  for (const ent of await readdir(dir)) {
    const full = join(dir, ent);
    const s = await stat(full);
    if (s.isDirectory()) {
      out.push(...(await listRoutes(full, prefix + '/' + ent)));
    } else if (ent === 'route.ts') {
      // Convert app/api/x402/trust/agent-status/route.ts → /api/x402/trust/agent-status
      out.push('/api/x402' + prefix);
    }
  }
  return out;
}

async function main() {
  const manifestRaw = await readFile(X402_JSON, 'utf8');
  const manifest = JSON.parse(manifestRaw);
  const advertised = new Set(manifest.endpoints.map(e => e.path));

  const onDisk = new Set(await listRoutes(ROUTES_ROOT));

  // Drop infra paths (verify, settle, submit-signed) from disk set
  const infra = new Set([
    '/api/x402/verify',
    '/api/x402/settle',
    '/api/x402/submit-signed',
    '/api/x402', // root
  ]);
  for (const p of infra) onDisk.delete(p);

  // 1. Advertised but not on disk = lying to crawlers
  const advertisedMissing = [...advertised].filter(p => !onDisk.has(p));
  // 2. On disk but not advertised = hidden endpoint
  const onDiskNotAdvertised = [...onDisk].filter(p => !advertised.has(p));

  console.log(`Advertised in x402.json: ${advertised.size}`);
  console.log(`Routes on disk:          ${onDisk.size}`);
  console.log(`Manifest endpointCount:  ${manifest.endpointCount}`);
  console.log(`Manifest pricedCount:    ${manifest.pricedEndpointCount}`);
  console.log();

  if (advertisedMissing.length) {
    console.log(`❌ ADVERTISED BUT MISSING ON DISK (${advertisedMissing.length}):`);
    for (const p of advertisedMissing) console.log('  -', p);
    console.log();
  }

  if (onDiskNotAdvertised.length) {
    console.log(`⚠️  ON DISK BUT NOT ADVERTISED (${onDiskNotAdvertised.length}):`);
    for (const p of onDiskNotAdvertised) console.log('  -', p);
    console.log();
  }

  if (manifest.endpointCount !== advertised.size) {
    console.log(`❌ endpointCount field (${manifest.endpointCount}) != actual endpoints[] length (${advertised.size})`);
  }
  const pricedCount = manifest.endpoints.filter(e => e.price && e.price !== 'free').length;
  if (manifest.pricedEndpointCount !== pricedCount) {
    console.log(`❌ pricedEndpointCount field (${manifest.pricedEndpointCount}) != actual priced count (${pricedCount})`);
  }

  if (advertisedMissing.length || (onDiskNotAdvertised.length > 0)) {
    process.exit(1);
  }
  console.log('✅ Parity check passed.');
}

main().catch(e => { console.error(e); process.exit(2); });
