/**
 * BluetoothBump —— 纯蓝牙"碰一碰"模块
 *
 * 设计目标：
 *   - 只负责蓝牙：隐私授权 / 打开适配器 / 广播自己 / 扫描他人 / RSSI 判定 / 去重 / 优雅停止
 *   - 不感知业务：碰到对方后通过 onBump 回调把 (peerDeviceId, rssi) 抛出去
 *   - 跨平台兼容：iOS 必须分别初始化 central / peripheral；Android 一次 openBluetoothAdapter 即可
 *   - 可测试：把 wx 调用抽成 WxBluetoothAdapter，主类通过依赖注入，单测可注入 mock
 *
 * 使用方式：
 *   const bt = new BluetoothBump({ onBump: (peerId, rssi) => { ... } });
 *   bt.start().then(() => { ... });
 *   bt.stop();
 *
 * ⚠️ start() 必须在【用户点击事件回调】中调用，否则 iOS 报：
 *    "openBluetoothAdapter:fail click action before resolve is needed"
 */
import { type WxBluetoothAdapter } from './wx-adapter';
import type { BluetoothBumpOptions } from './types';
/** 主类的额外依赖（用于测试时注入假时钟、假 timer、假 adapter） */
export interface BluetoothBumpDeps {
    adapter?: WxBluetoothAdapter;
    now?: () => number;
    setTimeoutFn?: (fn: () => void, ms: number) => any;
    clearTimeoutFn?: (handle: any) => void;
    setIntervalFn?: (fn: () => void, ms: number) => any;
    clearIntervalFn?: (handle: any) => void;
}
export declare class BluetoothBump {
    /** 我方临时 ID（每次启动随机生成，写到广播特征值里） */
    myTempId: string;
    /** 当前运行平台 */
    platform: string;
    /** 是否跳过广播（peripheral 初始化失败时降级为只扫描） */
    skipAdvertising: boolean;
    /** 是否已经成功触发过碰一碰 */
    hasBumped: boolean;
    private readonly serviceUuid;
    private readonly characteristicUuid;
    private readonly rssiThreshold;
    private readonly cooldownMs;
    private readonly lingerBeforeStopMs;
    private readonly pollIntervalMs;
    private readonly privacyContent;
    /** 匹配模式：simple（单向发现即触发）/ mutual（双向互认） */
    private readonly mode;
    private readonly peerTtlMs;
    private readonly advertiseUpdateThrottleMs;
    private readonly onBump?;
    private readonly onError?;
    private readonly onLog?;
    private readonly onDeviceFoundCallback?;
    private readonly adapter;
    private readonly now;
    private readonly setTimeoutFn;
    private readonly clearTimeoutFn;
    private readonly setIntervalFn;
    private readonly clearIntervalFn;
    private peripheralServer;
    private isDiscovering;
    private bumpedMap;
    private gracefulStopTimer;
    private pollTimer;
    /** mutual 模式：候选 peer 池，key = peerTempId */
    private seenPeers;
    /** mutual 模式：当前广播中"点名"的 peerId（为空表示还没看到任何人） */
    private currentAdvertisedPeer;
    /** mutual 模式：上次更新广播的时间戳（用于节流） */
    private lastAdvertiseUpdateAt;
    /** mutual 模式：updateAdvertisedValue 连续失败后降级为 simple（仅当前会话内） */
    private advertiseUpdateBroken;
    private deviceFoundCb;
    private adapterStateChangeCb;
    constructor(opts?: BluetoothBumpOptions, deps?: BluetoothBumpDeps);
    /** 启动碰一碰（必须在用户点击事件回调中调用） */
    start(): Promise<void>;
    /** 停止：解绑所有监听 + 停止扫描 + 停止广播 + 关闭适配器 */
    stop(): void;
    /** 启动失败的统一处理（业务方可通过 onError 拿到原始错误） */
    private handleStartError;
    /** 监听蓝牙适配器状态变化：用户打开蓝牙后自动重试 */
    private watchAdapterStateForRetry;
    /** 监听设备发现 + 启动 iOS 兜底轮询 */
    private bindDeviceFound;
    /** 调试用：定期 getBluetoothDevices，避免 iOS 上 allowDuplicatesKey 不上报重复的问题 */
    private startPolling;
    /** 处理扫到的单个设备 */
    private handleDevice;
    /**
     * mutual 模式（v2，方案2 实现）：协议双向 simple
     *
     * 设计取舍：
     *   v1 mutual 用"动态更新广播 payload 的 seenPeerId"做双向互认，但 iOS 上
     *   wx 的 updateBLEAdvertising → stop+addService+start 链路在真机上极不可靠：
     *     - deviceName 不会真正刷新（CoreBluetooth 缓存）
     *     - addService 重复注册会失败、走兜底分支后广播就停了
     *     - 高频 update 还会让 iOS 端事件循环卡死
     *   导致弱信号端永远收不到"被点名"广播 → 不弹窗。
     *
     * v2 直接退一步：
     *   - 不再动态更新广播 payload；广播一次启动后保持初始 payload 不变
     *   - 触发条件：扫到的对端必须能解析出 BUMP_ 协议 payload（协议匹配） + 本机 RSSI ≥ 阈值
     *   - "双向"靠两端都跑这套规则、各自独立达阈值时触发；阈值收紧（≈10cm）就足够防误触
     *   - iOS↔Android RSSI 不对称的代价：可能两端弹窗时差最大到秒级（取决于谁先稳定过阈值）
     *     但相比 v1 的"一端永远不弹"，这是更可接受的退化
     */
    private handleDeviceMutual;
    /** mutual 模式：更新自己广播里的 seenPeerId（带节流 + 失败降级） */
    private updateAdvertisedPeer;
    /** 触发碰一碰成功：通知业务方 + 优雅停止（保持广播一段时间） */
    private triggerBump;
    /** 仅停止扫描（保留广播） */
    private stopDiscoveryOnly;
    private log;
}
