//! Ethereum Bridge Implementation
//!
//! Lock-Mint bridge for Ethereum assets:
//! - ETH → sETH (wrapped ETH on Synor)
//! - ERC-20 → sERC20 (wrapped tokens)
//!
//! # Lock-Mint Flow
//!
//! 1. User locks ETH/ERC-20 in vault contract on Ethereum
//! 2. Relayer detects lock event and submits proof to Synor
//! 3. Synor verifies proof and mints wrapped tokens
//!
//! # Burn-Unlock Flow
//!
//! 1. User burns wrapped tokens on Synor
//! 2. Relayer detects burn event and submits proof to Ethereum
//! 3. Vault contract verifies proof and unlocks original tokens

use crate::{
    AssetId, Bridge, BridgeAddress, BridgeError, BridgeResult, BridgeTransfer, ChainType, TransferId, TransferManager, TransferStatus, VaultManager,
    ETH_MIN_CONFIRMATIONS,
};
use alloy_primitives::{Address, B256, U256};
use alloy_sol_types::sol;
use async_trait::async_trait;
use borsh::{BorshDeserialize, BorshSerialize};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use sha3::{Digest, Keccak256};
use std::collections::HashMap;
use std::sync::Arc;

// Solidity event signatures
sol! {
    event TokenLocked(
        address indexed token,
        address indexed sender,
        bytes32 recipient,
        uint256 amount,
        uint256 nonce
    );

    event TokenUnlocked(
        address indexed token,
        address indexed recipient,
        uint256 amount,
        bytes32 transferId
    );
}

/// Ethereum bridge configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EthereumBridgeConfig {
    /// Ethereum chain ID
    pub chain_id: u64,
    /// Vault contract address
    pub vault_address: Address,
    /// Required confirmations
    pub required_confirmations: u64,
    /// Supported tokens (address → AssetId)
    pub supported_tokens: HashMap<Address, AssetId>,
    /// Relayer addresses (for multi-sig)
    pub relayers: Vec<Address>,
    /// Required relayer signatures
    pub required_signatures: usize,
    /// Whether bridge is paused
    pub paused: bool,
    /// Daily limit per token (address → limit)
    pub daily_limits: HashMap<Address, U256>,
}

impl Default for EthereumBridgeConfig {
    fn default() -> Self {
        let mut supported_tokens = HashMap::new();
        supported_tokens.insert(Address::ZERO, AssetId::eth()); // Native ETH

        Self {
            chain_id: 1, // Mainnet
            vault_address: Address::ZERO,
            required_confirmations: ETH_MIN_CONFIRMATIONS,
            supported_tokens,
            relayers: Vec::new(),
            required_signatures: 1,
            paused: false,
            daily_limits: HashMap::new(),
        }
    }
}

impl EthereumBridgeConfig {
    /// Create testnet config
    pub fn sepolia() -> Self {
        Self {
            chain_id: 11155111,
            required_confirmations: 3, // Lower for testnet
            ..Default::default()
        }
    }

    /// Add supported token
    pub fn add_token(&mut self, address: Address, asset: AssetId) {
        self.supported_tokens.insert(address, asset);
    }

    /// Add relayer
    pub fn add_relayer(&mut self, address: Address) {
        if !self.relayers.contains(&address) {
            self.relayers.push(address);
        }
    }
}

/// Ethereum event types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EthereumEventType {
    /// Token locked for bridging to Synor
    TokenLocked,
    /// Token unlocked after bridging from Synor
    TokenUnlocked,
}

/// Ethereum event
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EthereumEvent {
    /// Event type
    pub event_type: EthereumEventType,
    /// Transaction hash
    pub tx_hash: B256,
    /// Block number
    pub block_number: u64,
    /// Log index
    pub log_index: u64,
    /// Token address (zero for native ETH)
    pub token: Address,
    /// Sender address
    pub sender: Address,
    /// Amount
    pub amount: U256,
    /// Recipient (Synor address for lock, Ethereum address for unlock)
    pub recipient: Vec<u8>,
    /// Nonce
    pub nonce: u64,
}

