const assert = require("assert");
const fs = require("fs");
const path = require("path");
const { findSafeTarget } = require("../src/services/versioning");

const root = path.join(__dirname, "..");
const releaseVersion = "0.2.25";
const previousStableVersion = "0.2.24";
const priorStableVersion = "0.2.23";
const earliestCompatibleCoreVersion = "0.1.9";
const changedPlugins = {
  "auto-vc": { from: "0.1.5", to: "0.1.6", knowledge: "auto-vc" },
  birthday: { from: "0.1.2", to: "0.1.3", knowledge: "birthday" },
  "economy-framework": { from: "0.2.9", to: "0.2.10", knowledge: "economy-framework" },
  "expression-interaction": { from: "0.2.0", to: "0.2.1", knowledge: "expression-interaction" },
  lumi_ai: { from: "0.8.4", to: "0.8.5", knowledge: "lumi-ai" },
  moderation: { from: "0.1.4", to: "0.1.5", knowledge: "moderation" },
  okf: { from: "0.1.1", to: "0.1.2", knowledge: "okf" },
  quotes: { from: "0.1.1", to: "0.1.2", knowledge: "quotes" },
  throne_wishlist: { from: "0.1.1", to: "0.1.2", knowledge: "throne-wishlist" },
  welcome_messages: { from: "0.1.0", to: "0.1.1", knowledge: "welcome-messages" }
};

function readJson(relativePath) {
  return JSON.parse(fs.readFileSync(path.join(root, relativePath), "utf8"));
}

function readText(relativePath) {
  return fs.readFileSync(path.join(root, relativePath), "utf8");
}

function escapeRegex(value) {
  return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function hasVersionHeading(markdown, version) {
  return new RegExp(`^#{1,3}\\s+\\[?v?${escapeRegex(version)}\\]?(?:\\s|$)`, "m").test(markdown);
}

const packageJson = readJson("package.json");
const packageLock = readJson("package-lock.json");
const coreManifest = readJson("update-manifest.json");
const releaseIndex = readJson("release-index.json");
assert.equal(packageJson.version, releaseVersion);
assert.equal(packageLock.version, releaseVersion);
assert.equal(packageLock.packages?.[""]?.version, releaseVersion);
assert.equal(coreManifest.version, releaseVersion);
assert.equal(coreManifest.channel, "stable");
assert.equal(coreManifest.compatible_from, earliestCompatibleCoreVersion);
assert.equal(coreManifest.rollback_safe, true);
assert.deepEqual(coreManifest.replaces_versions, ["1.2.0"]);
assert.equal(releaseIndex.releases[0].version, releaseVersion);
assert.equal(releaseIndex.releases[0].ref, `refs/tags/v${releaseVersion}`);
assert.equal(releaseIndex.releases[1].version, previousStableVersion);
assert.equal(releaseIndex.releases[1].ref, `refs/tags/v${previousStableVersion}`);
assert.equal(releaseIndex.releases[2].version, priorStableVersion);
assert.equal(releaseIndex.releases[2].ref, `refs/tags/v${priorStableVersion}`);
assert.equal(releaseIndex.releases.at(-1).version, earliestCompatibleCoreVersion);
assert.equal(hasVersionHeading(readText("CHANGELOG.md"), releaseVersion), true);
assert.match(readText("knowledge/core/lumi-core.md"), new RegExp(`^Version: ${escapeRegex(releaseVersion)}$`, "m"));

const safeCoreTarget = findSafeTarget(previousStableVersion, [
  ...(Array.isArray(coreManifest.versions) ? coreManifest.versions : []),
  coreManifest
]);
assert.equal(safeCoreTarget.blocked, false);
assert.equal(safeCoreTarget.target?.version, releaseVersion);

for (const [pluginId, expected] of Object.entries(changedPlugins)) {
  const manifest = readJson(`plugins/${pluginId}/plugin.json`);
  assert.equal(manifest.version, expected.to, `${pluginId} manifest version`);
  assert.equal(manifest.compatible_from, expected.from, `${pluginId} compatible_from`);
  assert.equal(manifest.channel, "stable", `${pluginId} release channel`);
  assert.equal(manifest.rollback_safe, true, `${pluginId} rollback metadata`);
  assert.equal(
    hasVersionHeading(readText(`plugins/${pluginId}/CHANGELOG.md`), expected.to),
    true,
    `${pluginId} changelog heading`
  );
  assert.match(
    readText(`knowledge/plugins/${expected.knowledge}.md`),
    new RegExp(`^Version: ${escapeRegex(expected.to)}$`, "m"),
    `${pluginId} generated knowledge version`
  );
}

const webSearch = readJson("plugins/lumi_ai_web_search/tool_info.json");
assert.equal(webSearch.version, "0.1.1");
assert.equal(webSearch.minimum_lumi_version, "0.2.0");
assert.equal(webSearch.minimum_lumi_ai_version, "0.8.2");
assert.equal(hasVersionHeading(readText("plugins/lumi_ai_web_search/CHANGELOG.md"), webSearch.version), true);

console.log("Release metadata verification passed: stable core 0.2.25 after 0.2.24, Lumi AI 0.8.5, and synchronized package metadata.");
