import { EventEmitter } from 'node:events';
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawnSync } from 'node:child_process';

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const failures = [];
const assert = (condition, message) => { if (!condition) failures.push(message); };
const expectThrow = async (fn, code, message) => { try { await fn(); failures.push(message); } catch (error) { if (code && error.code !== code) failures.push(`${message} (${error.code || error.message})`); } };
const read = rel => readFileSync(join(root, rel), 'utf8');
const temp = mkdtempSync(join(tmpdir(), 'vendoo-security-137-'));
try {
  const configPath = join(temp, 'vendoo.env');
  process.env.VENDOO_DATA_DIR = temp;
  process.env.VENDOO_CONFIG_PATH = configPath;
  process.env.VENDOO_MASTER_KEY_FILE = join(temp, 'master.key');
  process.env.VENDOO_SECRETS_PATH = join(temp, 'secrets.enc.json');
  delete process.env.VENDOO_MASTER_KEY;
  writeFileSync(configPath, 'OPENAI_API_KEY=sk-test-secret-123456\nSMTP_PASS=mail-secret-987\nPORT=8124\n');
  const secrets = await import(`../lib/secret-store.mjs?test=${Date.now()}`);
  const migration = secrets.migrateRuntimeConfigSecrets();
  assert(migration.migrated.includes('OPENAI_API_KEY') && migration.migrated.includes('SMTP_PASS'), 'Runtime-Secrets wurden nicht migriert');
  assert(readFileSync(configPath, 'utf8').includes('PORT=8124'), 'Nicht geheime Runtime-Konfiguration ging verloren');
  assert(!readFileSync(configPath, 'utf8').includes('sk-test-secret'), 'Klartext-Secret blieb in der Runtime-Konfiguration');
  const encrypted = readFileSync(process.env.VENDOO_SECRETS_PATH, 'utf8');
  assert(!encrypted.includes('sk-test-secret') && !encrypted.includes('mail-secret'), 'Secret-Speicher enthält Klartext');
  assert(secrets.getSecret('OPENAI_API_KEY') === 'sk-test-secret-123456', 'Entschlüsselung fehlgeschlagen');
  assert(secrets.getSecretMetadata('OPENAI_API_KEY').masked.endsWith('3456'), 'Maskierung ist fehlerhaft');
  assert(secrets.secretStoreStatus().encrypted >= 2, 'Verschlüsselte Secret-Anzahl ist falsch');
  await expectThrow(() => secrets.setSecret('OPENAI_API_KEY', 'line1\nline2'), 'SECRET_VALUE_INVALID', 'Mehrzeiliges Secret wurde akzeptiert');
  await expectThrow(() => secrets.setSecret('UNKNOWN_SECRET', 'x'), 'SECRET_NAME_INVALID', 'Unbekanntes Secret wurde akzeptiert');

  const logger = await import(`../lib/structured-logger.mjs?test=${Date.now()}`);
  const req = { method:'GET', path:'/api/test', user:null, get(name){ return name === 'x-vendoo-request-id' ? 'test-request-1' : ''; } };
  const res = new EventEmitter(); res.statusCode=200; res.setHeader=()=>{};
  logger.requestContextMiddleware(req,res,()=>{}); res.emit('finish');
  const telemetry = logger.getRequestTelemetry();
  assert(req.requestId === 'test-request-1' && req.correlationId === 'test-request-1', 'Request-/Correlation-ID fehlt');
  assert(telemetry.total === 1 && telemetry.recent[0].path === '/api/test', 'Request-Telemetrie fehlerhaft');

  const server = read('server.mjs');
  for (const marker of ["scriptSrcAttr: [\"'none'\"]", "id: 'security.secrets.read'", "id: 'security.secrets.update'", "policy: 'security.secrets.manage'", 'requestContextMiddleware', 'objectSchema']) assert(server.includes(marker), `Security-Serververtrag fehlt: ${marker}`);
  assert(!server.includes("scriptSrc: [\"'self'\", \"'unsafe-inline'\""), 'Inline-Skripte sind in CSP noch erlaubt');
  assert(!read('public/index.html').includes('onclick='), 'index.html enthält Inline-Eventhandler');
  assert(!read('public/login.html').includes('<script>'), 'login.html enthält Inline-Script');
  assert(read('public/login.html').includes('/login.js?v=1.41.2'), 'Externes Login-Script fehlt');
  assert(!read('public/app.js').includes('onclick='), 'app.js erzeugt Inline-Eventhandler');
  for (const file of ['lib/ebay-api.mjs','lib/etsy-api.mjs']) {
    const oauth = read(file);
    assert(oauth.includes("setSecret(key, value, { source: 'oauth' })"), `${file} schreibt OAuth-Tokens nicht in den Secret-Speicher`);
    assert(!oauth.includes("join(__dirname, '..', '.env')"), `${file} schreibt weiterhin direkt in .env`);
  }
  assert(read('server.mjs').includes("setSecret('LOCAL_IMAGE_TOKEN', token, { source: 'token-regeneration' })"), 'FLUX-Token-Regeneration nutzt den Secret-Speicher nicht');
  const manifest = JSON.parse(read('app/modules/security/module.json'));
  assert(manifest.status === 'native' && manifest.provides.includes('security.secrets'), 'Security-Modul ist nicht nativ');
  const pkg = JSON.parse(read('package.json'));
  assert(pkg.version === '1.41.2', `Paketversion ist ${pkg.version}`);

  const syntax = spawnSync(process.execPath, ['--check', join(root, 'public/login.js')], { encoding:'utf8' });
  assert(syntax.status === 0, `login.js Syntaxfehler: ${syntax.stderr}`);
} finally { rmSync(temp, { recursive:true, force:true }); }

if (failures.length) { console.error(`Security-Foundation-Gate 1.41.2 fehlgeschlagen (${failures.length}):`); failures.forEach(item => console.error(`- ${item}`)); process.exit(1); }
console.log('Security-Foundation-Gate 1.41.2 erfolgreich: verschlüsselte Secret-Migration, Maskierung, Inputschutz, strikte Script-CSP, Request-/Correlation-IDs und Telemetrie geprüft.');
