/**
 * Thin bridge over the Tauri JS API. Everything is dynamically imported so the
 * web bundle never pulls in `@tauri-apps/*` and `pnpm build` (web) keeps
 * working even if the native packages are absent.
 */
import { isTauriRuntime } from "@/lib/platform"

type InvokeFn = <T>(cmd: string, args?: Record<string, unknown>) => Promise<T>
type ListenFn = (
  event: string,
  handler: (e: { payload: unknown }) => void
) => Promise<() => void>

let invokeImpl: InvokeFn | null = null
let listenImpl: ListenFn | null = null

async function loadCore(): Promise<InvokeFn | null> {
  if (!isTauriRuntime()) return null
  if (invokeImpl) return invokeImpl
  try {
    const mod = (await import("@tauri-apps/api/core")) as { invoke: InvokeFn }
    invokeImpl = mod.invoke
    return invokeImpl
  } catch {
    return null
  }
}

async function loadEvent(): Promise<ListenFn | null> {
  if (!isTauriRuntime()) return null
  if (listenImpl) return listenImpl
  try {
    const mod = (await import("@tauri-apps/api/event")) as { listen: ListenFn }
    listenImpl = mod.listen
    return listenImpl
  } catch {
    return null
  }
}

/** Invoke a Tauri command. Returns null (no-op) outside a Tauri webview or on timeout. */
export async function invoke<T>(
  cmd: string,
  args?: Record<string, unknown>
): Promise<T | null> {
  const fn = await loadCore()
  if (!fn) return null
  try {
    return await Promise.race([
      fn<T>(cmd, args),
      new Promise<never>((_, reject) => {
        setTimeout(() => reject(new Error("invoke_timeout")), 5_000)
      }),
    ])
  } catch {
    return null
  }
}

/** Subscribe to a Tauri event. Returns an unsubscribe fn (no-op on web). */
export async function listen(
  event: string,
  handler: (payload: unknown) => void
): Promise<() => void> {
  const fn = await loadEvent()
  if (!fn) return () => {}
  return fn(event, (e) => handler(e.payload))
}
