import { describe, expect, it } from "vitest";
import { sampleOlpProject } from "../../src/olp/index.js";
import {
  MemoryWorkspaceStorage,
  detectWorkspaceDamage,
  exportWorkspaceBundle,
  importWorkspaceBundle,
  initializeWorkspace,
  migrateManifest,
  readJson,
  readManifest,
  readProjectModel,
  restoreWorkspace,
  snapshotWorkspace,
  writeJson,
  writeProjectModel
} from "../../src/workspace/index.js";

const NOW = "2026-06-27T00:00:00.000Z";

describe("Workspace storage", () => {
  it("creates project manifest and conventional project layout", async () => {
    const storage = new MemoryWorkspaceStorage();
    const manifest = await initializeWorkspace(storage, {
      projectId: "demo_cell",
      name: "Demo Cell",
      model: sampleOlpProject(),
      now: NOW
    });

    expect(manifest.entrypoints.model).toBe("model/olp-project.json");
    expect(await storage.list()).toEqual(["model/olp-project.json", "project.json"]);
    expect(await readManifest(storage)).toEqual(manifest);
    expect((await readProjectModel(storage)).project.id).toBe("demo_cell");
  });

  it("supports text/json read-write-delete with OPFS-like async storage", async () => {
    const storage = new MemoryWorkspaceStorage();
    await storage.writeText("reports/readme.txt", "hello");
    await writeJson(storage, "imports/report.json", { ok: true, count: 2 });

    expect(await storage.readText("reports/readme.txt")).toBe("hello");
    expect(await readJson(storage, "imports/report.json")).toEqual({ ok: true, count: 2 });

    await storage.delete("reports/readme.txt");
    expect(await storage.exists("reports/readme.txt")).toBe(false);
  });

  it("snapshots and restores an equivalent workspace", async () => {
    const source = new MemoryWorkspaceStorage();
    await initializeWorkspace(source, {
      projectId: "demo_cell",
      name: "Demo Cell",
      model: sampleOlpProject(),
      now: NOW
    });
    await source.writeText("programs/main.grl", "language grl 0.1\n");
    const snapshot = await snapshotWorkspace(source);

    const target = new MemoryWorkspaceStorage({ "old.txt": "delete me" });
    await restoreWorkspace(target, snapshot);

    expect(await target.list()).toEqual(await source.list());
    expect(await snapshotWorkspace(target)).toEqual(snapshot);
  });

  it("exports and imports a stable JSON bundle with checksum", async () => {
    const source = new MemoryWorkspaceStorage();
    await initializeWorkspace(source, {
      projectId: "demo_cell",
      name: "Demo Cell",
      model: sampleOlpProject(),
      now: NOW
    });
    await source.writeText("programs/main.grl", "language grl 0.1\n");
    const bundle = await exportWorkspaceBundle(source);

    const target = new MemoryWorkspaceStorage();
    const report = await importWorkspaceBundle(target, bundle);

    expect(report).toEqual({ ok: true, damages: [] });
    expect(await snapshotWorkspace(target)).toEqual(await snapshotWorkspace(source));
  });

  it("migrates legacy manifests and detects damaged workspaces", async () => {
    expect(migrateManifest({
      schemaVersion: 0,
      projectId: "legacy",
      name: "Legacy",
      createdAt: NOW,
      updatedAt: NOW,
      modelPath: "legacy/model.json"
    })).toMatchObject({
      schemaVersion: 1,
      projectId: "legacy",
      entrypoints: { model: "legacy/model.json" }
    });

    const storage = new MemoryWorkspaceStorage();
    await initializeWorkspace(storage, {
      projectId: "demo_cell",
      name: "Demo Cell",
      model: sampleOlpProject(),
      now: NOW
    });
    const checksum = (await snapshotWorkspace(storage)).checksum;
    const model = await readProjectModel(storage);
    model.operations[0]!.pathId = "missing_path";
    await writeProjectModel(storage, model, NOW);

    expect(await detectWorkspaceDamage(storage, checksum)).toMatchObject({
      ok: false,
      damages: [
        expect.objectContaining({ code: "WORKSPACE_MODEL_INVALID" }),
        expect.objectContaining({ code: "WORKSPACE_CHECKSUM_MISMATCH" })
      ]
    });
  });

  it("rejects tampered bundles before import", async () => {
    const source = new MemoryWorkspaceStorage();
    await initializeWorkspace(source, {
      projectId: "demo_cell",
      name: "Demo Cell",
      model: sampleOlpProject(),
      now: NOW
    });
    const tampered = JSON.parse(await exportWorkspaceBundle(source)) as {
      files: Record<string, string>;
    };
    tampered.files["project.json"] = "{}";

    const target = new MemoryWorkspaceStorage();
    expect(await importWorkspaceBundle(target, JSON.stringify(tampered))).toMatchObject({
      ok: false,
      damages: [expect.objectContaining({ code: "WORKSPACE_CHECKSUM_MISMATCH" })]
    });
    expect(await target.list()).toEqual([]);
  });
});
