//! # plato-ship-protocol
//!
//! Ship Interconnection Protocol — 6-layer trait definitions for the Plato network stack.
//!
//! Layers (bottom to top):
//! 1. [`HarborLayer`]  — direct addressing, peer discovery
//! 2. [`TidePoolLayer`] — async message routing, buffering
//! 3. [`CurrentLayer`]  — cross-runtime transport (git-based i2i)
//! 4. [`ChannelLayer`]  — simulation ↔ live channel bridging
//! 5. [`BeaconLayer`]   — event signaling, observation, trust score emission
//! 6. [`ReefLayer`]     — persistence, state handoff, belief serialization

// ─── Layer 1: Harbor ─────────────────────────────────────────────────────────

/// Direct addressing and peer discovery.
///
/// Implements `L1 Harbor → plato-address` (identity, exits, path resolution).
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::HarborLayer;
///
/// struct MockHarbor { peers: Vec<Vec<u8>> }
///
/// impl HarborLayer for MockHarbor {
///     fn resolve_peer(&self, address: &[u8]) -> Option<Vec<u8>> {
///         self.peers.iter().find(|p| p.as_slice() == address).cloned()
///     }
///     fn register_peer(&mut self, address: &[u8], _meta: &[u8]) -> bool {
///         self.peers.push(address.to_vec());
///         true
///     }
///     fn list_peers(&self) -> Vec<Vec<u8>> { self.peers.clone() }
/// }
///
/// let mut h = MockHarbor { peers: vec![] };
/// assert!(h.register_peer(b"ship-1", b"{}"));
/// assert_eq!(h.resolve_peer(b"ship-1"), Some(b"ship-1".to_vec()));
/// assert_eq!(h.list_peers().len(), 1);
/// ```
pub trait HarborLayer {
    /// Resolve a peer's routing descriptor by address. Returns `None` if unknown.
    fn resolve_peer(&self, address: &[u8]) -> Option<Vec<u8>>;

    /// Register a peer with associated metadata. Returns `true` on success.
    fn register_peer(&mut self, address: &[u8], meta: &[u8]) -> bool;

    /// List all currently known peer addresses.
    fn list_peers(&self) -> Vec<Vec<u8>>;
}

// ─── Layer 2: Tide Pool ───────────────────────────────────────────────────────

/// Async message routing and buffering.
///
/// Implements `L2 TidePool → plato-relay` (trust-weighted BFS routing, spore probes).
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::TidePoolLayer;
///
/// struct MockTidePool { buf: std::collections::VecDeque<Vec<u8>> }
///
/// impl TidePoolLayer for MockTidePool {
///     fn enqueue(&mut self, msg: &[u8]) -> bool {
///         self.buf.push_back(msg.to_vec());
///         true
///     }
///     fn dequeue(&mut self) -> Option<Vec<u8>> { self.buf.pop_front() }
///     fn buffer_len(&self) -> usize { self.buf.len() }
/// }
///
/// let mut tp = MockTidePool { buf: std::collections::VecDeque::new() };
/// assert!(tp.enqueue(b"hello"));
/// assert_eq!(tp.buffer_len(), 1);
/// assert_eq!(tp.dequeue(), Some(b"hello".to_vec()));
/// ```
pub trait TidePoolLayer {
    /// Enqueue a message for routing. Returns `true` if accepted into the buffer.
    fn enqueue(&mut self, msg: &[u8]) -> bool;

    /// Dequeue the next routed message. Returns `None` if the buffer is empty.
    fn dequeue(&mut self) -> Option<Vec<u8>>;

    /// Number of messages currently buffered.
    fn buffer_len(&self) -> usize;
}

// ─── Layer 3: Current ────────────────────────────────────────────────────────

