import { afterEach, expect, test } from "bun:test";
import {
  clearRegistry,
  NativeUnavailableError,
  platform,
  register,
  run,
  supports,
} from "../src/registry.ts";
import { mobileCapabilities } from "../src/mobile.ts";

afterEach(clearRegistry);

test("registers and runs a browser capability", async () => {
  register("example.echo", { browser: { run: (options) => options } });
  expect(supports("example.echo", "browser")).toBe(true);
  expect(await run<{ value: number }>("example.echo", { value: 3 }, { target: "browser" })).toEqual(
    { value: 3 },
  );
});

test("reports unsupported adapters without invoking them", async () => {
  register("example.mobile", { mobile: { supported: () => false, run: () => "no" } });
  expect(supports("example.mobile", "mobile")).toBe(false);
  expect(run("example.mobile", undefined, { target: "mobile" })).rejects.toBeInstanceOf(
    NativeUnavailableError,
  );
});

test("unregister callback removes a custom capability", () => {
  const unregister = register("example.temp", { browser: { run: () => true } });
  expect(supports("example.temp", "browser")).toBe(true);
  unregister();
  expect(supports("example.temp", "browser")).toBe(false);
});

test("reports server rather than browser during SSR", () => {
  const root = globalThis as typeof globalThis & { window?: Window };
  const existing = Object.getOwnPropertyDescriptor(root, "window");
  Reflect.deleteProperty(root, "window");
  expect(platform()).toBe("server");
  if (existing) Object.defineProperty(root, "window", existing);
});

test("mirrors custom registration into the declarative browser runtime", () => {
  const calls: string[] = [];
  const root = globalThis as typeof globalThis & { WrNexusNative?: object };
  root.WrNexusNative = {
    target: "browser",
    isMobile: false,
    register: (name: string) => calls.push(`add:${name}`),
    unregister: (name: string) => calls.push(`remove:${name}`),
    supports: () => true,
    run: async () => undefined,
  };
  const unregister = register("example.mirror", { browser: { run: () => true } });
  unregister();
  delete root.WrNexusNative;
  expect(calls).toEqual(["add:example.mirror", "remove:example.mirror"]);
});

test("normalizes unified clipboard options for Capacitor", async () => {
  let received: unknown;
  const root = globalThis as typeof globalThis & { Capacitor?: object };
  root.Capacitor = {
    Plugins: { Clipboard: { write: (options: unknown) => (received = options) } },
  };
  await mobileCapabilities["clipboard.write"]!.mobile!.run({ text: "hello" });
  delete root.Capacitor;
  expect(received).toEqual({ string: "hello" });
});

test("normalizes a simple notification into Capacitor's notification list", async () => {
  let received: unknown;
  const root = globalThis as typeof globalThis & { Capacitor?: object };
  root.Capacitor = {
    Plugins: { LocalNotifications: { schedule: (options: unknown) => (received = options) } },
  };
  await mobileCapabilities["notifications.schedule"]!.mobile!.run({
    id: 7,
    title: "Hi",
    body: "There",
  });
  delete root.Capacitor;
  expect(received).toEqual({
    notifications: [{ id: 7, title: "Hi", body: "There", schedule: undefined }],
  });
});
