import { describe, expect, it } from 'vitest'
import { readdirSync, readFileSync, statSync } from 'node:fs'
import { join } from 'node:path'

const SRC = join(import.meta.dirname, '..', '..', 'src')

function walk(dir: string): string[] {
  const out: string[] = []
  for (const name of readdirSync(dir)) {
    const path = join(dir, name)
    if (statSync(path).isDirectory()) out.push(...walk(path))
    else if (name.endsWith('.ts')) out.push(path)
  }
  return out
}

const files = walk(SRC)
function code(path: string): string {
  return readFileSync(path, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '')
}

describe('agent security tripwires (T18, INDEX §3)', () => {
  it('INV9: no console.log anywhere in src', () => {
    for (const f of files) {
      expect(code(f), `console.log in ${f}`).not.toMatch(/console\.log/)
    }
  })

  it('INV11: no ANSI/xterm/vt100 import anywhere in src (byte-shuttle)', () => {
    for (const f of files) {
      expect(code(f), `terminal-parser import in ${f}`).not.toMatch(/from ['"][^'"]*(xterm|ansi|vt100)[^'"]*['"]/)
    }
  })

  it('INV2 anti-MITM: hostEndpoint imports NO verifier from relay-e2e (FIX 6b)', () => {
    const he = code(join(SRC, 'e2e', 'hostEndpoint.ts'))
    expect(he).not.toMatch(/from ['"]relay-e2e['"]/)
    expect(he).not.toMatch(/verifyDeviceAuthProof/)
  })

  it('INV12: revocation.ts uses the frozen decoder, no bare integer reason literal', () => {
    const rev = code(join(SRC, 'lifecycle', 'revocation.ts'))
    expect(rev).toMatch(/decodeGoAwayReason/)
    expect(rev).not.toMatch(/reason\s*[=:]\s*\d/)
    expect(rev).not.toMatch(/===\s*[123]\b/)
  })

  it('INV4: identity exposes no raw private-key byte export', () => {
    const id = code(join(SRC, 'keys', 'identity.ts'))
    expect(id).not.toMatch(/exportPrivateRaw|privateKeyBytes|rawPrivateKey/)
  })

  it('every src module is well under the 800-line hard cap', () => {
    for (const f of files) {
      const lines = readFileSync(f, 'utf8').split('\n').length
      expect(lines, `${f} is ${lines} lines`).toBeLessThan(800)
    }
  })
})
