/**
 * Wait for a provider's `synced` event with a timeout.
 */
export function waitForSync(
  provider: { on(event: string, cb: () => void): void; off(event: string, cb: () => void): void },
  timeoutMs = 15000
): Promise<void> {
  return new Promise<void>((resolve, reject) => {
    const timer = setTimeout(() => {
      provider.off('synced', handler)
      reject(new Error(`Sync timed out after ${timeoutMs}ms`))
    }, timeoutMs)

    function handler() {
      clearTimeout(timer)
      resolve()
    }

    provider.on('synced', handler)
  })
}

/**
 * Wraps a promise with a timeout.
 */
export function withTimeout<T>(promise: Promise<T>, timeoutMs: number, message?: string): Promise<T> {
  return new Promise<T>((resolve, reject) => {
    const timer = setTimeout(
      () => reject(new Error(message ?? `Operation timed out after ${timeoutMs}ms`)),
      timeoutMs
    )
    promise.then(
      (val) => { clearTimeout(timer); resolve(val) },
      (err) => { clearTimeout(timer); reject(err) }
    )
  })
}
