import { randomBytes, randomUUID } from "crypto";
import { execFileSync } from "child_process";
import { writeFileSync, mkdtempSync, readFileSync, rmSync } from "fs";
import { tmpdir } from "os";
import { join } from "path";

/**
 * Cooldown (Stunden) zwischen Entfern-Antrag und Sichtbarwerden des
 * Removal-Passworts. Schützt gegen impulsives Abschalten im Drang-Fenster.
 * Bewusst gleich dem Mobile-Device-Lock (24h) gehalten.
 */
export const MAGIC_RELEASE_COOLDOWN_H = 24;

const PW_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // ohne 0/O/1/I/L
const PW_LEN = 10;

/**
 * Generiert ein menschenlesbares Removal-Passwort (Offboarding tippt es ab).
 * 10 Zeichen, keine mehrdeutigen Glyphen. ~50 Bit Entropie.
 */
export function generateRemovalPassword(): string {
  const bytes = randomBytes(PW_LEN);
  let out = "";
  for (let i = 0; i < PW_LEN; i++) {
    out += PW_ALPHABET[bytes[i] % PW_ALPHABET.length];
  }
  return out;
}

/**
 * Baut das com.apple.profileRemovalPassword-Payload-Dict (als XML-String),
 * das in die PayloadContent-Array des Mac/Win-Profils injiziert wird.
 */
export function buildRemovalPasswordPayload(
  password: string,
  deviceIdSlice: string,
): string {
  return `        <dict>
            <key>PayloadDisplayName</key>
            <string>Entfern-Passwort</string>
            <key>PayloadIdentifier</key>
            <string>org.rebreak.protection.removalpw.${deviceIdSlice}</string>
            <key>PayloadType</key>
            <string>com.apple.profileRemovalPassword</string>
            <key>PayloadUUID</key>
            <string>${randomUUID().toUpperCase()}</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>RemovalPassword</key>
            <string>${password}</string>
        </dict>`;
}

/**
 * Signiert ein mobileconfig-Profil per CMS (openssl smime), WENN Signing-Cert
 * + Key via runtimeConfig konfiguriert sind. Sonst wird das Profil UNSIGNIERT
 * zurückgegeben — der Lock (RemovalPassword + PayloadRemovalDisallowed +
 * ProhibitDisablement) greift auch unsigniert; macOS zeigt nur „Nicht
 * verifiziert" statt grünem Häkchen.
 *
 * ⚠️ Inaktiv bis Cert auf der API-Box provisioniert ist (Pfade via Infisical).
 * Verifiziertes Signing-Setup existiert bereits auf der mdm-Box (LE-Cert für
 * dns.rebreak.org) — die hier erwarteten Pfade müssen dort/da verfügbar sein.
 */
export function signProfileIfConfigured(
  profileXml: string,
  signing: { certPath?: string; keyPath?: string; chainPath?: string } | undefined,
): Buffer | string {
  if (!signing?.certPath || !signing.keyPath) {
    return profileXml; // unsigniert — Lock greift trotzdem
  }
  const dir = mkdtempSync(join(tmpdir(), "rbk-sign-"));
  const inPath = join(dir, "in.mobileconfig");
  const outPath = join(dir, "out.mobileconfig");
  try {
    writeFileSync(inPath, profileXml, "utf8");
    const args = [
      "smime",
      "-sign",
      "-signer",
      signing.certPath,
      "-inkey",
      signing.keyPath,
      "-nodetach",
      "-outform",
      "der",
      "-in",
      inPath,
      "-out",
      outPath,
    ];
    if (signing.chainPath) {
      args.push("-certfile", signing.chainPath);
    }
    execFileSync("openssl", args, { stdio: "pipe" });
    return readFileSync(outPath);
  } finally {
    rmSync(dir, { recursive: true, force: true });
  }
}
