#ifndef WEBRTCPUSH_WEBRTC_PUSHER_H
#define WEBRTCPUSH_WEBRTC_PUSHER_H

// libdatachannel WebRTC 推流器 (匹配 https://jywy.yd-ss.com 协议, 设备=推流端)
//
// 实测网页协议方向 (对齐 signal.js / client.js):
//   - 拉流端(client.js)进入房间后主动发 offer (recvonly video+audio + "init" DataChannel)
//   - 推流端(signal.js, 即本设备)收到 offer -> setRemoteDescription ->
//     addTrack(H.264 sendonly) -> createAnswer -> 发回 answer
//   - ICE candidate 双向 trickle
//
// 因此本类的首选路径是 handle_offer() (应答模式);
// start() 保留为兜底: 拉流端一直不发 offer 时 (num>=2 持续 6s) 设备主动发 offer。
//
// 编解码协商 (H.264):
//   libdatachannel 生成 answer 时同 mid 有本地 track 就直接用本地 PT/fmtp,
//   不会自动匹配 offer 里的 PT —— 所以 handle_offer 会先解析对方 offer 的
//   H.264 rtpmap/fmtp, 用完全相同的 PT + fmtp 构造本地 track, 保证浏览器接受。

#include <cstdint>
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
#include <vector>

namespace webrtcpush {

struct PusherConfig {
    // ICE 服务器 (默认与 https://jywy.yd-ss.com signal.js 完全一致)
    std::vector<std::string> ice_servers = {
        "stun:stun.l.google.com:19302",
        "stun:8.129.3.163:18084",
        "stun:stun.cloudflare.com:3478",
        "turn:8.129.3.163:18084",
    };
    std::string turn_username   = "coturn";
    std::string turn_credential = "coturn";

    std::string stream_id   = "webrtcpush";
    std::string h264_profile = "baseline";    // 必须与 MPP 编码 profile 一致
    int         payload_type = 96;            // H.264 (兜底 offer 模式用)
    uint32_t    ssrc         = 0x12345678;
    int         video_clock  = 90000;          // H.264 RTP 时钟
    int         mtu          = 1200;
    int         fps          = 24;             // RTP 时间戳步进用

    // 动态码率范围
    int init_bitrate_kbps = 1500;
    int min_bitrate_kbps  = 400;
    int max_bitrate_kbps  = 3000;

    // DataChannel 拥塞监控阈值
    size_t congest_buffer_bytes  = 64 * 1024;   // 缓冲超过此值判定拥塞, 降码率
    size_t clear_buffer_bytes    = 4  * 1024;   // 缓冲低于此值判定畅通, 升码率
    int    bitrate_adjust_period_ms = 2000;    // 检查周期 (对齐网页 2s)
};

// 本地 SDP (answer 或兜底 offer) 生成 -> 交给 WsSignaling::send_description
using LocalDescriptionCallback = std::function<void(const std::string &sdp, bool is_offer)>;

// 本地 ICE candidate 收集到 (trickle) -> 通过 WsSignaling::send_candidate 发送
using LocalCandidateCallback = std::function<void(const std::string &candidate_json)>;

// 连接状态变化 (true=已连上, 此时应请求编码器出 IDR)
using ConnectedCallback = std::function<void(bool connected)>;

// 网络拥塞监控回调: 调用方据此调用 mpp_encoder_set_bitrate
using BitrateAdjustCallback = std::function<void(int new_bitrate_kbps)>;

class WebrtcPusher {
public:
    explicit WebrtcPusher(const PusherConfig &cfg);
    ~WebrtcPusher();

    void set_local_description_callback(LocalDescriptionCallback cb);
    void set_local_candidate_callback(LocalCandidateCallback cb);
    void set_connected_callback(ConnectedCallback cb);
    void set_bitrate_adjust_callback(BitrateAdjustCallback cb);

    // ===== 首选: 应答模式 (拉流端发来 offer) =====
    // 创建 PeerConnection -> setRemoteDescription(offer) ->
    // 按对方 offer 的 H264 PT/fmtp 加 track -> 生成的 answer 经
    // local_description_callback (is_offer=false) 送出
    bool handle_offer(const std::string &offer_sdp);

    // ===== 兜底: 主动 offer 模式 (拉流端迟迟不发 offer 时) =====
    bool start();

    // 兜底模式下设置远端 answer
    bool set_remote_answer(const std::string &answer_sdp);

    // 添加远端 ICE candidate (两种模式通用)
    bool add_remote_candidate(const std::string &candidate_json);

    // 会话状态
    bool is_connected() const;
    bool has_session() const;      // 已有 PeerConnection (协商中或已连接)
    bool session_pending() const;  // 兜底 offer 已发出, 等 answer

    // 拆掉当前会话 (对端离开 / 协商失败), 等待下一个 offer
    void reset();

    // 输入 H.264 NAL (Annex-B, 含 00 00 00 01 起始码, 可含多个 NALU)
    void feed_nalu(const uint8_t *data, size_t len, bool is_keyframe);

    void stop();

private:
    struct Impl;
    std::unique_ptr<Impl> impl_;
};

} // namespace webrtcpush

#endif // WEBRTCPUSH_WEBRTC_PUSHER_H
