//! Internal transport types used by [`super::cluster::SimulatedCluster`].

use crate::db::TidalDb;
use crate::replication::WalSegmentId;
use crate::replication::shard::{RegionId, ShardId};
use crate::replication::transport::{Transport, TransportError, WalSegmentPayload};

// ── Internal: receive-only transport ─────────────────────────────────────

/// Minimal transport implementation used by follower receivers.
///
/// Owns a crossbeam `Receiver` for incoming WAL segments. The `send_segment`
/// side is a no-op — all shipping is managed by the cluster struct.
pub(super) struct ReceiveOnlyTransport {
    pub(super) local_shard: ShardId,
    pub(super) rx: crossbeam::channel::Receiver<WalSegmentPayload>,
}

impl Transport for ReceiveOnlyTransport {
    fn send_segment(&self, _: ShardId, _: WalSegmentPayload) -> Result<(), TransportError> {
        Ok(())
    }

    fn recv_segment(&self) -> Option<WalSegmentPayload> {
        self.rx.recv().ok()
    }

    fn local_shard(&self) -> ShardId {
        self.local_shard
    }
}

// ── Internal: batch log entry ─────────────────────────────────────────────

pub(super) struct BatchEntry {
    /// Which leader shard produced this batch.
    pub(super) source_shard: ShardId,
    /// 1-indexed sequence number scoped to `source_shard`.
    pub(super) seqno: u64,
    /// Encoded WAL batch bytes (from [`crate::wal::format::batch::encode_batch`]).
    pub(super) bytes: Vec<u8>,
}

// ── Re-delivery helper ────────────────────────────────────────────────────

/// Re-deliver all batch-log entries not yet applied to `db`, sending through `tx`.
///
/// Called by `SimulatedCluster::heal_region` for immediate recovery after a
/// partition is healed, and by `await_convergence` during the polling loop.
pub(super) fn redeliver_missed(
    tx: &crossbeam::channel::Sender<WalSegmentPayload>,
    db: &TidalDb,
    log: &[BatchEntry],
) {
    for entry in log {
        let applied = db
            .replication_state()
            .applied_seqno(entry.source_shard)
            .unwrap_or(0);
        if entry.seqno > applied {
            let payload = WalSegmentPayload {
                id: WalSegmentId::new(RegionId::SINGLE, entry.source_shard, entry.seqno),
                bytes: entry.bytes.clone(),
                event_count: 1,
            };
            let _ = tx.try_send(payload);
        }
    }
}