impl EthereumEvent {
    /// Compute event hash for verification
    pub fn hash(&self) -> B256 {
        let mut hasher = Keccak256::new();
        hasher.update(self.tx_hash.as_slice());
        hasher.update(self.block_number.to_le_bytes());
        hasher.update(self.log_index.to_le_bytes());
        hasher.update(self.token.as_slice());
        hasher.update(self.sender.as_slice());
        hasher.update(self.amount.to_le_bytes::<32>());
        hasher.update(&self.recipient);
        hasher.update(self.nonce.to_le_bytes());

        let result = hasher.finalize();
        B256::from_slice(&result)
    }
}

/// Wrapped token on Synor
#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct WrappedToken {
    /// Original asset
    pub original: AssetId,
    /// Wrapped asset on Synor
    pub wrapped: AssetId,
    /// Total supply minted
    pub total_supply: u128,
    /// Original token contract on Ethereum
    pub ethereum_address: Vec<u8>,
}

impl WrappedToken {
    /// Create a wrapped token
    pub fn new(ethereum_address: Address, original: AssetId) -> Self {
        let wrapped = AssetId::wrapped(&original);
        Self {
            original,
            wrapped,
            total_supply: 0,
            ethereum_address: ethereum_address.to_vec(),
        }
    }

    /// Mint wrapped tokens
    pub fn mint(&mut self, amount: u128) {
        self.total_supply += amount;
    }

    /// Burn wrapped tokens
    pub fn burn(&mut self, amount: u128) -> BridgeResult<()> {
        if amount > self.total_supply {
            return Err(BridgeError::InsufficientBalance {
                required: amount,
                available: self.total_supply,
            });
        }
        self.total_supply -= amount;
        Ok(())
    }
}

/// Ethereum bridge
pub struct EthereumBridge {
    /// Configuration
    config: RwLock<EthereumBridgeConfig>,
    /// Transfer manager
    transfers: Arc<RwLock<TransferManager>>,
    /// Vault manager
    vaults: Arc<RwLock<VaultManager>>,
    /// Wrapped tokens by original address
    wrapped_tokens: RwLock<HashMap<Address, WrappedToken>>,
    /// Pending events awaiting confirmation
    pending_events: RwLock<HashMap<B256, EthereumEvent>>,
    /// Processed event hashes (to prevent replay)
    processed_events: RwLock<HashMap<B256, bool>>,
    /// Relayer signatures per event
    relayer_signatures: RwLock<HashMap<B256, Vec<(Address, Vec<u8>)>>>,
}

impl EthereumBridge {
    /// Create a new Ethereum bridge
    pub fn new(config: EthereumBridgeConfig) -> Self {
        Self {
            config: RwLock::new(config),
            transfers: Arc::new(RwLock::new(TransferManager::new())),
            vaults: Arc::new(RwLock::new(VaultManager::new())),
            wrapped_tokens: RwLock::new(HashMap::new()),
            pending_events: RwLock::new(HashMap::new()),
            processed_events: RwLock::new(HashMap::new()),
            relayer_signatures: RwLock::new(HashMap::new()),
        }
    }

    /// Create for Sepolia testnet
    pub fn sepolia() -> Self {
        Self::new(EthereumBridgeConfig::sepolia())
    }

    /// Get configuration
    pub fn config(&self) -> EthereumBridgeConfig {
        self.config.read().clone()
    }

    /// Update configuration
    pub fn update_config<F>(&self, f: F)
    where
        F: FnOnce(&mut EthereumBridgeConfig),
    {
        f(&mut self.config.write());
    }

    /// Pause bridge
    pub fn pause(&self) {
        self.config.write().paused = true;
    }

    /// Resume bridge
    pub fn resume(&self) {
        self.config.write().paused = false;
    }

    /// Check if bridge is paused
    pub fn is_paused(&self) -> bool {
        self.config.read().paused
    }

