"use strict";

const crypto = require("node:crypto");
const fs = require("node:fs");
const path = require("node:path");

class GhdrAuthorizer {
  constructor({
    privateKeyFile = "/var/lib/guanghu/lake-lamp-authz/ghdr-authorizer-private.pem",
    now = () => Math.floor(Date.now() / 1000),
  } = {}) {
    this.privateKeyFile = privateKeyFile;
    this.now = now;
    this.privateKey = this.loadOrCreate();
    this.publicKey = crypto.createPublicKey(this.privateKey);
  }

  loadOrCreate() {
    if (fs.existsSync(this.privateKeyFile)) {
      const metadata = fs.lstatSync(this.privateKeyFile);
      if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.mode & 0o077) {
        throw new Error("ghdr_authorizer_private_key_permissions_invalid");
      }
      return crypto.createPrivateKey(fs.readFileSync(this.privateKeyFile));
    }
    fs.mkdirSync(path.dirname(this.privateKeyFile), { recursive: true, mode: 0o700 });
    const { privateKey } = crypto.generateKeyPairSync("ed25519");
    const pem = privateKey.export({ type: "pkcs8", format: "pem" });
    const temporary = `${this.privateKeyFile}.${process.pid}.tmp`;
    fs.writeFileSync(temporary, pem, { mode: 0o600, flag: "wx" });
    fs.renameSync(temporary, this.privateKeyFile);
    return privateKey;
  }

  publicBinding() {
    const publicPem = this.publicKey.export({ type: "spki", format: "pem" });
    const fingerprint = crypto.createHash("sha256").update(publicPem).digest("hex");
    return {
      schema: "guanghu.ghdr-authorizer-public-binding/v1",
      authorizer_id: "JD-FD-PRIMARY-LAKE-LAMP",
      algorithm: "Ed25519",
      public_key_pem: publicPem,
      public_key_sha256: fingerprint,
    };
  }

  issue({
    controllerNodeId,
    targetNodeId,
    layoutPayloadSha256,
    resource,
    workorderId,
  }) {
    const issued = this.now();
    const capability = {
      schema: "guanghu.ghdr-signing-capability/v1",
      authorizer_id: "JD-FD-PRIMARY-LAKE-LAMP",
      controller_node_id: controllerNodeId,
      target_node_id: targetNodeId,
      layout_payload_sha256: layoutPayloadSha256,
      resource,
      workorder_id: workorderId,
      issued_at_unix: issued,
      expires_at_unix: issued + 120,
      nonce: crypto.randomBytes(24).toString("base64url"),
    };
    const canonical = Buffer.from(JSON.stringify(capability));
    return {
      capability,
      capability_signature_base64url: crypto.sign(null, canonical, this.privateKey).toString("base64url"),
    };
  }
}

module.exports = { GhdrAuthorizer };
