//! Hole Punch Packet Processor for Citadel Protocol
//!
//! This module implements NAT traversal functionality through hole punching in the
//! Citadel Protocol network. It enables direct peer-to-peer connections between nodes
//! behind NATs by coordinating connection establishment.
//!
//! # Features
//!
//! - NAT traversal packet processing
//! - Secure packet validation
//! - Peer connection coordination
//! - Connection pipe management
//! - Proxy support
//!
//! # Important Notes
//!
//! - Requires valid peer CID
//! - All packets must be authenticated
//! - Manages hole puncher pipes
//! - Supports proxied connections
//! - Forwards validated packets
//!
//! # Related Components
//!
//! - `StateContainer`: Manages hole punch state
//! - `HolePuncherPipe`: Handles connection establishment
//! - `StackedRatchet`: Provides packet security
//! - `ProxyManager`: Handles proxied connections

use super::includes::*;
use crate::error::NetworkError;
use crate::proto::misc::platform_ops::PlatformOps;
use crate::proto::packet_processor::primary_group_packet::{
    get_orientation_safe_ratchet, get_resp_target_cid_from_header,
};
use citadel_crypt::ratchets::Ratchet;

/// This will handle an inbound group packet
#[cfg_attr(feature = "localhost-testing", tracing::instrument(
    level = "trace",
    target = "citadel",
    skip_all,
    ret,
    err,
    fields(is_server = session.is_server, src = packet.parse().unwrap().0.session_cid.get(), target = packet.parse().unwrap().0.target_cid.get()
    )
))]
pub fn process_hole_punch<R: Ratchet, T: PlatformOps>(
    session: &CitadelSession<R, T>,
    packet: HdpPacket,
    hr_version: u32,
    proxy_cid_info: Option<(u64, u64)>,
) -> Result<PrimaryProcessorResult, NetworkError> {
    let (header, payload, _, _) = packet.decompose();
    let mut state_container = inner_mut_state!(session.state_container);
    let hr = return_if_none!(
        get_orientation_safe_ratchet(hr_version, &state_container, proxy_cid_info),
        "Unable to get proper HR"
    );
    let header = header.as_ref();
    let (header, payload) = return_if_none!(
        super::super::validation::aead::validate_custom(&hr, &header, payload),
        "Unable to validate packet"
    );
    log::trace!(target: "citadel", "Success validating hole-punch packet");
    let peer_cid = get_resp_target_cid_from_header(&header);
    match state_container.hole_puncher_pipes.get(&peer_cid) {
        Some(pipe) => {
            return_if_none!(
                pipe.send(payload.freeze()).ok(),
                "Unable to forward hole-punch packet through pipe"
            );
            log::trace!(target: "citadel", "Success forwarding hole-punch packet to hole-puncher");
        }
        None => {
            log::trace!(target: "citadel", "Enqueuing early hole-punch packet for peer {peer_cid} (pipe not yet registered)");
            state_container
                .pending_hole_punch_packets
                .entry(peer_cid)
                .or_default()
                .push(payload.freeze());
        }
    }

    Ok(PrimaryProcessorResult::Void)
}
