/**
 * Pentester-Hilfsscript (Pentest R152): legt einen KONTROLLIERTEN „getarnten"
 * Upload an, um den Magic-Byte-Mismatch→attachment-Zweig des Download-Endpoints
 * live zu belegen.
 *
 * Was passiert:
 *   - Es wird eine dedizierte TEST-Bankkarte (accountHolder-Marker) angelegt –
 *     ECHTE Kundendaten werden NICHT angefasst/überschrieben.
 *   - An diese Karte wird eine Datei mit `.pdf`-Endung gehängt, deren Inhalt
 *     aber ein SVG mit <script> ist (Non-Whitelist-Magic-Byte, klassischer
 *     Stored-XSS-Payload).
 *   - documentPath wird exakt gesetzt, damit findUploadOwner die Datei der
 *     Test-Bankkarte (→ Customer) zuordnet und der Ownership-Check greift.
 *
 * Erwartetes Verhalten am Endpoint
 *   GET /api/files/download?path=<pfad>&disposition=inline :
 *     → HTTP 200, aber `Content-Disposition: attachment` (NICHT inline),
 *       `X-Content-Type-Options: nosniff`  → Browser lädt herunter, rendert
 *       NICHT im iframe → kein Stored-XSS.
 *     → Backend-Log: "[fileDownload] inline angefragt, aber Magic-Byte-Check
 *       fehlgeschlagen: <pfad>"
 *   Ohne `disposition=inline` ohnehin attachment (Default).
 *   Als fremder Portal-User: 403 (Ownership-Check, Karte gehört Test-Customer).
 *
 * Aufruf (im Backend-App-Verzeichnis / Container-WORKDIR /app):
 *   npx tsx scripts/seed-magic-byte-test.ts create   [--customer <id>]
 *   npx tsx scripts/seed-magic-byte-test.ts cleanup
 *
 * Danach unbedingt `cleanup` laufen lassen (löscht Datei + Test-Bankkarte).
 */
import fs from 'fs';
import path from 'path';
import prisma from '../src/lib/prisma.js';

const MARKER = 'MAGICBYTE-TEST (Pentester R152)';
const FILENAME = 'magic-byte-test.pdf'; // .pdf-Endung, aber SVG-Inhalt (getarnt)
const UPLOAD_SUBDIR = 'bank-cards';
const RELATIVE_PATH = `/uploads/${UPLOAD_SUBDIR}/${FILENAME}`;

// SVG mit <script> – würde bei inline-Auslieferung als image/svg+xml im Browser
// ausgeführt. Genau das muss der Magic-Byte-Gate verhindern.
const SVG_XSS = `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="80">
  <text x="10" y="40">MAGICBYTE-TEST</text>
  <script type="text/javascript">/* Pentest R152 */ alert('XSS-MAGICBYTE-TEST');</script>
</svg>
`;

function uploadsDir(): string {
  return path.join(process.cwd(), 'uploads', UPLOAD_SUBDIR);
}

function absoluteFilePath(): string {
  return path.join(uploadsDir(), FILENAME);
}