/// Cross-runtime transport (git-based i2i).
///
/// Implements `L3 Current → plato-bridge / plato-hooks` (git-based inter-instance transport).
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::CurrentLayer;
///
/// struct MockCurrent;
///
/// impl CurrentLayer for MockCurrent {
///     fn export(&self, msg: &[u8]) -> Vec<u8> {
///         let mut out = b"git:".to_vec();
///         out.extend_from_slice(msg);
///         out
///     }
///     fn import(&self, data: &[u8]) -> Option<Vec<u8>> {
///         data.strip_prefix(b"git:").map(|b| b.to_vec())
///     }
///     fn transport_id(&self) -> String { "git-i2i-mock".to_string() }
/// }
///
/// let c = MockCurrent;
/// let exported = c.export(b"payload");
/// assert_eq!(c.import(&exported), Some(b"payload".to_vec()));
/// ```
pub trait CurrentLayer {
    /// Serialize and frame a message for cross-runtime export.
    fn export(&self, msg: &[u8]) -> Vec<u8>;

    /// Deserialize and unframe an incoming cross-runtime message.
    /// Returns `None` if the frame is malformed.
    fn import(&self, data: &[u8]) -> Option<Vec<u8>>;

    /// A stable identifier for this transport implementation.
    fn transport_id(&self) -> String;
}

// ─── Layer 4: Channel ────────────────────────────────────────────────────────

/// Simulation ↔ live channel bridging.
///
/// Implements `L4 Channel → plato-sim-bridge`.
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::ChannelLayer;
///
/// struct MockChannel { live: bool }
///
/// impl ChannelLayer for MockChannel {
///     fn bridge_send(&mut self, _channel: u8, _msg: &[u8]) -> bool { self.live }
///     fn bridge_recv(&mut self, _channel: u8) -> Option<Vec<u8>> {
///         if self.live { Some(b"ack".to_vec()) } else { None }
///     }
///     fn is_live(&self) -> bool { self.live }
/// }
///
/// let mut ch = MockChannel { live: true };
/// assert!(ch.is_live());
/// assert!(ch.bridge_send(0, b"ping"));
/// assert_eq!(ch.bridge_recv(0), Some(b"ack".to_vec()));
/// ```
pub trait ChannelLayer {
    /// Send a message on the given channel id. Returns `true` if delivered.
    fn bridge_send(&mut self, channel: u8, msg: &[u8]) -> bool;

    /// Receive a message from the given channel. Returns `None` if nothing waiting.
    fn bridge_recv(&mut self, channel: u8) -> Option<Vec<u8>>;

    /// Whether this channel is operating in live (vs. simulation) mode.
    fn is_live(&self) -> bool;
}

// ─── Layer 5: Beacon ─────────────────────────────────────────────────────────

/// Event signaling, observation, and trust score emission.
///
/// Implements `L5 Beacon → cuda-trust` (trust score events, observation).
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::BeaconLayer;
///
/// struct MockBeacon { score: f32, last: Option<Vec<u8>> }
///
/// impl BeaconLayer for MockBeacon {
///     fn emit_event(&mut self, event: &[u8]) -> bool {
///         self.last = Some(event.to_vec());
///         true
///     }
///     fn observe(&self) -> Option<Vec<u8>> { self.last.clone() }
///     fn trust_score(&self) -> f32 { self.score }
/// }
///
/// let mut b = MockBeacon { score: 0.9, last: None };
/// assert!(b.emit_event(b"connected"));
/// assert_eq!(b.observe(), Some(b"connected".to_vec()));
/// assert!((b.trust_score() - 0.9).abs() < f32::EPSILON);
/// ```
pub trait BeaconLayer {
    /// Emit a protocol event. Returns `true` if observers were notified.
    fn emit_event(&mut self, event: &[u8]) -> bool;

    /// Observe the most recent event. Returns `None` if no events have been emitted.
    fn observe(&self) -> Option<Vec<u8>>;

    /// Current trust score for this node, in `[0.0, 1.0]`.
    fn trust_score(&self) -> f32;
}

// ─── Layer 6: Reef ───────────────────────────────────────────────────────────

