import { describe, it, expect, vi, afterEach } from "vitest";
import {
  isFileMakerEnvironment,
  performScript,
  performScriptWithOption,
  resolveFileMakerCallback,
} from "./webviewer";

function setFileMaker(api: FileMakerAPI | undefined) {
  Object.defineProperty(globalThis, "FileMaker", {
    value: api,
    configurable: true,
    writable: true,
  });
}

afterEach(() => {
  setFileMaker(undefined);
});

describe("isFileMakerEnvironment", () => {
  it("returns false when FileMaker is not defined", () => {
    expect(isFileMakerEnvironment()).toBe(false);
  });

  it("returns true when FileMaker is defined", () => {
    setFileMaker({ PerformScript: vi.fn(), PerformScriptWithOption: vi.fn() });
    expect(isFileMakerEnvironment()).toBe(true);
  });
});

describe("performScript", () => {
  it("returns false when FileMaker is not available", () => {
    expect(performScript("TestScript")).toBe(false);
  });

  it("calls FileMaker.PerformScript and returns true when available", () => {
    const mock = vi.fn();
    setFileMaker({ PerformScript: mock, PerformScriptWithOption: vi.fn() });
    expect(performScript("MyScript", "param")).toBe(true);
    expect(mock).toHaveBeenCalledWith("MyScript", "param");
  });
});

describe("performScriptWithOption", () => {
  it("returns false when FileMaker is not available", () => {
    expect(performScriptWithOption("TestScript")).toBe(false);
  });

  it("calls FileMaker.PerformScriptWithOption with option", () => {
    const mock = vi.fn();
    setFileMaker({ PerformScript: vi.fn(), PerformScriptWithOption: mock });
    expect(performScriptWithOption("MyScript", "param", "3")).toBe(true);
    expect(mock).toHaveBeenCalledWith("MyScript", "param", "3");
  });
});

describe("resolveFileMakerCallback", () => {
  it("does nothing for an unknown callback ID", () => {
    expect(() => resolveFileMakerCallback("9999")).not.toThrow();
  });

  it("resolves a pending promise registered via callFileMakerScript", async () => {
    const { callFileMakerScript } = await import("./webviewer");

    let capturedId: number | undefined;
    setFileMaker({
      PerformScript: (_script, payload) => {
        capturedId = JSON.parse(payload ?? "").callbackId;
      },
      PerformScriptWithOption: vi.fn(),
    });

    const promise = callFileMakerScript("TestScript", "hello");
    resolveFileMakerCallback(String(capturedId), "result-data");
    await expect(promise).resolves.toBe("result-data");
  });

  it("rejects a pending promise when isError is true", async () => {
    const { callFileMakerScript } = await import("./webviewer");

    let capturedId: number | undefined;
    setFileMaker({
      PerformScript: (_script, payload) => {
        capturedId = JSON.parse(payload ?? "").callbackId;
      },
      PerformScriptWithOption: vi.fn(),
    });

    const promise = callFileMakerScript("TestScript", "hello");
    resolveFileMakerCallback(String(capturedId), "error message", true);
    await expect(promise).rejects.toMatchObject({ message: "error message" });
  });
});
