/**
 * Sync User IDs in Docs/logins.dev to match current DB state.
 * Run: DATABASE_URL=... PII_KEY=... tsx src/server/db/seeds/sync-logins-ids.ts
 */

import { scriptOutput } from '../../lib/script-output.js';
import { bytesToHex } from '@/lib/encoding.js';
import { drizzle } from 'drizzle-orm/neon-serverless';
import { Pool, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';
import { inArray } from 'drizzle-orm';
import * as schema from '../schema.js';
import { readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { readSeedCliEnv } from '../seed-cli-env.js';

neonConfig.webSocketConstructor = ws;

const { DATABASE_URL, PII_KEY } = readSeedCliEnv();

const pool = new Pool({ connectionString: DATABASE_URL });
const db = drizzle(pool, { schema });

async function blindIndex(value: string, key: string): Promise<string> {
  const enc = new TextEncoder();
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    enc.encode(key),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign'],
  );
  const sig = await crypto.subtle.sign('HMAC', cryptoKey, enc.encode(value));
  return bytesToHex(sig);
}

const EMAILS = [
  'admin@example.dev',
  'vendor.test@multi.deal',
  'nimrod@demo-multideal.test',
  'roma@demo-multideal.test',
  'merav.spa@demo-multideal.test',
  'uri.sushi@demo-multideal.test',
  'gil.bakery@demo-multideal.test',
  'amitz.escape@demo-multideal.test',
  'halom.gelato@demo-multideal.test',
  'segev.barber@demo-multideal.test',
  'segev.barber@multi.deal',
  'halom.gelato@multi.deal',
  'de.luca@multi.deal',
  'amitz.escape@multi.deal',
  'lechem.shalom@multi.deal',
  'gil.bakery@multi.deal',
  'uri.sushi@multi.deal',
  'sushi.hacarmel@multi.deal',
  'merav.spa@multi.deal',
  ...Array.from({ length: 20 }, (_, i) => `testuser${String(i + 1).padStart(2, '0')}@multi.deal`),
  ...Array.from({ length: 5 }, (_, i) => `customer${String(i + 1).padStart(2, '0')}@multi.deal`),
];

const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;

async function main() {
  // Compute blind indexes
  const emailToIndex = new Map<string, string>();
  for (const email of EMAILS) {
    emailToIndex.set(email, await blindIndex(email, PII_KEY));
  }

  // Batch fetch UUIDs from DB
  const rows = await db.query.users.findMany({
    where: inArray(schema.users.emailIndex, [...emailToIndex.values()]),
    columns: { id: true, emailIndex: true },
  });

  const indexToId = new Map(rows.map((u) => [u.emailIndex, u.id]));
  const emailToId = new Map<string, string>();
  for (const [email, idx] of emailToIndex) {
    const id = indexToId.get(idx);
    if (id) emailToId.set(email, id);
    else console.warn(`  NOT FOUND in DB: ${email}`);
  }

  const loginsPath = resolve(process.cwd(), '../../Docs/logins.dev');
  let content = readFileSync(loginsPath, 'utf8');
  let updated = 0;

  // For each email, find its block and replace/insert the User ID
  for (const [email, newId] of emailToId) {
    const emailEsc = email.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

    // Try to replace existing "User ID  │ <uuid>" within 400 chars after email occurrence
    const blockRe = new RegExp(
      `(${emailEsc}[\\s\\S]{0,400}?)(User ID\\s*│\\s*)(${UUID_RE.source})`,
      'i',
    );
    if (blockRe.test(content)) {
      content = content.replace(blockRe, `$1$2${newId}`);
      updated++;
      continue;
    }

    // admin@example.dev line 1 — no User ID field, insert after the credentials line
    if (email === 'admin@example.dev') {
      const adminLineRe = /^(admin@example\.dev .+)$/m;
      if (adminLineRe.test(content)) {
        content = content.replace(adminLineRe, `$1\nUser ID │ ${newId}`);
        updated++;
        scriptOutput(`  Inserted User ID for ${email}: ${newId}`);
      }
    }
  }

  writeFileSync(loginsPath, content, 'utf8');
  scriptOutput(`\n✓ Updated ${updated} entries in logins.dev\n`);

  for (const [email, id] of [...emailToId].sort((a, b) => a[0].localeCompare(b[0]))) {
    scriptOutput(`  ${email.padEnd(46)} ${id}`);
  }

  await pool.end();
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