/// Persistence, state handoff, and belief serialization.
///
/// Implements `L6 Reef → plato-afterlife` (ghost tile persistence, state handoff).
///
/// # Examples
///
/// ```rust
/// use plato_ship_protocol::ReefLayer;
///
/// struct MockReef { store: std::collections::HashMap<Vec<u8>, Vec<u8>> }
///
/// impl ReefLayer for MockReef {
///     fn persist(&mut self, key: &[u8], state: &[u8]) -> bool {
///         self.store.insert(key.to_vec(), state.to_vec());
///         true
///     }
///     fn restore(&self, key: &[u8]) -> Option<Vec<u8>> {
///         self.store.get(key).cloned()
///     }
///     fn handoff(&mut self, _state: &[u8]) -> bool { true }
/// }
///
/// let mut r = MockReef { store: std::collections::HashMap::new() };
/// assert!(r.persist(b"ghost-1", b"belief-state"));
/// assert_eq!(r.restore(b"ghost-1"), Some(b"belief-state".to_vec()));
/// ```
pub trait ReefLayer {
    /// Persist state under the given key. Returns `true` on success.
    fn persist(&mut self, key: &[u8], state: &[u8]) -> bool;

    /// Restore state by key. Returns `None` if not found.
    fn restore(&self, key: &[u8]) -> Option<Vec<u8>>;

    /// Hand off serialized state to the next runtime instance.
    /// Returns `true` if the handoff was accepted.
    fn handoff(&mut self, state: &[u8]) -> bool;
}

// ─── ShipStack ───────────────────────────────────────────────────────────────

/// A composed stack of all 6 Ship Interconnection Protocol layers.
///
/// `send` routes a message through layers 1 → 6 (bottom-up).
/// `receive` routes incoming data through layers 6 → 1 (top-down).
pub struct ShipStack {
    pub harbor: Box<dyn HarborLayer>,
    pub tide_pool: Box<dyn TidePoolLayer>,
    pub current: Box<dyn CurrentLayer>,
    pub channel: Box<dyn ChannelLayer>,
    pub beacon: Box<dyn BeaconLayer>,
    pub reef: Box<dyn ReefLayer>,
}

impl ShipStack {
    /// Route a message outbound through all 6 layers (L1 → L6).
    ///
    /// Each layer may transform the payload; the final bytes are returned.
    pub fn send(&mut self, msg: &[u8]) -> Vec<u8> {
        // L1 Harbor: register the message origin
        self.harbor.register_peer(msg, b"outbound");
        // L2 TidePool: buffer for routing
        self.tide_pool.enqueue(msg);
        let buffered = self.tide_pool.dequeue().unwrap_or_else(|| msg.to_vec());
        // L3 Current: frame for cross-runtime transport
        let framed = self.current.export(&buffered);
        // L4 Channel: bridge to live channel 0
        self.channel.bridge_send(0, &framed);
        // L5 Beacon: emit send event
        self.beacon.emit_event(b"send");
        // L6 Reef: persist outbound state
        self.reef.persist(b"last-send", &framed);
        framed
    }

    /// Route incoming data inbound through all 6 layers (L6 → L1).
    ///
    /// Each layer may transform the payload; the final bytes are returned.
    pub fn receive(&mut self, data: &[u8]) -> Vec<u8> {
        // L6 Reef: restore / record inbound
        self.reef.persist(b"last-recv", data);
        // L5 Beacon: emit receive event
        self.beacon.emit_event(b"recv");
        // L4 Channel: receive from live channel 0
        let from_channel = self.channel.bridge_recv(0).unwrap_or_else(|| data.to_vec());
        // L3 Current: unframe cross-runtime payload
        let unframed = self.current.import(&from_channel).unwrap_or_else(|| from_channel.clone());
        // L2 TidePool: buffer then drain
        self.tide_pool.enqueue(&unframed);
        let routed = self.tide_pool.dequeue().unwrap_or_else(|| unframed.clone());
        // L1 Harbor: register inbound peer
        self.harbor.register_peer(&routed, b"inbound");
        routed
    }
}

