/** @wrnexus/mobile — SSR-safe access to Capacitor's native bridge. */

export { native } from "@wrnexus/native";

export type MobilePlatform = "ios" | "android" | "web" | string;

export interface CapacitorBridge {
  isNativePlatform?: () => boolean;
  getPlatform?: () => MobilePlatform;
  Plugins?: Record<string, unknown>;
}

export class MobileUnavailableError extends Error {
  constructor(message = "A Capacitor native runtime is not available") {
    super(message);
    this.name = "MobileUnavailableError";
  }
}

function bridge(): CapacitorBridge | undefined {
  if (typeof globalThis === "undefined") return undefined;
  return (globalThis as typeof globalThis & { Capacitor?: CapacitorBridge }).Capacitor;
}

const registered = new Map<string, object>();

/** Register a plugin imported by browser-only application code. */
export function registerPlugin<T extends object>(name: string, instance: T): T {
  registered.set(name, instance);
  return instance;
}

/** True only inside a native Capacitor iOS or Android WebView. SSR-safe. */
export function isNative(): boolean {
  return bridge()?.isNativePlatform?.() ?? false;
}

/** Current Capacitor platform, falling back to `web` during SSR and in browsers. */
export function platform(): MobilePlatform {
  return bridge()?.getPlatform?.() ?? "web";
}

/** Return an injected Capacitor plugin, or undefined when it is unavailable. */
export function plugin<T extends object>(name: string): T | undefined {
  if (!isNative()) return undefined;
  return (registered.get(name) ?? bridge()?.Plugins?.[name]) as T | undefined;
}

/** Require an installed native plugin and produce a useful error when absent. */
export function requirePlugin<T extends object>(name: string): T {
  const value = plugin<T>(name);
  if (!value) {
    throw new MobileUnavailableError(
      `Capacitor plugin "${name}" is unavailable. Run \`wrnexus mobile add <package>\` and rebuild the native app.`,
    );
  }
  return value;
}

/** Invoke a plugin method without importing native code into an SSR module. */
export async function invoke<TResult = unknown>(
  pluginName: string,
  method: string,
  options?: unknown,
): Promise<TResult> {
  const target = requirePlugin<Record<string, unknown>>(pluginName);
  const fn = target[method];
  if (typeof fn !== "function") {
    throw new MobileUnavailableError(`Capacitor plugin "${pluginName}" has no method "${method}".`);
  }
  return (await fn.call(target, options)) as TResult;
}

/** Run native behavior when available, with an optional SSR/web fallback. */
export async function whenNative<T>(
  native: () => T | Promise<T>,
  fallback?: () => T | Promise<T>,
): Promise<T | undefined> {
  if (isNative()) return native();
  return fallback?.();
}

export const mobile = {
  isNative,
  platform,
  registerPlugin,
  plugin,
  requirePlugin,
  invoke,
  whenNative,
};
export {
  listenDeepLinks,
  parseDeepLink,
  memoryOfflineTaskStore,
  OfflineQueue,
  PushNotifications,
  SecureStorage,
  mobileEnvironment,
} from "./advanced.ts";
export type {
  DeepLink,
  DeepLinkSource,
  OfflineTask,
  OfflineTaskStore,
  MobileEnvironment,
  PushAdapter,
  PushRegistration,
  SecureStorageAdapter,
} from "./advanced.ts";
