import path from "node:path";
import { fileURLToPath } from "node:url";
import fg from "fast-glob";
import { describe, expect, it } from "vitest";
import { readJsonFile } from "../../../lib/parse-json";
import { checkCompatRange, compat } from "./compat-range";
import { ManifestSchema, type Manifest, type WorkspacePackage } from "./shared";

describe("checkCompatRange", () => {
  function sdkPkg(version: string): WorkspacePackage[] {
    return [
      {
        relativePath: "apps/web/backend/package.json",
        manifest: { dependencies: { "@tailor-platform/sdk": version } },
      },
    ];
  }

  it("passes an exact pin inside the compat range", () => {
    expect(checkCompatRange(sdkPkg("1.55.0"))).toEqual([]);
  });

  it("errors an exact pin outside the compat range", () => {
    const [finding] = checkCompatRange(sdkPkg("1.20.0"));
    expect(finding?.severity).toBe("error");
    expect(finding?.message).toContain("does not satisfy");
    expect(finding?.message).toContain("@tailor-platform/sdk@1.20.0");
  });

  it("warns on a range that is a subset of compat", () => {
    const [finding] = checkCompatRange(sdkPkg("^1.56.0"));
    expect(finding?.severity).toBe("warning");
    expect(finding?.message).toContain("pinned to an exact version");
  });

  it("errors on a range that admits versions outside compat", () => {
    const [finding] = checkCompatRange(sdkPkg("^1.0.0"));
    expect(finding?.severity).toBe("error");
    expect(finding?.message).toContain("admits versions outside");
  });

  it("errors on an invalid specifier", () => {
    const [finding] = checkCompatRange(sdkPkg("not-a-version"));
    expect(finding?.severity).toBe("error");
    expect(finding?.message).toContain("is not a valid version or range");
  });

  it("warns on a non-semver specifier", () => {
    const [finding] = checkCompatRange(sdkPkg("catalog:"));
    expect(finding?.severity).toBe("warning");
    expect(finding?.message).toContain("non-semver specifier");
  });
});

describe("compat ranges stay in sync with the repo", () => {
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
  const packageRoot = path.resolve(__dirname, "../../../../..");

  function readManifest(filePath: string): Manifest {
    const result = readJsonFile(filePath, ManifestSchema);
    if (!result.ok) throw new Error(result.error);
    return result.data;
  }

  it("ensures template package.json pins satisfy the declared compat ranges", async () => {
    const templatePackageJsons = await fg("templates/scaffold/**/package.json", {
      cwd: packageRoot,
      absolute: true,
      ignore: ["**/node_modules/**"],
    });
    expect(templatePackageJsons.length).toBeGreaterThan(0);

    const packages = templatePackageJsons.map((filePath) => ({
      relativePath: path.relative(packageRoot, filePath),
      manifest: readManifest(filePath),
    }));
    expect(checkCompatRange(packages)).toEqual([]);
  });

  it("declares an SDK range identical to the published peerDependencies range", () => {
    const pkg = readManifest(path.join(packageRoot, "package.json"));
    const peerRange = pkg.peerDependencies?.["@tailor-platform/sdk"];
    expect(peerRange).toBeDefined();
    expect(compat["@tailor-platform/sdk"]!.range).toBe(peerRange);
  });
});