// ─── Tests ───────────────────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::{HashMap, VecDeque};

    // ── Mock implementations ──────────────────────────────────────────────────

    struct MockHarbor {
        peers: Vec<Vec<u8>>,
    }
    impl HarborLayer for MockHarbor {
        fn resolve_peer(&self, address: &[u8]) -> Option<Vec<u8>> {
            self.peers.iter().find(|p| p.as_slice() == address).cloned()
        }
        fn register_peer(&mut self, address: &[u8], _meta: &[u8]) -> bool {
            self.peers.push(address.to_vec());
            true
        }
        fn list_peers(&self) -> Vec<Vec<u8>> {
            self.peers.clone()
        }
    }

    struct MockTidePool {
        buf: VecDeque<Vec<u8>>,
    }
    impl TidePoolLayer for MockTidePool {
        fn enqueue(&mut self, msg: &[u8]) -> bool {
            self.buf.push_back(msg.to_vec());
            true
        }
        fn dequeue(&mut self) -> Option<Vec<u8>> {
            self.buf.pop_front()
        }
        fn buffer_len(&self) -> usize {
            self.buf.len()
        }
    }

    struct MockCurrent;
    impl CurrentLayer for MockCurrent {
        fn export(&self, msg: &[u8]) -> Vec<u8> {
            let mut out = b"git:".to_vec();
            out.extend_from_slice(msg);
            out
        }
        fn import(&self, data: &[u8]) -> Option<Vec<u8>> {
            data.strip_prefix(b"git:").map(|b| b.to_vec())
        }
        fn transport_id(&self) -> String {
            "git-i2i-mock".to_string()
        }
    }

    struct MockChannel {
        live: bool,
        inbox: Option<Vec<u8>>,
    }
    impl ChannelLayer for MockChannel {
        fn bridge_send(&mut self, _channel: u8, msg: &[u8]) -> bool {
            self.inbox = Some(msg.to_vec());
            true
        }
        fn bridge_recv(&mut self, _channel: u8) -> Option<Vec<u8>> {
            self.inbox.take()
        }
        fn is_live(&self) -> bool {
            self.live
        }
    }

    struct MockBeacon {
        score: f32,
        last: Option<Vec<u8>>,
    }
    impl BeaconLayer for MockBeacon {
        fn emit_event(&mut self, event: &[u8]) -> bool {
            self.last = Some(event.to_vec());
            true
        }
        fn observe(&self) -> Option<Vec<u8>> {
            self.last.clone()
        }
        fn trust_score(&self) -> f32 {
            self.score
        }
    }

    struct MockReef {
        store: HashMap<Vec<u8>, Vec<u8>>,
    }
    impl ReefLayer for MockReef {
        fn persist(&mut self, key: &[u8], state: &[u8]) -> bool {
            self.store.insert(key.to_vec(), state.to_vec());
            true
        }
        fn restore(&self, key: &[u8]) -> Option<Vec<u8>> {
            self.store.get(key).cloned()
        }
        fn handoff(&mut self, _state: &[u8]) -> bool {
            true
        }
    }

    fn make_stack() -> ShipStack {
        ShipStack {
            harbor: Box::new(MockHarbor { peers: vec![] }),
            tide_pool: Box::new(MockTidePool { buf: VecDeque::new() }),
            current: Box::new(MockCurrent),
            channel: Box::new(MockChannel { live: true, inbox: None }),
            beacon: Box::new(MockBeacon { score: 1.0, last: None }),
            reef: Box::new(MockReef { store: HashMap::new() }),
        }
    }

    // ── Integration tests ─────────────────────────────────────────────────────

    #[test]
    fn test_ship_stack_construction() {
        let stack = make_stack();
        assert!(stack.channel.is_live());
        assert_eq!(stack.current.transport_id(), "git-i2i-mock");
        assert_eq!(stack.beacon.trust_score(), 1.0);
    }

    #[test]
    fn test_message_roundtrip() {
        let mut stack = make_stack();
        let original = b"hello plato";

        // send frames the message through all layers
        let sent = stack.send(original);
        assert_eq!(sent, b"git:hello plato");

        // receive unframes back to original
        // MockChannel.bridge_recv will return the framed bytes placed by send's bridge_send
        // But send already called bridge_send and bridge_recv is None after that.
        // So we simulate a fresh inbound by injecting the framed bytes directly.
        let received = stack.receive(&sent);
        assert_eq!(received, original.as_ref());
    }
}
