import { mkdir, rename, writeFile } from "node:fs/promises";
import { basename, dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { assertKnownArgs, optionalArg, parseArgs, reportCliError, requiredArg } from "./cli.ts";
import { buildManifest } from "./manifest.ts";
import { installHostedSchemas, writeReleaseChecksums } from "./release-bundle.ts";

async function atomicWrite(path: string, contents: string): Promise<void> {
  await mkdir(dirname(path), { recursive: true });
  const temporary = `${path}.tmp-${process.pid}`;
  await writeFile(temporary, contents, { encoding: "utf8", mode: 0o644, flag: "wx" });
  await rename(temporary, path);
}

async function main(): Promise<void> {
  const args = parseArgs(process.argv.slice(2));
  assertKnownArgs(args, ["config", "out", "private-key", "key-id", "schema-ref", "schema-dir"]);
  const outputPath = resolve(requiredArg(args, "out"));
  const privateKeyPath = optionalArg(args, "private-key");
  const keyId = optionalArg(args, "key-id");
  const schemaRef = optionalArg(args, "schema-ref");
  const schemaDirectory = resolve(
    optionalArg(args, "schema-dir") ?? fileURLToPath(new URL("../schema", import.meta.url)),
  );
  const manifest = await buildManifest({
    sourcePath: resolve(requiredArg(args, "config")),
    ...(privateKeyPath === undefined ? {} : { privateKeyPath }),
    ...(keyId === undefined ? {} : { keyId }),
    ...(schemaRef === undefined ? {} : { schemaRef }),
  });
  const outputDirectory = dirname(outputPath);
  await installHostedSchemas(outputDirectory, schemaDirectory);
  await atomicWrite(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);
  await writeReleaseChecksums(outputDirectory, manifest);
  process.stdout.write(
    `Manifeste ${manifest.payload.releaseId} généré: ${basename(outputPath)} (${manifest.payload.artifacts.length} artefact(s), ${manifest.signature ? "signé" : "non signé"})\n`,
  );
}

main().catch(reportCliError);
