//! Bridge types

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

// ==================== Chain Types ====================

/// Supported blockchain networks
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ChainId {
    Synor,
    Ethereum,
    Polygon,
    Arbitrum,
    Optimism,
    #[serde(rename = "bsc")]
    BSC,
    Avalanche,
    Solana,
    Cosmos,
}

/// Native currency info
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NativeCurrency {
    pub name: String,
    pub symbol: String,
    pub decimals: u8,
}

/// Chain information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Chain {
    pub id: ChainId,
    pub name: String,
    #[serde(rename = "chainId")]
    pub chain_id: u64,
    #[serde(rename = "rpcUrl")]
    pub rpc_url: String,
    #[serde(rename = "explorerUrl")]
    pub explorer_url: String,
    #[serde(rename = "nativeCurrency")]
    pub native_currency: NativeCurrency,
    pub confirmations: u32,
    #[serde(rename = "estimatedBlockTime")]
    pub estimated_block_time: u32,
    pub supported: bool,
}

// ==================== Asset Types ====================

/// Asset type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AssetType {
    Native,
    #[serde(rename = "erc20")]
    ERC20,
    #[serde(rename = "erc721")]
    ERC721,
    #[serde(rename = "erc1155")]
    ERC1155,
}

/// Asset information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Asset {
    pub id: String,
    pub symbol: String,
    pub name: String,
    #[serde(rename = "type")]
    pub asset_type: AssetType,
    pub chain: ChainId,
    #[serde(rename = "contractAddress", skip_serializing_if = "Option::is_none")]
    pub contract_address: Option<String>,
    pub decimals: u8,
    #[serde(rename = "logoUrl", skip_serializing_if = "Option::is_none")]
    pub logo_url: Option<String>,
    #[serde(default)]
    pub verified: bool,
}

/// Wrapped asset mapping
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WrappedAsset {
    #[serde(rename = "originalAsset")]
    pub original_asset: Asset,
    #[serde(rename = "wrappedAsset")]
    pub wrapped_asset: Asset,
    pub chain: ChainId,
    #[serde(rename = "bridgeContract")]
    pub bridge_contract: String,
}

// ==================== Transfer Types ====================

/// Transfer status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TransferStatus {
    Pending,
    Locked,
    Confirming,
    Minting,
    Completed,
    Failed,
    Refunded,
}

/// Transfer direction
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TransferDirection {
    LockMint,
    BurnUnlock,
}

/// Validator signature
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidatorSignature {
    pub validator: String,
    pub signature: String,
    pub timestamp: i64,
}

/// Lock receipt
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LockReceipt {
    pub id: String,
    #[serde(rename = "txHash")]
    pub tx_hash: String,
    #[serde(rename = "sourceChain")]
    pub source_chain: ChainId,
    #[serde(rename = "targetChain")]
    pub target_chain: ChainId,
    pub asset: Asset,
    pub amount: String,
    pub sender: String,
    pub recipient: String,
    #[serde(rename = "lockTimestamp")]
    pub lock_timestamp: i64,
    pub confirmations: u32,
    #[serde(rename = "requiredConfirmations")]
    pub required_confirmations: u32,
}

/// Lock proof for minting
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LockProof {
    #[serde(rename = "lockReceipt")]
    pub lock_receipt: LockReceipt,
    #[serde(rename = "merkleProof")]
    pub merkle_proof: Vec<String>,
    #[serde(rename = "blockHeader")]
    pub block_header: String,
    pub signatures: Vec<ValidatorSignature>,
}

/// Burn receipt
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BurnReceipt {
    pub id: String,
    #[serde(rename = "txHash")]
    pub tx_hash: String,
    #[serde(rename = "sourceChain")]
    pub source_chain: ChainId,
    #[serde(rename = "targetChain")]
    pub target_chain: ChainId,
    #[serde(rename = "wrappedAsset")]
    pub wrapped_asset: Asset,
    #[serde(rename = "originalAsset")]
    pub original_asset: Asset,
    pub amount: String,
    pub sender: String,
    pub recipient: String,
    #[serde(rename = "burnTimestamp")]
    pub burn_timestamp: i64,
    pub confirmations: u32,
    #[serde(rename = "requiredConfirmations")]
    pub required_confirmations: u32,
}

/// Burn proof for unlocking
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BurnProof {
    #[serde(rename = "burnReceipt")]
    pub burn_receipt: BurnReceipt,
    #[serde(rename = "merkleProof")]
    pub merkle_proof: Vec<String>,
    #[serde(rename = "blockHeader")]
    pub block_header: String,
    pub signatures: Vec<ValidatorSignature>,
}

