import { describe, it, expect, beforeEach, vi } from "vitest";
import { loadWorkspace, createDebouncedSave } from "../blockstorage";

// ---------------------------------------------------------------------------
// localStorage mock
// ---------------------------------------------------------------------------
const store = {};
const localStorageMock = {
  getItem: vi.fn((k) => store[k] ?? null),
  setItem: vi.fn((k, v) => { store[k] = v; }),
  removeItem: vi.fn((k) => { delete store[k]; }),
};
vi.stubGlobal("localStorage", localStorageMock);

beforeEach(() => {
  Object.keys(store).forEach((k) => delete store[k]);
  vi.clearAllMocks();
});

// ---------------------------------------------------------------------------
const VALID_WORKSPACE = { blocks: { blocks: [{ type: "mover" }] } };
const EMPTY_BLOCKS    = { blocks: { blocks: [] } };

describe("loadWorkspace()", () => {
  it("devolve null quando a chave não existe", () => {
    expect(loadWorkspace("absent")).toBeNull();
  });

  it("devolve o workspace quando válido", () => {
    store["ws"] = JSON.stringify(VALID_WORKSPACE);
    expect(loadWorkspace("ws")).toEqual(VALID_WORKSPACE);
  });

  it("devolve workspace com blocks vazio (array)", () => {
    store["ws"] = JSON.stringify(EMPTY_BLOCKS);
    expect(loadWorkspace("ws")).toEqual(EMPTY_BLOCKS);
  });

  it("devolve null quando blocks não é array", () => {
    store["ws"] = JSON.stringify({ blocks: { blocks: "não-array" } });
    expect(loadWorkspace("ws")).toBeNull();
  });

  it("devolve null quando blocks.blocks está ausente", () => {
    store["ws"] = JSON.stringify({ blocks: {} });
    expect(loadWorkspace("ws")).toBeNull();
  });

  it("devolve null quando o JSON está corrompido", () => {
    store["ws"] = "{ broken";
    expect(loadWorkspace("ws")).toBeNull();
    expect(localStorageMock.removeItem).toHaveBeenCalledWith("ws");
  });
});

describe("createDebouncedSave()", () => {
  it("retorna uma função de save", () => {
    expect(typeof createDebouncedSave()).toBe("function");
  });

  it("instâncias diferentes são independentes", () => {
    expect(createDebouncedSave()).not.toBe(createDebouncedSave());
  });

  it("quando invocada com delay=0 persiste workspace válido", async () => {
    const save = createDebouncedSave(0);
    save("ws", VALID_WORKSPACE);
    await new Promise((r) => setTimeout(r, 10));
    expect(localStorageMock.setItem).toHaveBeenCalledWith(
      "ws",
      JSON.stringify(VALID_WORKSPACE),
    );
  });

  it("quando invocada com delay=0 remove chave para workspace inválido", async () => {
    const save = createDebouncedSave(0);
    save("ws", null);
    await new Promise((r) => setTimeout(r, 10));
    expect(localStorageMock.removeItem).toHaveBeenCalledWith("ws");
    expect(localStorageMock.setItem).not.toHaveBeenCalled();
  });
});
