// Raw access to host-registered headless services — the escape hatch for services that
// have no typed wrapper (yet). First-party services ship wrapped (Geolocation); app-local
// native code (an `engine.registerService` in the app shell) and third-party plugins are
// reachable through this global immediately, wrapper or not. Thin sugar over the internal
// ServiceClient (src/runtime/service.ts) — same JSON call/event channel, same lazy session.

import { ServiceClient } from "../runtime/service"

export interface Service {
  /** Invoke a method on the service (`battery.call("level")`). Arguments and the result are
   *  JSON-serialized; rejects when the host has no such service or the method reports an
   *  error. The host session opens lazily on the first call. */
  call(method: string, ...args: any[]): Promise<any>
  /** Subscribe to an event the service emits while a session is open
   *  (`battery.on("change", data => …)`). Payloads are JSON-decoded. */
  on(event: string, callback: (data?: any) => void): this
  /** Remove a previously added listener. */
  off(event: string, callback: (data?: any) => void): this
  /** Close the host session (stops whatever the service was doing). Listeners stay
   *  registered — a later `call()` opens a fresh session that delivers to them again. */
  close(): void
}

/**
 * A host-registered headless service — the UI-less sibling of `NativeView`. Use it for
 * services without a typed wrapper: native code registered in your app shell
 * (`engine.registerService("app.battery") { … }`) or a third-party plugin's channel.
 * **Host-optional** — gate on `Service.isSupported` (the web editor registers none of them).
 *
 * ```ts
 * if (Service.isSupported("app.battery")) {
 *   const battery = Service("app.battery")
 *   battery.on("change", data => { level.text = data.level + "%" })
 *   const { level } = await battery.call("level")
 * }
 * ```
 */
// PURE IIFE so an app that never touches raw services tree-shakes this away.
export const Service: {
  (name: string, params?: any): Service
  /** Whether this host registered a service under `name`. */
  isSupported(name: string): boolean
} = /*#__PURE__*/ (() => {
  const factory = (name: string, params: any = {}): Service => new ServiceClient(name, params) as unknown as Service
  factory.isSupported = (name: string): boolean => ServiceClient.isSupported(name)
  return factory as any
})()
