/**
 * @file bridge.hpp
 * @brief Synor Bridge SDK for C++
 *
 * Modern C++17 SDK for cross-chain asset transfers with lock-mint and burn-unlock patterns.
 */

#pragma once

#include <string>
#include <vector>
#include <optional>
#include <future>
#include <memory>
#include <cstdint>
#include <chrono>
#include "wallet.hpp"  // For SynorException

namespace synor {
namespace bridge {

/// Chain identifier
enum class ChainId {
    Synor,
    Ethereum,
    Polygon,
    Arbitrum,
    Optimism,
    Bsc,
    Avalanche,
    Solana,
    Cosmos
};

/// Asset type
enum class AssetType {
    Native,
    Erc20,
    Erc721,
    Erc1155
};

/// Transfer status
enum class TransferStatus {
    Pending,
    Locked,
    Confirming,
    Minting,
    Completed,
    Failed,
    Refunded
};

/// Transfer direction
enum class TransferDirection {
    LockMint,
    BurnUnlock
};

/// Bridge configuration
struct Config {
    std::string api_key;
    std::string endpoint = "https://bridge.synor.io/v1";
    uint32_t timeout_ms = 60000;
    uint32_t retries = 3;
    bool debug = false;
};

/// Native currency
struct NativeCurrency {
    std::string name;
    std::string symbol;
    int32_t decimals;
};

/// A blockchain network
struct Chain {
    ChainId id;
    std::string name;
    int64_t chain_id;
    std::string rpc_url;
    std::string explorer_url;
    NativeCurrency native_currency;
    int32_t confirmations;
    int32_t estimated_block_time;
    bool supported;
};

/// An asset
struct Asset {
    std::string id;
    std::string symbol;
    std::string name;
    AssetType type;
    ChainId chain;
    std::optional<std::string> contract_address;
    int32_t decimals;
    std::optional<std::string> logo_url;
    bool verified = false;
};

/// A wrapped asset
struct WrappedAsset {
    Asset original_asset;
    Asset wrapped_asset;
    ChainId chain;
    std::string bridge_contract;
};

/// Validator signature
struct ValidatorSignature {
    std::string validator;
    std::string signature;
    int64_t timestamp;
};

/// Lock receipt
struct LockReceipt {
    std::string id;
    std::string tx_hash;
    ChainId source_chain;
    ChainId target_chain;
    Asset asset;
    std::string amount;
    std::string sender;
    std::string recipient;
    int64_t lock_timestamp;
    int32_t confirmations;
    int32_t required_confirmations;
};

/// Lock proof
struct LockProof {
    LockReceipt lock_receipt;
    std::vector<std::string> merkle_proof;
    std::string block_header;
    std::vector<ValidatorSignature> signatures;
};

/// Burn receipt
struct BurnReceipt {
    std::string id;
    std::string tx_hash;
    ChainId source_chain;
    ChainId target_chain;
    Asset wrapped_asset;
    Asset original_asset;
    std::string amount;
    std::string sender;
    std::string recipient;
    int64_t burn_timestamp;
    int32_t confirmations;
    int32_t required_confirmations;
};

/// Burn proof
struct BurnProof {
    BurnReceipt burn_receipt;
    std::vector<std::string> merkle_proof;
    std::string block_header;
    std::vector<ValidatorSignature> signatures;
};

/// A transfer
struct Transfer {
    std::string id;
    TransferDirection direction;
    TransferStatus status;
    ChainId source_chain;
    ChainId target_chain;
    Asset asset;
    std::string amount;
    std::string sender;
    std::string recipient;
    std::optional<std::string> source_tx_hash;
    std::optional<std::string> target_tx_hash;
    std::string fee;
    Asset fee_asset;
    int64_t created_at;
    int64_t updated_at;
    std::optional<int64_t> completed_at;
    std::optional<std::string> error_message;
};

/// Transfer filter
struct TransferFilter {
    std::optional<TransferStatus> status;
    std::optional<ChainId> source_chain;
    std::optional<ChainId> target_chain;
    std::optional<std::string> asset;
    std::optional<std::string> sender;
    std::optional<std::string> recipient;
    std::optional<int32_t> limit;
    std::optional<int32_t> offset;
};

/// Fee estimate
struct FeeEstimate {
    std::string bridge_fee;
    std::string gas_fee_source;
    std::string gas_fee_target;
    std::string total_fee;
    Asset fee_asset;
    int32_t estimated_time;
    std::optional<std::string> exchange_rate;
};

/// Exchange rate
struct ExchangeRate {
    Asset from_asset;
    Asset to_asset;
    std::string rate;
    std::string inverse_rate;
    int64_t last_updated;
    std::string source;
};

/// Signed transaction
struct SignedTransaction {
    std::string tx_hash;
    ChainId chain;
    std::string from;
    std::string to;
    std::string value;
    std::string data;
    std::string gas_limit;
    std::optional<std::string> gas_price;
    std::optional<std::string> max_fee_per_gas;
    std::optional<std::string> max_priority_fee_per_gas;
    int32_t nonce;
    std::string signature;
};

/// Lock options
struct LockOptions {
    std::optional<std::string> recipient;
    std::optional<int64_t> deadline;
    std::optional<double> slippage;
};

/// Mint options
struct MintOptions {
    std::optional<std::string> gas_limit;
    std::optional<std::string> max_fee_per_gas;
    std::optional<std::string> max_priority_fee_per_gas;
};

/// Burn options
struct BurnOptions {
    std::optional<std::string> recipient;
    std::optional<int64_t> deadline;
};

/// Unlock options
struct UnlockOptions {
    std::optional<std::string> gas_limit;
    std::optional<std::string> gas_price;
};

// Forward declaration
class SynorBridgeImpl;

/// Synor Bridge client
class SynorBridge {
public:
    explicit SynorBridge(const Config& config);
    ~SynorBridge();

