//! Network layer for blvm-node
//!
//! This module provides P2P networking, peer management, and Bitcoin protocol
//! message handling for communication with other Bitcoin nodes.

pub mod address_db;
pub mod ban_list_merging;
pub mod ban_list_signing;
pub mod bandwidth_protection;
pub mod chain_access;
pub mod connection_manager;
pub mod dns_seeds;
pub mod dos_protection;
pub mod erlay;
pub mod ibd_protection;
pub mod inventory;
pub mod lan_discovery;
pub mod lan_security;
pub mod message_bridge;
pub mod module_registry_extensions;
pub mod network_manager;
pub mod peer;
pub mod peer_manager;
pub mod peer_scoring;
pub mod protocol;
pub mod protocol_adapter;
pub mod protocol_extensions;
pub mod relay;
pub mod replay_protection;
pub mod tcp_transport;
pub mod transport;

#[cfg(feature = "quinn")]
pub mod quinn_transport;

#[cfg(feature = "iroh")]
pub mod iroh_transport;

#[cfg(feature = "utxo-commitments")]
pub mod utxo_commitments_client;

// Compact Block Relay (BIP152)
pub mod compact_blocks;

// Block Filter Service (BIP157/158)
mod background_tasks;
pub mod bip157_handler;
mod block_announced_sync;
pub mod filter_service;
mod getdata_serve;
mod handlers;
mod network_message_dispatch;
mod peer_connections;
mod startup;
mod wire_dispatch;
// Payment Protocol (BIP70) - P2P handlers
pub mod bip70_handler;

// Privacy and Performance Enhancements
#[cfg(feature = "dandelion")]
pub mod dandelion; // Dandelion++ privacy-preserving transaction relay
pub mod package_relay; // BIP 331 Package Relay
pub mod package_relay_handler; // BIP 331 handlers
// Stratum V2: P2P TLV demux → `StratumV2MessageReceived`; dedicated miner TCP is owned by
// `blvm-stratum-v2`. `NodeAPI::send_peer_transport_payload` sends opaque bytes on P2P.
pub mod txhash; // Non-consensus hashing helpers for relay

use std::net::SocketAddr;
use tokio::sync::mpsc;

pub use connection_manager::{ConnectionManager, NetworkIO};
pub use network_manager::NetworkManager;
pub use peer_manager::{PeerByteRateLimiter, PeerManager, PeerRateLimiter};
pub use transport::{TransportAddr, TransportPreference};

/// Network message types (central enum for network layer)
#[derive(Debug, Clone)]
pub enum NetworkMessage {
    PeerConnected(TransportAddr),
    PeerDisconnected(TransportAddr),
    BlockReceived(Vec<u8>),
    TransactionReceived(Vec<u8>),
    InventoryReceived(Vec<u8>, SocketAddr),
    #[cfg(feature = "utxo-commitments")]
    UTXOSetReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    #[cfg(feature = "utxo-commitments")]
    FilteredBlockReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    #[cfg(feature = "utxo-commitments")]
    GetUTXOSetReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    #[cfg(feature = "utxo-commitments")]
    GetFilteredBlockReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    #[cfg(feature = "stratum-v2")]
    StratumV2MessageReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // Raw message received from peer (needs processing)
    RawMessageReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // Headers response (for IBD)
    HeadersReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // BIP157 Block Filter messages
    GetCfiltersReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    GetCfheadersReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    GetCfcheckptReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // BIP331 Package Relay messages
    PkgTxnReceived(Vec<u8>, SocketAddr),     // (data, peer_addr)
    SendPkgTxnReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // Module Registry messages
    GetModuleReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    ModuleReceived(Vec<u8>, SocketAddr),    // (data, peer_addr)
    GetModuleByHashReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    ModuleByHashReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    GetModuleListReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    ModuleListReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // BIP70 Payment Protocol messages
    GetPaymentRequestReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    PaymentRequestReceived(Vec<u8>, SocketAddr),    // (data, peer_addr)
    PaymentReceived(Vec<u8>, SocketAddr),           // (data, peer_addr)
    PaymentACKReceived(Vec<u8>, SocketAddr),        // (data, peer_addr)
    // CTV Payment Proof messages
    #[cfg(feature = "ctv")]
    PaymentProofReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    /// Outbound payment proof queued by PaymentStateMachine for NetworkManager delivery.
    #[cfg(feature = "ctv")]
    SendPaymentProof(Vec<u8>, SocketAddr), // (wire payload, peer_addr)
    SettlementNotificationReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
    // Mesh networking packets
    MeshPacketReceived(Vec<u8>, SocketAddr), // (data, peer_addr)
}

