import { describe, it, expect, onTestFinished } from "vitest";
import {
  mkdtempSync,
  rmSync,
  cpSync,
  readFileSync,
  writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { execSync } from "node:child_process";
import { join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { computeSnapshot } from "../lib/snapshot.js";
import expectedSnapshot from "../__snapshots__/core-package/events.snapshot.json" with { type: "json" };

// Repo root is 2 levels up from turbo/generators/__tests__
const REPO_ROOT = resolve(
  fileURLToPath(import.meta.url),
  "..",
  "..",
  "..",
  "..",
);

/**
 * Strip "@repo/core-events" from a package.json file in the tmp tree.
 * Required when simulating a fresh scaffold: core-events does not exist yet
 * but the snapshot was captured before removal. Feature packages in the
 * current tree may still list it as a dependency.
 */
function stripCoreEventsDep(pkgJsonPath: string): void {
  const raw = readFileSync(pkgJsonPath, "utf8");
  const parsed = JSON.parse(raw) as Record<string, Record<string, string>>;
  for (const section of [
    "dependencies",
    "devDependencies",
    "peerDependencies",
  ] as const) {
    if (parsed[section]?.["@repo/core-events"]) {
      delete parsed[section]["@repo/core-events"];
    }
  }
  writeFileSync(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n");
}

describe("e2e: core-package events", () => {
  it(
    "byte-identical reconstruction matches snapshot",
    { timeout: 120_000 },
    () => {
      const tmp = mkdtempSync(join(tmpdir(), "e2e-events-"));
      // Each e2e run clones the repo into the OS temp dir; remove it when
      // the test finishes so sequential runs don't accumulate and fill disk.
      onTestFinished(() => rmSync(tmp, { recursive: true, force: true }));
      cpSync(REPO_ROOT, tmp, {
        recursive: true,
        filter: (src) =>
          !src.includes("node_modules") &&
          !src.includes(".turbo") &&
          !src.includes(".pnpm-store") &&
          !src.includes("packages/core-events"),
      });

      // Strip @repo/core-events from feature package.json files so pnpm install
      // succeeds without the package being present (simulating the post-removal state).
      const featurePackages = [
        "auth",
        "blog",
        "media",
        "marketing-pages",
        "navigation",
      ];
      for (const pkg of featurePackages) {
        const pkgJson = join(tmp, "packages", pkg, "package.json");
        stripCoreEventsDep(pkgJson);
      }
      // Also strip from apps/web-next
      stripCoreEventsDep(join(tmp, "apps", "web-next", "package.json"));

      execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
        stdio: "ignore",
      });
      execSync(`cd ${tmp} && pnpm turbo gen core-package --args events`, {
        stdio: "ignore",
      });
      const result = computeSnapshot(join(tmp, "packages/core-events"));
      expect(result).toEqual(expectedSnapshot);
    },
  );
});
