/*!
# Peer Cryptography Module

This module implements the cryptographic key exchange and NAT traversal functionality for peer-to-peer connections in the Citadel Protocol.

## Features
- **Key Exchange Protocol**: Implements a multi-stage key exchange process
- **NAT Traversal Support**: Provides NAT type detection and compatibility checking
- **TLS Integration**: Supports TLS domain configuration for secure connections
- **Security Settings**: Configurable security levels and UDP modes
- **STUN/TURN Support**: Automatic TURN server fallback for incompatible NATs

## Core Components
- `KeyExchangeProcess`: Manages the stages of peer key exchange
- `PeerNatInfo`: Handles NAT-related information and compatibility
- `TlsDomain`: Configures TLS settings for secure connections

## Important Notes
1. Key exchange follows a three-stage protocol for security
2. NAT compatibility is checked before direct connections
3. TURN servers are used as fallback for incompatible NATs
4. TLS domains ensure secure communication channels

## Related Components
- `p2p_conn_handler`: Manages peer connections
- `hole_punch_compat_sink_stream`: Handles hole punching
- `session`: Manages connection sessions
- `state_container`: Tracks connection state

*/

use crate::proto::node::TlsDomain;
use crate::proto::remote::Ticket;
use citadel_types::proto::SessionSecuritySettings;
use citadel_types::proto::UdpMode;
use citadel_wire::nat_identification::NatType;
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;

/// Serializable ICE candidate for WebRTC signaling exchange.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct IceCandidateData {
    pub candidate: String,
    pub sdp_mid: Option<String>,
    pub sdp_mline_index: Option<u16>,
}

/// WebRTC signaling payload relayed between peers through the server.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum WebRtcSignalingPayload {
    Offer {
        sdp: String,
        ice_candidates: Vec<IceCandidateData>,
    },
    Answer {
        sdp: String,
        ice_candidates: Vec<IceCandidateData>,
    },
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum KeyExchangeProcess {
    // alice sends public key + p2p_connection_id (generated by initiator)
    Stage0(Vec<u8>, SessionSecuritySettings, UdpMode, Ticket),
    // Bob sends ciphertext, addr, file transfer compatibility + echoed p2p_connection_id
    Stage1(Vec<u8>, Option<PeerNatInfo>, bool, Ticket),
    // Alice sends a sync time over. Server takes care of external addr. Includes file transfer compat
    Stage2(i64, Option<PeerNatInfo>, bool),
    // The hole-punch failed
    HolePunchFailed,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PeerNatInfo {
    // This is the location of the listener for the other peer as obtained by the central server
    pub peer_remote_addr_visible_from_server: SocketAddr,
    pub peer_nat: NatType,
    pub tls_domain: TlsDomain,
}

impl PeerNatInfo {
    pub fn generate_proper_listener_connect_addr(
        &self,
        local_nat_type: &NatType,
    ) -> (bool, SocketAddr) {
        //let predicted_addr = self.peer_nat.predict_external_addr_from_local_bind_port(self.peer_unnated_listener_port).map(|r| SocketAddr::new(self.peer_remote_ip, r.port())).unwrap_or_else(|| SocketAddr::new(self.peer_remote_ip, self.peer_unnated_listener_port));
        let predicted_addr = self.peer_remote_addr_visible_from_server;
        // TODO: This assumes same IP, Port as visible from server. For EDM's w/delta,
        // we need to *ensure* the dualstack udp hole puncher can already handle deltas
        // properly
        let needs_turn = !self.peer_nat.stun_compatible(local_nat_type);
        (needs_turn, predicted_addr)
    }
}