    /// Process a lock event from Ethereum
    pub fn process_lock_event(
        &self,
        event: EthereumEvent,
        current_time: u64,
    ) -> BridgeResult<TransferId> {
        if self.is_paused() {
            return Err(BridgeError::BridgePaused);
        }

        // Check for replay
        let event_hash = event.hash();
        if self.processed_events.read().contains_key(&event_hash) {
            return Err(BridgeError::TransferAlreadyExists(
                hex::encode(event_hash.as_slice()),
            ));
        }

        // Verify token is supported
        let config = self.config.read();
        let asset = config
            .supported_tokens
            .get(&event.token)
            .cloned()
            .ok_or_else(|| BridgeError::AssetNotSupported(format!("{:?}", event.token)))?;

        // Create bridge address from recipient bytes
        let recipient = if event.recipient.len() == 32 {
            let mut arr = [0u8; 32];
            arr.copy_from_slice(&event.recipient);
            BridgeAddress::from_synor(arr)
        } else {
            return Err(BridgeError::InvalidAddress("invalid recipient".to_string()));
        };

        let sender = BridgeAddress::from_eth(event.sender.into());
        let amount = event.amount.to::<u128>();

        // Create transfer
        let transfer_id = self.transfers.write().create_inbound(
            ChainType::Ethereum,
            asset,
            amount,
            sender,
            recipient,
            config.required_confirmations,
            current_time,
        )?;

        // Store pending event
        self.pending_events.write().insert(event_hash, event);

        // Mark event as processed to prevent replay
        self.processed_events.write().insert(event_hash, true);

        // Record lock in transfer
        self.transfers.write().confirm_lock(
            &transfer_id,
            event_hash.to_vec(),
            0, // Will be updated with actual block number
            current_time,
        )?;

        Ok(transfer_id)
    }

    /// Submit relayer signature for an event
    pub fn submit_relayer_signature(
        &self,
        event_hash: B256,
        relayer: Address,
        signature: Vec<u8>,
    ) -> BridgeResult<bool> {
        let config = self.config.read();

        // Verify relayer is authorized
        if !config.relayers.contains(&relayer) {
            return Err(BridgeError::SignatureVerificationFailed(
                "unauthorized relayer".to_string(),
            ));
        }

        // Add signature
        let mut signatures = self.relayer_signatures.write();
        let sigs = signatures.entry(event_hash).or_default();

        // Check for duplicate
        if sigs.iter().any(|(r, _)| r == &relayer) {
            return Ok(false);
        }

        sigs.push((relayer, signature));

        // Check if we have enough signatures
        Ok(sigs.len() >= config.required_signatures)
    }

    /// Update confirmations for pending events
    pub fn update_confirmations(
        &self,
        current_block: u64,
        current_time: u64,
    ) -> BridgeResult<Vec<TransferId>> {
        let config = self.config.read();
        let required_confirmations = config.required_confirmations;
        drop(config);

        let mut confirmed = Vec::new();

        // Collect pending events and their confirmations
        let pending = self.pending_events.read();
        let events_to_process: Vec<_> = pending
            .iter()
            .map(|(hash, event)| {
                let confirmations = current_block.saturating_sub(event.block_number);
                (*hash, confirmations)
            })
            .collect();
        drop(pending);

        // Find and update matching transfers
        for (event_hash, confirmations) in events_to_process {
            // Collect matching transfer IDs first
            let matching_transfer_id = {
                let transfers = self.transfers.read();
                transfers
                    .pending_transfers()
                    .iter()
                    .find_map(|transfer| {
                        transfer.source_tx_hash.as_ref().and_then(|tx_hash| {
                            if tx_hash.as_slice() == event_hash.as_slice() {
                                Some(transfer.id.clone())
                            } else {
                                None
                            }
                        })
                    })
            };

            // Now update the transfer if found
            if let Some(transfer_id) = matching_transfer_id {
                self.transfers.write().update_confirmations(
                    &transfer_id,
                    confirmations,
                    current_time,
                )?;

                if confirmations >= required_confirmations {
                    confirmed.push(transfer_id);
                }
            }
        }

        Ok(confirmed)
    }

