#!/usr/bin/env node

"use strict";

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

const root = path.resolve(__dirname, "..");
const packagePath = path.join(root, "package.json");
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
const args = new Set(process.argv.slice(2));
const json = args.has("--json");
const allowLocal = args.has("--allow-local") || args.has("--allow-draft");
const localOnly = packageJson.private === true && packageJson.license === "UNLICENSED";

const issues = [];
const warnings = [];

function issue(field, message) {
  issues.push({ field, message });
}

function warning(field, message) {
  warnings.push({ field, message });
}

if (!packageJson.name || packageJson.name === "jso-protector") {
  if (!localOnly) {
    warning("name", "Confirm the final public npm name or approved scope before publishing.");
  }
}

if (packageJson.private !== true) {
  issue("private", "This package is local-only. Keep private:true to block npm registry publishing.");
}

if (packageJson.license !== "UNLICENSED") {
  issue("license", "This package is local-only. Keep license set to UNLICENSED unless a public license is approved.");
}

if (!packageJson.description || packageJson.description.length < 20) {
  issue("description", "Provide a concise npm package description.");
}

if (!packageJson.homepage) {
  issue("homepage", "Provide a homepage that points to the npm CLI documentation.");
}

if (!packageJson.author) {
  issue("author", "Provide the publishing organization or maintainer.");
}

if (!packageJson.bin || !packageJson.bin["jso-protector"]) {
  issue("bin", "Expose the jso-protector CLI binary.");
}

if (!packageJson.files || !packageJson.files.includes("README.md") || !packageJson.files.includes("SECURITY.md")) {
  issue("files", "Pack README.md and SECURITY.md with the npm artifact.");
}

if (!packageJson.scripts || !String(packageJson.scripts.verify || "").includes("verify:package")) {
  warning("scripts.verify", "Consider a single npm run verify script that includes tests and package verification.");
}

if (!packageJson.repository) {
  if (!localOnly) {
    warning("repository", "Add repository metadata when the public source location is final.");
  }
}

if (!packageJson.bugs) {
  if (!localOnly) {
    warning("bugs", "Add issue/support metadata when the public support channel is final.");
  }
}

const report = {
  format: "jso-protector-publish-metadata",
  ok: issues.length === 0,
  publishReady: !localOnly && issues.length === 0 && warnings.length === 0,
  localOnly,
  localAllowed: allowLocal,
  issues,
  warnings
};

if (json) {
  process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
} else {
  if (report.ok && localOnly && allowLocal) {
    process.stdout.write("Local-only package metadata is locked. npm publish remains blocked by prepublishOnly.\n");
  } else if (report.ok && localOnly) {
    process.stdout.write("Package is intentionally local-only. Refusing publish-ready mode while private:true and UNLICENSED are set.\n");
  } else if (report.publishReady) {
    process.stdout.write("Publish metadata is ready.\n");
  } else {
    process.stdout.write(`Package metadata has ${issues.length} blocking issue(s) and ${warnings.length} warning(s).\n`);
    for (const item of issues) {
      process.stdout.write(`BLOCKER ${item.field}: ${item.message}\n`);
    }
    for (const item of warnings) {
      process.stdout.write(`WARNING ${item.field}: ${item.message}\n`);
    }
  }
}

if ((!allowLocal && localOnly) || (issues.length && !allowLocal)) {
  process.exitCode = 1;
}