#[cfg(test)]
mod tests {
    mod bandwidth_protection_tests;
    mod concurrency_stress_tests;
    use super::*;

    #[tokio::test]
    async fn test_peer_manager_creation() {
        let _addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = PeerManager::new(10);
        assert_eq!(manager.peer_count(), 0);
        assert!(manager.can_accept_peer());
    }

    #[tokio::test]
    async fn test_peer_manager_add_peer() {
        let manager = PeerManager::new(2);
        let _addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        // Create a mock peer without requiring network connection
        let (_tx, _rx): (mpsc::UnboundedSender<NetworkMessage>, _) = mpsc::unbounded_channel();

        // Skip this test since we can't easily create a mock TcpStream
        // In a real implementation, we'd use dependency injection
        // For now, just test the manager logic without the peer
        assert_eq!(manager.peer_count(), 0);
        assert!(manager.can_accept_peer());
    }

    #[tokio::test]
    async fn test_peer_manager_max_peers() {
        let manager = PeerManager::new(1);
        let _addr1: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let _addr2: std::net::SocketAddr = "127.0.0.1:8081".parse().unwrap();

        // Test manager capacity without creating real peers
        assert_eq!(manager.peer_count(), 0);
        assert!(manager.can_accept_peer());

        // Test that we can't exceed max peers
        // (In a real test, we'd create mock peers, but for now we test the logic)
        assert_eq!(manager.peer_count(), 0);
    }

    #[tokio::test]
    async fn test_peer_manager_remove_peer() {
        let mut manager = PeerManager::new(10);
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test removing non-existent peer
        let transport_addr = TransportAddr::Tcp(addr);
        let removed_peer = manager.remove_peer(&transport_addr);
        assert!(removed_peer.is_none());
        assert_eq!(manager.peer_count(), 0);
    }

    #[tokio::test]
    async fn test_peer_manager_get_peer() {
        let manager = PeerManager::new(10);
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test getting non-existent peer
        let transport_addr = TransportAddr::Tcp(addr);
        let retrieved_peer = manager.get_peer(&transport_addr);
        assert!(retrieved_peer.is_none());
    }

    #[tokio::test]
    async fn test_peer_manager_peer_addresses() {
        let manager = PeerManager::new(10);
        let _addr1: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let _addr2: std::net::SocketAddr = "127.0.0.1:8081".parse().unwrap();

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test getting addresses when no peers exist
        let addresses = manager.peer_addresses();
        assert_eq!(addresses.len(), 0);
    }

    #[tokio::test]
    async fn test_connection_manager_creation() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = ConnectionManager::new(addr);

