/**
 * Resolve the WeChat Mini Program upload version.
 *
 * WeChat requires x.y.z with each segment in 0..999.
 * Server and miniapp versions are independent on purpose.
 *
 * Priority:
 * 1. MINIAPP_VERSION_OVERRIDE — full manual version (rare / release pinning)
 * 2. MINIAPP_BUILD_NUMBER — auto version from CI run number
 * 3. package.json version — local / fallback
 */

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

function readPackageVersion(projectPath) {
  const packageJson = JSON.parse(
    fs.readFileSync(path.join(projectPath, "package.json"), "utf8"),
  );
  if (!packageJson.version) {
    throw new Error("package.json version is missing.");
  }
  return String(packageJson.version);
}

function parseSemverParts(version) {
  const parts = String(version)
    .trim()
    .split(".")
    .map((part) => Number.parseInt(part, 10));
  if (
    parts.length < 1 ||
    parts.some((part) => !Number.isInteger(part) || part < 0 || part > 999)
  ) {
    throw new Error(
      `Invalid version "${version}". WeChat requires x.y.z with each segment 0-999.`,
    );
  }
  return {
    major: parts[0] ?? 0,
    minor: parts[1] ?? 0,
    patch: parts[2] ?? 0,
  };
}

/**
 * Encode a monotonic CI build number into WeChat x.y.z.
 * Keeps package.json major.minor as the baseline; build number maps to patch.
 * Examples (base 1.1.0): build 45 → 1.1.45, build 999 → 1.1.999
 * (patch wraps every 1000 builds; bump package.json minor before that)
 */
function versionFromBuildNumber(major, minor, buildNumber) {
  if (!Number.isInteger(buildNumber) || buildNumber < 1) {
    throw new Error("MINIAPP_BUILD_NUMBER must be a positive integer.");
  }
  if (!Number.isInteger(major) || major < 0 || major > 999) {
    throw new Error("package.json major version must be an integer 0-999.");
  }
  if (!Number.isInteger(minor) || minor < 0 || minor > 999) {
    throw new Error("package.json minor version must be an integer 0-999.");
  }

  const patch = buildNumber % 1000;
  return `${major}.${minor}.${patch}`;
}

/** @param {Record<string, string | undefined>} [env] */
function resolveVersion(projectPath, env = process.env) {
  const override = (env.MINIAPP_VERSION_OVERRIDE || "").trim();
  if (override) {
    parseSemverParts(override);
    return override;
  }

  const packageVersion = readPackageVersion(projectPath);
  const { major, minor } = parseSemverParts(packageVersion);

  const buildRaw = (env.MINIAPP_BUILD_NUMBER || "").trim();
  if (buildRaw) {
    const buildNumber = Number.parseInt(buildRaw, 10);
    return versionFromBuildNumber(major, minor, buildNumber);
  }

  // Legacy fixed override — prefer not to use; keeps version stuck across uploads.
  const legacy = (env.MINIAPP_VERSION || "").trim();
  if (legacy) {
    parseSemverParts(legacy);
    return legacy;
  }

  return packageVersion;
}

module.exports = {
  parseSemverParts,
  resolveVersion,
  versionFromBuildNumber,
};
