// SPDX-License-Identifier: MPL-2.0
// Copyright (C) 2026 Petr Hodina <petr.hodina@protonmail.com>

//! Outer wire envelope: every request and reply on the SSC service starts
//! here and wraps a sensor-specific protobuf payload as opaque bytes.

use prost::Message;

/// 128-bit sensor handle. Protobuf has no 128-bit primitive, so the value
/// is split across two `fixed64` fields. Combine `high << 64 | low` to
/// recover the full UID.
#[derive(Clone, PartialEq, Eq, Message)]
pub struct Uid {
    #[prost(fixed64, required, tag = "1")]
    pub low: u64,
    #[prost(fixed64, required, tag = "2")]
    pub high: u64,
}

/// Wakeup configuration carried in every outgoing envelope. The daemon
/// uses these to decide whether messages on this client should keep the
/// AP from suspending.
#[derive(Clone, PartialEq, Message)]
pub struct ClientConfig {
    /// Which processor we're running on. 1 == APSS (apps processor).
    #[prost(int32, required, tag = "1")]
    pub processor: i32,
    /// 0 == wake AP from suspend, 1 == hold messages until AP wakes.
    #[prost(int32, required, tag = "2")]
    pub suspend_mode: i32,
}

/// Inner part of an [`Envelope`]: an opaque protobuf payload plus a
/// passive flag that controls whether the daemon activates the sensor.
#[derive(Clone, PartialEq, Message)]
pub struct EnvelopeBody {
    /// Reserved field — the daemon accepts but ignores it. Kept here so
    /// captured traffic round-trips bit-for-bit.
    #[prost(bytes = "vec", optional, tag = "1")]
    pub opaque: Option<Vec<u8>>,
    /// Sensor-specific request body, encoded as protobuf bytes.
    #[prost(bytes = "vec", optional, tag = "2")]
    pub payload: Option<Vec<u8>>,
    /// `true` requests data without activating the sensor (read-only piggy-
    /// back on whatever else is already streaming). Defaults to `false`.
    #[prost(bool, optional, tag = "3")]
    pub passive: Option<bool>,
}

/// Outgoing envelope sent inside a QMI control TLV.
#[derive(Clone, PartialEq, Message)]
pub struct Envelope {
    #[prost(message, required, tag = "1")]
    pub uid: Uid,
    /// Inner protobuf message ID — see `crate::suid::MSG_*`.
    #[prost(fixed32, required, tag = "2")]
    pub msg_id: u32,
    #[prost(message, required, tag = "3")]
    pub config: ClientConfig,
    #[prost(message, required, tag = "4")]
    pub body: EnvelopeBody,
}

/// One body within a [`Reply`]. `timestamp` is the DSP's QTimer ticks
/// (typically 19.2 MHz on modern Snapdragons).
#[derive(Clone, PartialEq, Message)]
pub struct ReplyBody {
    #[prost(fixed32, required, tag = "1")]
    pub msg_id: u32,
    #[prost(fixed64, required, tag = "2")]
    pub timestamp: u64,
    /// Sensor-specific response body, encoded as protobuf bytes.
    #[prost(bytes = "vec", required, tag = "3")]
    pub payload: Vec<u8>,
}

/// Incoming envelope. A single QMI indication can carry several
/// [`ReplyBody`] entries (e.g. config-ack + first measurement burst).
#[derive(Clone, PartialEq, Message)]
pub struct Reply {
    #[prost(message, required, tag = "1")]
    pub uid: Uid,
    #[prost(message, repeated, tag = "2")]
    pub bodies: Vec<ReplyBody>,
}
