//! Shared message dispatch — handle inbound text/binary frames once auth is complete.

use bft_json_crdt::json_crdt::SignedOp;

use crate::crdt_snapshot;
use crate::crdt_state;
use crate::crdt_wire;
use crate::slog;

use super::wire::SyncMessage;

mod snapshot;

#[cfg(test)]
mod tests;

/// Dispatch an incoming text frame from a peer.
///
/// First attempts to parse the frame as a snapshot protocol message; on
/// failure falls through to the legacy [`SyncMessage`] handler.
pub(super) fn handle_incoming_text(text: &str) {
    // First try to parse as a snapshot protocol message.
    if let Ok(snapshot_msg) = serde_json::from_str::<crdt_snapshot::SnapshotMessage>(text) {
        snapshot::handle_snapshot_message(snapshot_msg);
        return;
    }

    let msg: SyncMessage = match serde_json::from_str(text) {
        Ok(m) => m,
        Err(e) => {
            slog!("[crdt-sync] Bad text message from peer: {e}");
            return;
        }
    };

    match msg {
        SyncMessage::Bulk { ops } => {
            let mut applied = 0u64;
            for op_json in &ops {
                if let Ok(signed_op) = serde_json::from_str::<SignedOp>(op_json)
                    && crdt_state::apply_remote_op(signed_op)
                {
                    applied += 1;
                }
            }
            slog!(
                "[crdt-sync] Bulk sync: received {} ops, applied {applied}",
                ops.len()
            );
        }
        SyncMessage::Op { op } => {
            if let Ok(signed_op) = serde_json::from_str::<SignedOp>(&op) {
                crdt_state::apply_remote_op(signed_op);
            }
        }
        SyncMessage::Clock { .. } => {
            // Clock frames are handled during the initial negotiation phase.
            // If one arrives during the streaming loop it is a protocol error
            // on the peer's part — log and ignore.
            slog!("[crdt-sync] Ignoring unexpected clock frame during streaming phase");
        }
        SyncMessage::Ready => {
            // Ready frames are intercepted inline in the streaming loop before
            // this function is called.  If one reaches here it is a protocol
            // error — log and ignore.
            slog!("[crdt-sync] Ignoring unexpected ready frame in handle_incoming_text");
        }
    }
}

/// Process an incoming binary-frame op from a peer.
///
/// Binary frames carry a single `SignedOp` encoded via [`crdt_wire`].
pub(super) fn handle_incoming_binary(bytes: &[u8]) {
    match crdt_wire::decode(bytes) {
        Ok(signed_op) => {
            crdt_state::apply_remote_op(signed_op);
        }
        Err(e) => {
            slog!("[crdt-sync] Bad binary frame from peer: {e}");
        }
    }
}