    /// Mint wrapped tokens after confirmation
    pub fn mint_wrapped_tokens(
        &self,
        transfer_id: &TransferId,
        current_time: u64,
    ) -> BridgeResult<()> {
        let mut transfers = self.transfers.write();
        let transfer = transfers
            .get(transfer_id)
            .ok_or_else(|| BridgeError::TransferNotFound(transfer_id.to_string()))?;

        // Verify transfer is confirmed
        if transfer.status != TransferStatus::Confirmed {
            return Err(BridgeError::InvalidProof(format!(
                "transfer not confirmed: {}",
                transfer.status
            )));
        }

        // Get original token address
        let token_address = if transfer.asset.identifier == "native" {
            Address::ZERO
        } else {
            let bytes = hex::decode(
                transfer
                    .asset
                    .identifier
                    .strip_prefix("0x")
                    .unwrap_or(&transfer.asset.identifier),
            )
            .map_err(|e| BridgeError::InvalidAddress(e.to_string()))?;

            if bytes.len() != 20 {
                return Err(BridgeError::InvalidAddress("invalid address length".to_string()));
            }
            Address::from_slice(&bytes)
        };

        // Get or create wrapped token
        let mut wrapped_tokens = self.wrapped_tokens.write();
        let wrapped = wrapped_tokens
            .entry(token_address)
            .or_insert_with(|| WrappedToken::new(token_address, transfer.asset.clone()));

        // Mint tokens
        wrapped.mint(transfer.amount);

        // Mark transfer as completed
        drop(wrapped_tokens);
        transfers.confirm_mint(transfer_id, vec![], current_time)?;

        Ok(())
    }

    /// Initiate burn for outbound transfer
    pub fn initiate_burn(
        &self,
        asset: AssetId,
        amount: u128,
        sender: BridgeAddress,
        recipient: BridgeAddress,
        current_time: u64,
    ) -> BridgeResult<TransferId> {
        if self.is_paused() {
            return Err(BridgeError::BridgePaused);
        }

        // Find wrapped token
        let token_address = if let Some(id) = asset.unwrap_identifier() {
            if id == "native" {
                Address::ZERO
            } else {
                let bytes = hex::decode(id.strip_prefix("0x").unwrap_or(id))
                    .map_err(|e| BridgeError::InvalidAddress(e.to_string()))?;
                Address::from_slice(&bytes)
            }
        } else {
            return Err(BridgeError::AssetNotSupported(asset.to_string()));
        };

        // Verify we have enough supply
        let mut wrapped_tokens = self.wrapped_tokens.write();
        let wrapped = wrapped_tokens
            .get_mut(&token_address)
            .ok_or_else(|| BridgeError::AssetNotSupported(format!("{:?}", token_address)))?;

        // Burn tokens
        wrapped.burn(amount)?;

        // Get original asset
        let original_asset = wrapped.original.clone();

        // Create outbound transfer
        let config = self.config.read();
        let transfer_id = self.transfers.write().create_outbound(
            ChainType::Ethereum,
            original_asset,
            amount,
            sender,
            recipient,
            config.required_confirmations,
            current_time,
        )?;

        Ok(transfer_id)
    }

    /// Get wrapped token info
    pub fn get_wrapped_token(&self, address: Address) -> Option<WrappedToken> {
        self.wrapped_tokens.read().get(&address).cloned()
    }

    /// Get total wrapped supply
    pub fn total_wrapped_supply(&self) -> u128 {
        self.wrapped_tokens
            .read()
            .values()
            .map(|t| t.total_supply)
            .sum()
    }

    /// Get transfer manager
    pub fn transfer_manager(&self) -> Arc<RwLock<TransferManager>> {
        self.transfers.clone()
    }

    /// Get vault manager
    pub fn vault_manager(&self) -> Arc<RwLock<VaultManager>> {
        self.vaults.clone()
    }
}

#[async_trait]
impl Bridge for EthereumBridge {
    fn source_chain(&self) -> ChainType {
        ChainType::Ethereum
    }

    fn destination_chain(&self) -> ChainType {
        ChainType::Synor
    }

