import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";

const mocks = vi.hoisted(() => ({
  readLocalFileSafely: vi.fn(),
}));

vi.mock("../infra/fs-safe.js", async (importOriginal) => {
  const actual = await importOriginal<typeof import("../infra/fs-safe.js")>();
  return {
    ...actual,
    readLocalFileSafely: mocks.readLocalFileSafely,
  };
});

type StoreModule = typeof import("./store.js");
type FsSafeModule = typeof import("../infra/fs-safe.js");

let saveMediaSource: StoreModule["saveMediaSource"];
let SafeOpenError: FsSafeModule["SafeOpenError"];

async function expectOutsideWorkspaceStoreFailure(sourcePath: string) {
  await expect(saveMediaSource(sourcePath)).rejects.toMatchObject({
    code: "invalid-path",
    message: "Media path is outside workspace root",
  });
}

describe("media store outside-workspace mapping", () => {
  let tempHome: TempHomeEnv;
  let home = "";

  beforeEach(async () => {
    vi.resetModules();
    ({ saveMediaSource } = await import("./store.js"));
    ({ SafeOpenError } = await import("../infra/fs-safe.js"));
  });

  beforeAll(async () => {
    tempHome = await createTempHomeEnv("openclaw-media-store-test-home-");
    home = tempHome.home;
  });

  afterAll(async () => {
    await tempHome.restore();
  });

  it("maps outside-workspace reads to a descriptive invalid-path error", async () => {
    const sourcePath = path.join(home, "outside-media.txt");
    await fs.writeFile(sourcePath, "hello");
    mocks.readLocalFileSafely.mockRejectedValueOnce(
      new SafeOpenError("outside-workspace", "file is outside workspace root"),
    );

    await expectOutsideWorkspaceStoreFailure(sourcePath);
  });
});