/// Complete transfer record
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transfer {
    pub id: String,
    pub direction: TransferDirection,
    pub status: TransferStatus,
    #[serde(rename = "sourceChain")]
    pub source_chain: ChainId,
    #[serde(rename = "targetChain")]
    pub target_chain: ChainId,
    pub asset: Asset,
    pub amount: String,
    pub sender: String,
    pub recipient: String,
    #[serde(rename = "sourceTxHash", skip_serializing_if = "Option::is_none")]
    pub source_tx_hash: Option<String>,
    #[serde(rename = "targetTxHash", skip_serializing_if = "Option::is_none")]
    pub target_tx_hash: Option<String>,
    pub fee: String,
    #[serde(rename = "feeAsset")]
    pub fee_asset: Asset,
    #[serde(rename = "createdAt")]
    pub created_at: i64,
    #[serde(rename = "updatedAt")]
    pub updated_at: i64,
    #[serde(rename = "completedAt", skip_serializing_if = "Option::is_none")]
    pub completed_at: Option<i64>,
    #[serde(rename = "errorMessage", skip_serializing_if = "Option::is_none")]
    pub error_message: Option<String>,
}

// ==================== Fee Types ====================

/// Fee estimate
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeeEstimate {
    #[serde(rename = "bridgeFee")]
    pub bridge_fee: String,
    #[serde(rename = "gasFeeSource")]
    pub gas_fee_source: String,
    #[serde(rename = "gasFeeTarget")]
    pub gas_fee_target: String,
    #[serde(rename = "totalFee")]
    pub total_fee: String,
    #[serde(rename = "feeAsset")]
    pub fee_asset: Asset,
    #[serde(rename = "estimatedTime")]
    pub estimated_time: u32,
    #[serde(rename = "exchangeRate", skip_serializing_if = "Option::is_none")]
    pub exchange_rate: Option<String>,
}

/// Exchange rate
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExchangeRate {
    #[serde(rename = "fromAsset")]
    pub from_asset: Asset,
    #[serde(rename = "toAsset")]
    pub to_asset: Asset,
    pub rate: String,
    #[serde(rename = "inverseRate")]
    pub inverse_rate: String,
    #[serde(rename = "lastUpdated")]
    pub last_updated: i64,
    pub source: String,
}

// ==================== Transaction Types ====================

/// Signed transaction
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedTransaction {
    #[serde(rename = "txHash")]
    pub tx_hash: String,
    pub chain: ChainId,
    pub from: String,
    pub to: String,
    pub value: String,
    pub data: String,
    #[serde(rename = "gasLimit")]
    pub gas_limit: String,
    #[serde(rename = "gasPrice", skip_serializing_if = "Option::is_none")]
    pub gas_price: Option<String>,
    #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")]
    pub max_fee_per_gas: Option<String>,
    #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")]
    pub max_priority_fee_per_gas: Option<String>,
    pub nonce: u64,
    pub signature: String,
}

// ==================== Filter Types ====================

/// Transfer filter
#[derive(Debug, Clone, Default)]
pub struct TransferFilter {
    pub status: Option<TransferStatus>,
    pub source_chain: Option<ChainId>,
    pub target_chain: Option<ChainId>,
    pub asset: Option<String>,
    pub sender: Option<String>,
    pub recipient: Option<String>,
    pub from_date: Option<i64>,
    pub to_date: Option<i64>,
    pub limit: Option<u32>,
    pub offset: Option<u32>,
}

// ==================== Options Types ====================

/// Lock options
#[derive(Debug, Clone, Default, Serialize)]
pub struct LockOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub recipient: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deadline: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub slippage: Option<f64>,
}

/// Mint options
#[derive(Debug, Clone, Default, Serialize)]
pub struct MintOptions {
    #[serde(rename = "gasLimit", skip_serializing_if = "Option::is_none")]
    pub gas_limit: Option<String>,
    #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")]
    pub max_fee_per_gas: Option<String>,
    #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")]
    pub max_priority_fee_per_gas: Option<String>,
}

/// Burn options
#[derive(Debug, Clone, Default, Serialize)]
pub struct BurnOptions {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub recipient: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub deadline: Option<i64>,
}

/// Unlock options
#[derive(Debug, Clone, Default, Serialize)]
pub struct UnlockOptions {
    #[serde(rename = "gasLimit", skip_serializing_if = "Option::is_none")]
    pub gas_limit: Option<String>,
    #[serde(rename = "gasPrice", skip_serializing_if = "Option::is_none")]
    pub gas_price: Option<String>,
}

// ==================== Config Types ====================

/// Bridge configuration
#[derive(Debug, Clone)]
pub struct BridgeConfig {
    pub api_key: String,
    pub endpoint: String,
    pub timeout_secs: u64,
    pub retries: u32,
    pub debug: bool,
}

impl Default for BridgeConfig {
    fn default() -> Self {
        Self {
            api_key: String::new(),
            endpoint: "https://bridge.synor.io/v1".to_string(),
            timeout_secs: 60,
            retries: 3,
            debug: false,
        }
    }
}