    fn supports_asset(&self, asset: &AssetId) -> bool {
        let config = self.config.read();
        config
            .supported_tokens
            .values()
            .any(|a| a.identifier == asset.identifier)
    }

    fn min_confirmations(&self) -> u64 {
        self.config.read().required_confirmations
    }

    async fn lock(&self, transfer: &BridgeTransfer) -> BridgeResult<TransferId> {
        // In production, this would interact with Ethereum contract
        // For now, we simulate the lock
        Ok(transfer.id.clone())
    }

    async fn verify_lock(&self, transfer_id: &TransferId) -> BridgeResult<bool> {
        let transfers = self.transfers.read();
        let transfer = transfers
            .get(transfer_id)
            .ok_or_else(|| BridgeError::TransferNotFound(transfer_id.to_string()))?;

        Ok(transfer.has_sufficient_confirmations())
    }

    async fn mint(&self, transfer: &BridgeTransfer) -> BridgeResult<()> {
        let current_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();

        self.mint_wrapped_tokens(&transfer.id, current_time)
    }

    async fn burn(&self, transfer: &BridgeTransfer) -> BridgeResult<TransferId> {
        let current_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();

        self.initiate_burn(
            transfer.asset.clone(),
            transfer.amount,
            transfer.sender.clone(),
            transfer.recipient.clone(),
            current_time,
        )
    }

    async fn unlock(&self, transfer_id: &TransferId) -> BridgeResult<()> {
        // In production, this would interact with Ethereum contract
        let current_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();

        self.transfers
            .write()
            .confirm_unlock(transfer_id, vec![], current_time)
    }

    async fn get_transfer_status(&self, transfer_id: &TransferId) -> BridgeResult<TransferStatus> {
        let transfers = self.transfers.read();
        let transfer = transfers
            .get(transfer_id)
            .ok_or_else(|| BridgeError::TransferNotFound(transfer_id.to_string()))?;

        Ok(transfer.status)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::TransferDirection;

    // ==================== Helper Functions ====================

    fn test_sender() -> BridgeAddress {
        BridgeAddress::from_eth([0xaa; 20])
    }

    fn test_recipient() -> BridgeAddress {
        BridgeAddress::from_synor([0xbb; 32])
    }

    fn create_lock_event(nonce: u64) -> EthereumEvent {
        EthereumEvent {
            event_type: EthereumEventType::TokenLocked,
            tx_hash: B256::from([0x11; 32]),
            block_number: 100,
            log_index: 0,
            token: Address::ZERO,
            sender: Address::from([0xaa; 20]),
            amount: U256::from(1000u64),
            recipient: vec![0xbb; 32],
            nonce,
        }
    }

    // ==================== EthereumBridgeConfig Tests ====================

    #[test]
    fn test_config_default() {
        let config = EthereumBridgeConfig::default();

        assert_eq!(config.chain_id, 1);
        assert_eq!(config.required_confirmations, ETH_MIN_CONFIRMATIONS);
        assert!(!config.paused);
    }

    #[test]
    fn test_config_sepolia() {
        let config = EthereumBridgeConfig::sepolia();

        assert_eq!(config.chain_id, 11155111);
        assert_eq!(config.required_confirmations, 3);
    }

    #[test]
    fn test_config_add_token() {
        let mut config = EthereumBridgeConfig::default();
        let usdc_address = Address::from([0x12; 20]);
        let usdc_asset = AssetId::erc20("0x1212121212121212121212121212121212121212", "USDC", 6);

        config.add_token(usdc_address, usdc_asset.clone());

        assert!(config.supported_tokens.contains_key(&usdc_address));
    }

    #[test]
    fn test_config_add_relayer() {
        let mut config = EthereumBridgeConfig::default();
        let relayer = Address::from([0x11; 20]);

        config.add_relayer(relayer);

        assert_eq!(config.relayers.len(), 1);
    }

    #[test]
    fn test_config_add_relayer_duplicate() {
        let mut config = EthereumBridgeConfig::default();
        let relayer = Address::from([0x11; 20]);

        config.add_relayer(relayer);
        config.add_relayer(relayer);

        assert_eq!(config.relayers.len(), 1);
    }

    // ==================== EthereumEvent Tests ====================

    #[test]
    fn test_event_hash_deterministic() {
        let event = create_lock_event(0);

        let hash1 = event.hash();
        let hash2 = event.hash();

        assert_eq!(hash1, hash2);
    }

    #[test]
    fn test_event_hash_different_nonce() {
        let event1 = create_lock_event(0);
        let event2 = create_lock_event(1);

        assert_ne!(event1.hash(), event2.hash());
    }

    #[test]
    fn test_event_hash() {
        let event1 = EthereumEvent {
            event_type: EthereumEventType::TokenLocked,
            tx_hash: B256::from([0x11; 32]),
            block_number: 100,
            log_index: 0,
            token: Address::ZERO,
            sender: Address::from([0xaa; 20]),
            amount: U256::from(1000u64),
            recipient: vec![0xbb; 32],
            nonce: 0,
        };

        let event2 = EthereumEvent {
            nonce: 1,
            ..event1.clone()
        };

        assert_ne!(event1.hash(), event2.hash());

        let event3 = event1.clone();
        assert_eq!(event1.hash(), event3.hash());
    }

    // ==================== WrappedToken Tests ====================

    #[test]
    fn test_wrapped_token_new() {
        let wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());

        assert_eq!(wrapped.total_supply, 0);
        assert!(wrapped.wrapped.is_wrapped());
        assert_eq!(wrapped.wrapped.symbol, "sETH");
    }

