import { createHash } from "node:crypto";

/**
 * Normalisiert eine Domain für Hashing — muss zwischen Server und iOS-Extension
 * IDENTISCH sein, sonst stimmen die Hashes nicht überein.
 *
 * Schritte:
 * 1. trim, lowercase
 * 2. http:// und https:// entfernen
 * 3. Pfad / Query nach erstem `/` abschneiden
 * 4. Optional `www.` Prefix entfernen (so dass `www.bet365.com` und `bet365.com`
 *    den gleichen Hash haben)
 */
export function normalizeDomain(input: string): string {
  return input
    .trim()
    .toLowerCase()
    .replace(/^https?:\/\//, "")
    .replace(/\/.*$/, "")
    .replace(/^www\./, "");
}

/**
 * SHA-256 → erste 8 Bytes als big-endian UInt64.
 * Wenn salt gesetzt ist, wird `<salt>:<domain>` gehasht (für user-spezifische
 * Custom-Domains, damit gleiche Domain bei zwei Usern unterschiedliche
 * Hashes ergibt → keine Cross-User-Korrelation möglich).
 */
export function hashDomain(domain: string, salt = ""): bigint {
  const normalized = normalizeDomain(domain);
  const input = salt ? `${salt}:${normalized}` : normalized;
  const digest = createHash("sha256").update(input, "utf8").digest();
  return digest.readBigUInt64BE(0);
}

/**
 * Hasht eine Liste von Domains, sortiert die Hashes aufsteigend, und gibt
 * sie als Binary-Buffer zurück (8 Bytes pro Hash, big-endian).
 *
 * Format der Binary-Datei für die iOS-Extension:
 *   ┌────────────────┬────────────────┬─────────────────┐
 *   │  Hash 0 (8 B)  │  Hash 1 (8 B)  │  Hash 2 (8 B)   │  ...
 *   └────────────────┴────────────────┴─────────────────┘
 *   sorted ascending → binary-search möglich, O(log n).
 */
export function buildHashListBinary(domains: string[], salt = ""): Buffer {
  const hashes = new BigUint64Array(domains.length);
  for (let i = 0; i < domains.length; i++) {
    hashes[i] = hashDomain(domains[i], salt);
  }
  hashes.sort();

  // BigUint64Array ist platform-endian — wir brauchen explicit big-endian
  // damit Server und iOS-Extension dasselbe Format lesen.
  const buf = Buffer.alloc(hashes.length * 8);
  for (let i = 0; i < hashes.length; i++) {
    buf.writeBigUInt64BE(hashes[i], i * 8);
  }
  return buf;
}

/**
 * ETag aus dem Binary-Content (sha256 der Bytes, hex-encoded).
 * Client cached darauf basierend → wenn Server-DB sich nicht ändert,
 * spart Bandbreite + Battery.
 */
export function etagFor(buf: Buffer): string {
  return `"${createHash("sha256").update(buf).digest("hex").slice(0, 16)}"`;
}