async function create(customerIdArg?: number): Promise<void> {
  // Harter Prod-Riegel: dieses Script legt eine Fake-Bankkarte + getarnte
  // Datei an – das darf NIE gegen Produktion laufen (weder versehentlich noch
  // absichtlich). `cleanup` bleibt erlaubt, damit man immer aufräumen kann.
  if (process.env.NODE_ENV === 'production') {
    console.error(
      'ABBRUCH: "create" ist bei NODE_ENV=production deaktiviert. Dieser ' +
      'Pentester-/Test-Helfer gehört nur nach Dev/Staging. (Zum Aufräumen ist ' +
      '"cleanup" weiterhin erlaubt.)',
    );
    process.exit(1);
  }

  // Ziel-Customer bestimmen (Default: erster vorhandener Kunde).
  const customer = customerIdArg
    ? await prisma.customer.findUnique({ where: { id: customerIdArg }, select: { id: true, customerNumber: true } })
    : await prisma.customer.findFirst({ orderBy: { id: 'asc' }, select: { id: true, customerNumber: true } });

  if (!customer) {
    console.error('Kein Kunde gefunden – bitte zuerst einen Kunden anlegen oder --customer <id> angeben.');
    process.exit(1);
  }

  // Getarnte Datei schreiben.
  fs.mkdirSync(uploadsDir(), { recursive: true });
  fs.writeFileSync(absoluteFilePath(), SVG_XSS, 'utf8');

  // Test-Bankkarte anlegen oder wiederverwenden (idempotent, kein Duplikat).
  const existing = await prisma.bankCard.findFirst({ where: { accountHolder: MARKER } });
  const card = existing
    ? await prisma.bankCard.update({ where: { id: existing.id }, data: { customerId: customer.id, documentPath: RELATIVE_PATH } })
    : await prisma.bankCard.create({
        data: {
          customerId: customer.id,
          accountHolder: MARKER,
          iban: 'DE00000000000000000000',
          documentPath: RELATIVE_PATH,
          description: 'Pentest R152 – getarnte Datei (SVG-als-PDF). Nach Test via cleanup entfernen.',
        },
      });

  const head = Buffer.alloc(12);
  const fd = fs.openSync(absoluteFilePath(), 'r');
  fs.readSync(fd, head, 0, 12, 0);
  fs.closeSync(fd);

  console.log('=== Magic-Byte-Test angelegt ===');
  console.log('Test-Customer   :', customer.customerNumber, `(id ${customer.id})`);
  console.log('Test-Bankkarte  : id', card.id, `– accountHolder="${MARKER}"`);
  console.log('Datei (Disk)    :', absoluteFilePath());
  console.log('Erste 12 Bytes  :', JSON.stringify(head.toString('latin1')), '(kein PDF/PNG/JPEG/GIF/WebP-Magic)');
  console.log('documentPath    :', RELATIVE_PATH);
  console.log('');
  console.log('--- So testen (Token des berechtigten Users anhängen) ---');
  console.log(`  curl -sSI "https://<host>/api/files/download?path=${RELATIVE_PATH}&disposition=inline&token=<JWT>"`);
  console.log('  Erwartet: 200, Content-Disposition: attachment, X-Content-Type-Options: nosniff');
  console.log('            (NICHT inline) + Backend-Log "Magic-Byte-Check fehlgeschlagen".');
  console.log(`  Ohne &disposition=inline: ebenfalls attachment.`);
  console.log('  Als fremder Portal-User: 403 (Ownership-Check).');
  console.log('');
  console.log('>>> Nach dem Test aufräumen:  npx tsx scripts/seed-magic-byte-test.ts cleanup');
}

async function cleanup(): Promise<void> {
  let removed = 0;
  const cards = await prisma.bankCard.findMany({ where: { accountHolder: MARKER } });
  for (const c of cards) {
    await prisma.bankCard.delete({ where: { id: c.id } });
    removed++;
  }
  // Datei löschen (falls vorhanden).
  const abs = absoluteFilePath();
  let fileDeleted = false;
  if (fs.existsSync(abs)) {
    fs.unlinkSync(abs);
    fileDeleted = true;
  }
  console.log('=== Cleanup ===');
  console.log('Gelöschte Test-Bankkarten:', removed);
  console.log('Datei gelöscht           :', fileDeleted ? abs : '(nicht vorhanden)');
}

(async () => {
  const mode = process.argv[2] || 'create';
  const custIdx = process.argv.indexOf('--customer');
  const customerIdArg = custIdx >= 0 ? parseInt(process.argv[custIdx + 1], 10) : undefined;
  try {
    if (mode === 'create') {
      await create(Number.isFinite(customerIdArg as number) ? customerIdArg : undefined);
    } else if (mode === 'cleanup') {
      await cleanup();
    } else {
      console.error(`Unbekannter Modus "${mode}". Nutze: create | cleanup`);
      process.exit(1);
    }
  } catch (err) {
    console.error('Fehler:', err instanceof Error ? err.message : err);
    process.exit(1);
  } finally {
    await prisma.$disconnect();
  }
})();