    #[test]
    fn test_wrapped_token_mint() {
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());

        wrapped.mint(1000);
        assert_eq!(wrapped.total_supply, 1000);

        wrapped.mint(500);
        assert_eq!(wrapped.total_supply, 1500);
    }

    #[test]
    fn test_wrapped_token_burn() {
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(1000);

        wrapped.burn(400).unwrap();
        assert_eq!(wrapped.total_supply, 600);
    }

    #[test]
    fn test_wrapped_token_burn_insufficient() {
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(1000);

        let result = wrapped.burn(1500);
        assert!(matches!(result, Err(BridgeError::InsufficientBalance { .. })));
    }

    #[test]
    fn test_wrapped_token_burn_exact() {
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(1000);

        wrapped.burn(1000).unwrap();
        assert_eq!(wrapped.total_supply, 0);
    }

    // ==================== EthereumBridge Tests ====================

    #[test]
    fn test_bridge_creation() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        assert!(!bridge.is_paused());
        assert!(bridge.supports_asset(&AssetId::eth()));
    }

    #[test]
    fn test_bridge_sepolia() {
        let bridge = EthereumBridge::sepolia();
        let config = bridge.config();

        assert_eq!(config.chain_id, 11155111);
        assert_eq!(config.required_confirmations, 3);
    }

    #[test]
    fn test_bridge_update_config() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        bridge.update_config(|config| {
            config.required_confirmations = 20;
        });

        let config = bridge.config();
        assert_eq!(config.required_confirmations, 20);
    }

    #[test]
    fn test_bridge_pause() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        bridge.pause();
        assert!(bridge.is_paused());

        let event = create_lock_event(0);
        let result = bridge.process_lock_event(event, 0);
        assert!(matches!(result, Err(BridgeError::BridgePaused)));

        bridge.resume();
        assert!(!bridge.is_paused());
    }

    #[test]
    fn test_bridge_burn_when_paused() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let mut wrapped_tokens = bridge.wrapped_tokens.write();
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(5000);
        wrapped_tokens.insert(Address::ZERO, wrapped);
        drop(wrapped_tokens);

        bridge.pause();

        let asset = AssetId::wrapped(&AssetId::eth());
        let result = bridge.initiate_burn(asset, 1000, test_recipient(), test_sender(), 0);

        assert!(matches!(result, Err(BridgeError::BridgePaused)));
    }

    #[test]
    fn test_lock_event_processing() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let event = create_lock_event(0);
        let transfer_id = bridge.process_lock_event(event, current_time).unwrap();

        let transfers = bridge.transfers.read();
        let transfer = transfers.get(&transfer_id).unwrap();
        assert_eq!(transfer.direction, TransferDirection::Inbound);
        assert_eq!(transfer.amount, 1000);
    }

    #[test]
    fn test_lock_event_replay_protection() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let event = create_lock_event(0);
        bridge.process_lock_event(event.clone(), current_time).unwrap();

        let result = bridge.process_lock_event(event, current_time + 100);
        assert!(matches!(result, Err(BridgeError::TransferAlreadyExists(_))));
    }

    #[test]
    fn test_lock_event_unsupported_token() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let event = EthereumEvent {
            event_type: EthereumEventType::TokenLocked,
            tx_hash: B256::from([0x11; 32]),
            block_number: 100,
            log_index: 0,
            token: Address::from([0x99; 20]),
            sender: Address::from([0xaa; 20]),
            amount: U256::from(1000u64),
            recipient: vec![0xbb; 32],
            nonce: 0,
        };

        let result = bridge.process_lock_event(event, 0);
        assert!(matches!(result, Err(BridgeError::AssetNotSupported(_))));
    }

    #[test]
    fn test_lock_event_invalid_recipient() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let event = EthereumEvent {
            event_type: EthereumEventType::TokenLocked,
            tx_hash: B256::from([0x11; 32]),
            block_number: 100,
            log_index: 0,
            token: Address::ZERO,
            sender: Address::from([0xaa; 20]),
            amount: U256::from(1000u64),
            recipient: vec![0xbb; 20],
            nonce: 0,
        };

        let result = bridge.process_lock_event(event, 0);
        assert!(matches!(result, Err(BridgeError::InvalidAddress(_))));
    }

    #[test]
    fn test_relayer_signature_unauthorized() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let event_hash = B256::from([0x11; 32]);
        let unauthorized_relayer = Address::from([0x99; 20]);

        let result = bridge.submit_relayer_signature(event_hash, unauthorized_relayer, vec![0x00; 65]);
        assert!(matches!(result, Err(BridgeError::SignatureVerificationFailed(_))));
    }

    #[test]
    fn test_relayer_signature_authorized() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let relayer = Address::from([0x11; 20]);

        bridge.update_config(|config| {
            config.add_relayer(relayer);
            config.required_signatures = 1;
        });

        let event_hash = B256::from([0x11; 32]);
        let result = bridge.submit_relayer_signature(event_hash, relayer, vec![0x00; 65]).unwrap();

        assert!(result);
    }

    #[test]
    fn test_wrapped_token_minting() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let event = create_lock_event(0);
        let transfer_id = bridge.process_lock_event(event, current_time).unwrap();

        bridge
            .transfers
            .write()
            .update_confirmations(&transfer_id, 12, current_time + 100)
            .unwrap();

        bridge.mint_wrapped_tokens(&transfer_id, current_time + 200).unwrap();

        let wrapped = bridge.get_wrapped_token(Address::ZERO).unwrap();
        assert_eq!(wrapped.total_supply, 1000);
    }

    #[test]
    fn test_mint_not_confirmed() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let event = create_lock_event(0);
        let transfer_id = bridge.process_lock_event(event, current_time).unwrap();

        let result = bridge.mint_wrapped_tokens(&transfer_id, current_time + 100);
        assert!(matches!(result, Err(BridgeError::InvalidProof(_))));
    }

    #[test]
    fn test_mint_nonexistent_transfer() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let result = bridge.mint_wrapped_tokens(&TransferId::new("nonexistent"), 0);
        assert!(matches!(result, Err(BridgeError::TransferNotFound(_))));
    }

    #[test]
    fn test_burn_initiation() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let mut wrapped_tokens = bridge.wrapped_tokens.write();
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(5000);
        wrapped_tokens.insert(Address::ZERO, wrapped);
        drop(wrapped_tokens);

        let asset = AssetId::wrapped(&AssetId::eth());
        let transfer_id = bridge
            .initiate_burn(
                asset,
                1000,
                test_recipient(),
                test_sender(),
                current_time,
            )
            .unwrap();

        let transfers = bridge.transfers.read();
        let transfer = transfers.get(&transfer_id).unwrap();
        assert_eq!(transfer.direction, TransferDirection::Outbound);
        assert_eq!(transfer.amount, 1000);

        drop(transfers);
        let wrapped = bridge.get_wrapped_token(Address::ZERO).unwrap();
        assert_eq!(wrapped.total_supply, 4000);
    }

    #[test]
    fn test_burn_insufficient_supply() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let current_time = 1700000000;

        let mut wrapped_tokens = bridge.wrapped_tokens.write();
        let mut wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped.mint(500);
        wrapped_tokens.insert(Address::ZERO, wrapped);
        drop(wrapped_tokens);

        let asset = AssetId::wrapped(&AssetId::eth());
        let result = bridge.initiate_burn(
            asset,
            1000,
            test_recipient(),
            test_sender(),
            current_time,
        );

        assert!(matches!(result, Err(BridgeError::InsufficientBalance { .. })));
    }

    #[test]
    fn test_burn_no_wrapped_token() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        let asset = AssetId::wrapped(&AssetId::eth());
        let result = bridge.initiate_burn(
            asset,
            1000,
            test_recipient(),
            test_sender(),
            0,
        );

        assert!(matches!(result, Err(BridgeError::AssetNotSupported(_))));
    }

    #[test]
    fn test_bridge_get_wrapped_token() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        assert!(bridge.get_wrapped_token(Address::ZERO).is_none());

        let mut wrapped_tokens = bridge.wrapped_tokens.write();
        let wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        wrapped_tokens.insert(Address::ZERO, wrapped);
        drop(wrapped_tokens);

        assert!(bridge.get_wrapped_token(Address::ZERO).is_some());
    }

    #[test]
    fn test_bridge_total_wrapped_supply() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());

        assert_eq!(bridge.total_wrapped_supply(), 0);

        let mut wrapped_tokens = bridge.wrapped_tokens.write();

        let mut eth_wrapped = WrappedToken::new(Address::ZERO, AssetId::eth());
        eth_wrapped.mint(1000);
        wrapped_tokens.insert(Address::ZERO, eth_wrapped);

        let usdc_address = Address::from([0x12; 20]);
        let mut usdc_wrapped = WrappedToken::new(usdc_address, AssetId::erc20("0x12", "USDC", 6));
        usdc_wrapped.mint(500);
        wrapped_tokens.insert(usdc_address, usdc_wrapped);

        drop(wrapped_tokens);

        assert_eq!(bridge.total_wrapped_supply(), 1500);
    }

    #[test]
    fn test_bridge_transfer_manager() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let manager = bridge.transfer_manager();

        assert_eq!(manager.read().pending_transfers().len(), 0);
    }

    #[test]
    fn test_bridge_vault_manager() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let manager = bridge.vault_manager();

        assert_eq!(manager.read().total_locked(), 0);
    }

    #[test]
    fn test_bridge_source_chain() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        assert_eq!(bridge.source_chain(), ChainType::Ethereum);
    }

    #[test]
    fn test_bridge_destination_chain() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        assert_eq!(bridge.destination_chain(), ChainType::Synor);
    }

    #[test]
    fn test_bridge_supports_asset() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        assert!(bridge.supports_asset(&AssetId::eth()));
    }

    #[test]
    fn test_bridge_supports_asset_unsupported() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        let random_asset = AssetId::erc20("0x9999999999999999999999999999999999999999", "RAND", 18);
        assert!(!bridge.supports_asset(&random_asset));
    }

    #[test]
    fn test_bridge_min_confirmations() {
        let bridge = EthereumBridge::new(EthereumBridgeConfig::default());
        assert_eq!(bridge.min_confirmations(), ETH_MIN_CONFIRMATIONS);
    }

    #[test]
    fn test_bridge_min_confirmations_sepolia() {
        let bridge = EthereumBridge::sepolia();
        assert_eq!(bridge.min_confirmations(), 3);
    }
}