        assert_eq!(manager.listen_addr(), addr);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_creation() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        assert_eq!(manager.peer_count(), 0);
        assert_eq!(manager.peer_addresses().len(), 0);
    }

    #[tokio::test]
    async fn test_network_manager_with_config() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::with_config(
            addr,
            5,
            crate::network::transport::TransportPreference::TCP_ONLY,
            None,
        );

        // peer_count() might not exist, check peer_manager instead
        let peer_manager = manager.peer_manager().await;
        assert_eq!(peer_manager.peer_count(), 0);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_peer_count() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_peer_addresses() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test getting addresses when no peers exist
        let addresses = manager.peer_addresses();
        assert_eq!(addresses.len(), 0);
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_broadcast() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test broadcast with no peers (should succeed)
        let message = b"test message".to_vec();
        let result = manager.broadcast(message).await;
        assert!(result.is_ok());
    }

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_send_to_peer() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test manager logic without creating real peers
        assert_eq!(manager.peer_count(), 0);

        // Test send to non-existent peer (returns Err - peer not in peer manager)
        let peer_addr = "127.0.0.1:8081".parse().unwrap();
        let message = b"test message".to_vec();
        let result = manager.send_to_peer(peer_addr, message).await;
        assert!(result.is_err()); // Peer not found when not connected
    }

    #[tokio::test]
    async fn test_network_manager_send_to_nonexistent_peer() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test send to non-existent peer
        let peer_addr = "127.0.0.1:8081".parse().unwrap();
        let message = b"test message".to_vec();
        let result = manager.send_to_peer(peer_addr, message).await;
        assert!(result.is_err()); // Peer not found when not in peer manager
    }

    #[tokio::test]
    async fn test_network_message_peer_connected() {
        let socket_addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let transport_addr = TransportAddr::Tcp(socket_addr);
        let message = NetworkMessage::PeerConnected(transport_addr.clone());
        match message {
            NetworkMessage::PeerConnected(addr) => {
                assert_eq!(addr, transport_addr);
            }
            _ => panic!("Expected PeerConnected message"),
        }
    }

    #[tokio::test]
    async fn test_network_message_peer_disconnected() {
        let socket_addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let transport_addr = TransportAddr::Tcp(socket_addr);
        let message = NetworkMessage::PeerDisconnected(transport_addr.clone());
        match message {
            NetworkMessage::PeerDisconnected(addr) => {
                assert_eq!(addr, transport_addr);
            }
            _ => panic!("Expected PeerDisconnected message"),
        }
    }

    #[tokio::test]
    async fn test_network_message_block_received() {
        let data = b"block data".to_vec();
        let message = NetworkMessage::BlockReceived(data.clone());
        match message {
            NetworkMessage::BlockReceived(msg_data) => {
                assert_eq!(msg_data, data);
            }
            _ => panic!("Expected BlockReceived message"),
        }
    }

    #[tokio::test]
    async fn test_network_message_transaction_received() {
        let data = b"tx data".to_vec();
        let message = NetworkMessage::TransactionReceived(data.clone());
        match message {
            NetworkMessage::TransactionReceived(msg_data) => {
                assert_eq!(msg_data, data);
            }
            _ => panic!("Expected TransactionReceived message"),
        }
    }

    #[tokio::test]
    async fn test_network_message_inventory_received() {
        let data = b"inv data".to_vec();
        let peer: SocketAddr = "127.0.0.1:18333".parse().unwrap();
        let message = NetworkMessage::InventoryReceived(data.clone(), peer);
        match message {
            NetworkMessage::InventoryReceived(msg_data, addr) => {
                assert_eq!(msg_data, data);
                assert_eq!(addr, peer);
            }
            _ => panic!("Expected InventoryReceived message"),
        }
    }

    // NOTE: `test_handle_incoming_wire_tcp_enqueues_pkgtxn` was removed — it hung under async
    // mutex contention on `handle_incoming_wire_tcp`. Full routing is covered by integration tests.

    #[tokio::test(flavor = "multi_thread")]
    async fn test_network_manager_peer_manager_access() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        // Test immutable access - drop the guard immediately to avoid holding lock
        {
            let peer_manager = manager.peer_manager().await;
            assert_eq!(peer_manager.peer_count(), 0);
        } // Guard dropped here

        // Test peer count access (this also locks the mutex, but guard is dropped immediately)
        assert_eq!(manager.peer_count(), 0);
    }

    #[tokio::test]
    async fn test_network_manager_transport_preference() {
        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let manager = NetworkManager::new(addr);

        assert_eq!(
            manager.transport_preference(),
            TransportPreference::TCP_ONLY
        );
    }

    /// Block request/response connection test (IBD first-block path).
    /// Tests register_block_request + complete_block_request matching without full wire parsing,
    /// since handle_incoming_wire_tcp can block in test environments.
    #[tokio::test(flavor = "multi_thread")]
    async fn test_block_request_completion_direct() {
        use crate::storage::hashing::double_sha256;
        use blvm_protocol::genesis;

        let genesis = genesis::mainnet_genesis();
        let mut header_bytes = Vec::with_capacity(80);
        header_bytes.extend_from_slice(&(genesis.header.version as i32).to_le_bytes());
        header_bytes.extend_from_slice(&genesis.header.prev_block_hash);
        header_bytes.extend_from_slice(&genesis.header.merkle_root);
        header_bytes.extend_from_slice(&(genesis.header.timestamp as u32).to_le_bytes());
        header_bytes.extend_from_slice(&(genesis.header.bits as u32).to_le_bytes());
        header_bytes.extend_from_slice(&(genesis.header.nonce as u32).to_le_bytes());
        let block_hash = double_sha256(&header_bytes);
        let mut hash_array = [0u8; 32];
        hash_array.copy_from_slice(&block_hash);

        let addr: std::net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
        let network = NetworkManager::with_config(addr, 5, TransportPreference::TCP_ONLY, None);

        let peer_addr: std::net::SocketAddr = "127.0.0.1:18444".parse().unwrap();
        let block_rx = network.register_block_request(peer_addr, hash_array);

        let empty_witnesses: Vec<Vec<blvm_protocol::segwit::Witness>> =
            (0..genesis.transactions.len()).map(|_| vec![]).collect();
        let ok = network.complete_block_request(
            peer_addr,
            hash_array,
            genesis.clone(),
            empty_witnesses.clone(),
        );
        assert!(
            ok,
            "complete_block_request should find matching pending request"
        );

        let (received, witnesses) =
            tokio::time::timeout(std::time::Duration::from_secs(1), block_rx)
                .await
                .expect("block rx should complete within 1s")
                .expect("block channel should not be closed");

        assert_eq!(received.header.merkle_root, genesis.header.merkle_root);
        assert_eq!(witnesses.len(), genesis.transactions.len());
    }
}
