//! Runtime handshake state shared by the I/O drivers.
//!
//! The type-state plumbing for the handshake lives in the two drivers —
//! [`SyncHandshake`](super::io_sync::SyncHandshake) (blocking
//! [`std::io`]) and [`AsyncHandshake`](super::io_async::AsyncHandshake)
//! (async I/O). Both thread the same runtime data, [`HandshakeInner`],
//! through their token chains; the per-token crypto operating on it is
//! shared via [`process`](super::process).
//!
//! This module holds only that runtime struct and its shared
//! constructor [`HandshakeInner::new`] — the protocol-name +
//! `SymmetricState::initialize` + `mix_hash(prologue)` initialisation
//! every driver (and the internal seal helpers) start from.

use super::Protocol;
use super::cipher::Cipher;
use super::hash::Hash;
use super::pattern::Pattern;
use super::symmetric_state::SymmetricState;
use super::well_formed::DerivedHasPsk;
use crate::curve::Curve;
use crate::provider::CryptoKeyProvider;

// ── Runtime state shared across the drivers ───────────────────

/// The runtime handshake data, threaded through every type state of the
/// sync/async drivers.
///
/// Separated from the type-state wrappers so that the shared per-token
/// crypto in [`process`](super::process) can operate on it without
/// fighting ownership.
pub(crate) struct HandshakeInner<Cu, Ci, H, CP>
where
    Cu: Curve,
    Ci: Cipher,
    H: Hash,
    CP: CryptoKeyProvider<Cu>,
{
    pub(crate) symmetric: SymmetricState<Ci, H>,
    /// Our ephemeral private key (generated by the `E` token).
    pub(crate) e: Option<CP::PrivateKey>,
    /// Our ephemeral public key (derived from `e` during the `E` token).
    pub(crate) e_pub: Option<Cu::PublicKey>,
    /// Our static private key (provided by the `S` token).
    pub(crate) s: Option<CP::PrivateKey>,
    /// Our static public key (derived from `s`).
    pub(crate) s_pub: Option<Cu::PublicKey>,
    /// Remote party's ephemeral public key (received via `E` token).
    pub(crate) re: Option<Cu::PublicKey>,
    /// Remote party's static public key.
    pub(crate) rs: Option<Cu::PublicKey>,
    /// Whether the pattern includes a PSK modifier (affects `E` token
    /// behaviour — it additionally calls `mix_key` on the ephemeral
    /// public key).
    pub(crate) has_psk: bool,
    /// The crypto provider (key generation, DH, signing).
    pub(crate) provider: CP,
}

impl<Cu, Ci, H, CP> HandshakeInner<Cu, Ci, H, CP>
where
    Cu: Curve,
    Ci: Cipher,
    H: Hash,
    CP: CryptoKeyProvider<Cu>,
{
    /// Build the runtime handshake state for protocol `Proto` and the given
    /// provider, mixing the prologue into the handshake hash.
    ///
    /// This is the single source of the protocol-name + `mix_hash`
    /// initialisation shared by every driver (`SyncHandshake`,
    /// `AsyncHandshake`, and the internal seal helpers). The protocol
    /// descriptor `Proto` supplies the pattern/curve/cipher/hash names.
    pub(crate) fn new<Proto>(provider: CP, prologue: &[u8]) -> Self
    where
        Proto: Protocol<Curve = Cu, Cipher = Ci, Hash = H>,
    {
        let protocol_name = format!(
            "Noise_{}_{}_{}_{}",
            <Proto::Pattern as Pattern>::NAME,
            <Cu as Curve>::NAME,
            <Ci as Cipher>::NAME,
            <H as Hash>::NAME,
        );
        let mut symmetric = SymmetricState::<Ci, H>::initialize(&protocol_name);

        // Noise spec §5.3: MixHash(prologue).
        symmetric.mix_hash(prologue);

        HandshakeInner {
            symmetric,
            e: None,
            e_pub: None,
            s: None,
            s_pub: None,
            re: None,
            rs: None,
            has_psk: <Proto::Pattern as DerivedHasPsk>::HAS_PSK,
            provider,
        }
    }
}