    SynorBridge(const SynorBridge&) = delete;
    SynorBridge& operator=(const SynorBridge&) = delete;
    SynorBridge(SynorBridge&&) noexcept;
    SynorBridge& operator=(SynorBridge&&) noexcept;

    // Chain operations
    std::future<std::vector<Chain>> get_supported_chains();
    std::future<Chain> get_chain(ChainId chain_id);
    std::future<bool> is_chain_supported(ChainId chain_id);

    // Asset operations
    std::future<std::vector<Asset>> get_supported_assets(ChainId chain_id);
    std::future<Asset> get_asset(const std::string& asset_id);
    std::future<WrappedAsset> get_wrapped_asset(const std::string& original_asset_id,
                                                 ChainId target_chain);

    // Fee & rate operations
    std::future<FeeEstimate> estimate_fee(const std::string& asset, const std::string& amount,
                                          ChainId source_chain, ChainId target_chain);
    std::future<ExchangeRate> get_exchange_rate(const std::string& from_asset,
                                                 const std::string& to_asset);

    // Lock-Mint flow
    std::future<LockReceipt> lock(const std::string& asset, const std::string& amount,
                                   ChainId target_chain, const LockOptions& options = {});
    std::future<LockProof> get_lock_proof(const std::string& lock_receipt_id);
    std::future<LockProof> wait_for_lock_proof(
        const std::string& lock_receipt_id,
        std::chrono::milliseconds poll_interval = std::chrono::seconds(5),
        std::chrono::milliseconds max_wait = std::chrono::minutes(10));
    std::future<SignedTransaction> mint(const LockProof& proof, const std::string& target_address,
                                        const MintOptions& options = {});

    // Burn-Unlock flow
    std::future<BurnReceipt> burn(const std::string& wrapped_asset, const std::string& amount,
                                   const BurnOptions& options = {});
    std::future<BurnProof> get_burn_proof(const std::string& burn_receipt_id);
    std::future<BurnProof> wait_for_burn_proof(
        const std::string& burn_receipt_id,
        std::chrono::milliseconds poll_interval = std::chrono::seconds(5),
        std::chrono::milliseconds max_wait = std::chrono::minutes(10));
    std::future<SignedTransaction> unlock(const BurnProof& proof, const UnlockOptions& options = {});

    // Transfer management
    std::future<Transfer> get_transfer(const std::string& transfer_id);
    std::future<TransferStatus> get_transfer_status(const std::string& transfer_id);
    std::future<std::vector<Transfer>> list_transfers(const TransferFilter& filter = {});
    std::future<Transfer> wait_for_transfer(
        const std::string& transfer_id,
        std::chrono::milliseconds poll_interval = std::chrono::seconds(10),
        std::chrono::milliseconds max_wait = std::chrono::minutes(30));

    // Convenience methods
    std::future<Transfer> bridge_to(const std::string& asset, const std::string& amount,
                                    ChainId target_chain, const std::string& target_address,
                                    const LockOptions& lock_options = {},
                                    const MintOptions& mint_options = {});
    std::future<Transfer> bridge_back(const std::string& wrapped_asset, const std::string& amount,
                                      const BurnOptions& burn_options = {},
                                      const UnlockOptions& unlock_options = {});

    // Lifecycle
    void close();
    bool is_closed() const;
    std::future<bool> health_check();

private:
    std::unique_ptr<SynorBridgeImpl> impl_;
};

}  // namespace bridge
}  // namespace synor
