//! The link state machine (`ARCHITECTURE.md` §3.7).
//!
//! Links are the protocol's encrypted bidirectional channels, established with a
//! three-packet handshake (LinkRequest → LRRTT → LRPROOF). After the handshake
//! both sides hold a shared [`Token`] key; forward secrecy comes from the
//! ephemerality of the handshake keys, refreshed over time by ratchets (§3.9).

use std::time::{Duration, Instant};

use plexus_core::{AddressHash, ContextByte};
use plexus_crypto::Token;

/// Link lifecycle state.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkState {
    /// Request sent, awaiting LRRTT.
    Pending,
    /// LRRTT received, awaiting LRPROOF.
    Handshaking,
    /// Established and carrying traffic.
    Active,
    /// No traffic within `KEEPALIVE * STALE_FACTOR`.
    Stale,
    /// Torn down.
    Closed,
}

/// Whether we initiated the link or responded to it.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkRole {
    /// We sent the LinkRequest.
    Initiator,
    /// We responded to a LinkRequest.
    Responder,
}

/// An encrypted bidirectional channel (§3.7).
pub struct Link {
    /// Truncated SHA-256 of the public link material.
    pub id: AddressHash,
    state: LinkState,
    role: LinkRole,
    token: Option<Token>,
    rtt: Option<Duration>,
    established_at: Option<Instant>,
    last_inbound: Instant,
    last_outbound: Instant,
    keepalive_interval: Duration,
    teardown_at: Option<Instant>,
}

/// Why a link closed.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkCloseReason {
    /// Timed out.
    Timeout,
    /// The initiator closed it.
    InitiatorClosed,
    /// The destination closed it.
    DestinationClosed,
    /// A local error forced closure.
    LocalError,
}

/// Link-level events surfaced to the host.
#[derive(Debug)]
pub enum LinkEvent {
    /// The link is established.
    Established {
        /// Link id.
        id: AddressHash,
        /// Measured round-trip time.
        rtt: Duration,
    },
    /// Decrypted data arrived on the link.
    DataReceived {
        /// Link id.
        id: AddressHash,
        /// Decrypted payload.
        plaintext: Vec<u8>,
        /// Packet context.
        context: ContextByte,
    },
    /// The link closed.
    Closed {
        /// Link id.
        id: AddressHash,
        /// Why it closed.
        reason: LinkCloseReason,
    },
}

/// Table of active links, keyed by link id.
#[derive(Default)]
pub struct LinkTable {}
