from dataclasses import dataclass
from loguru import logger
from web3 import Web3, Account

from src.utils import load_abi, is_native_token

@dataclass
class MarketConfig:
    market_address: str
    base_token: str
    quote_token: str
    market_symbol: str
    mm_entrypoint_address: str
    margin_contract_address: str
    base_token_decimals: int
    quote_token_decimals: int
    price_precision: int
    size_precision: int
    base_symbol: str
    quote_symbol: str
    orderbook_implementation: str  # Orderbook implementation contract address
    margin_account_implementation: str  # Margin account implementation contract address


@dataclass
class KuruMMConfig:
    rpc_url: str
    rpc_ws_url: str
    kuru_ws_url: str
    kuru_api_url: str
    private_key: str
    user_address: str


MON_AUSD_MARKET = MarketConfig(
    market_address="0x...",
    base_token="0x...",
    quote_token="0x...",
    market_symbol="MON-AUSD",
    mm_entrypoint_address="0xA9d8269ad1Bd6e2a02BD8996a338Dc5C16aef440",
    margin_contract_address="0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5",
    base_token_decimals=18,
    quote_token_decimals=18,
    price_precision=6,
    size_precision=6,
    base_symbol="MON",
    quote_symbol="AUSD",
    orderbook_implementation="0xea2Cc8769Fb04Ff1893Ed11cf517b7F040C823CD",
    margin_account_implementation="0x57cF97FE1FAC7D78B07e7e0761410cb2e91F0ca7",
)

MON_USDC_MARKET = MarketConfig(
    market_address="0x065C9d28E428A0db40191a54d33d5b7c71a9C394",
    base_token="0x0000000000000000000000000000000000000000",
    quote_token="0x754704Bc059F8C67012fEd69BC8A327a5aafb603",
    market_symbol="MON-USDC",
    mm_entrypoint_address="0xA9d8269ad1Bd6e2a02BD8996a338Dc5C16aef440",
    margin_contract_address="0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5",
    base_token_decimals=18,
    quote_token_decimals=6,
    price_precision=100000000,
    size_precision=10000000000,
    base_symbol="MON",
    quote_symbol="USDC",
    orderbook_implementation="0xea2Cc8769Fb04Ff1893Ed11cf517b7F040C823CD", 
    margin_account_implementation="0x57cF97FE1FAC7D78B07e7e0761410cb2e91F0ca7",
)

WBTC_AUSD_MARKET = MarketConfig(
    market_address="0xed1448a8f1859970B2C96D184938690353E88330",
    base_token="0x...",
    quote_token="0x...",
    market_symbol="BTC-AUSD",
    mm_entrypoint_address="0xA9d8269ad1Bd6e2a02BD8996a338Dc5C16aef440",
    margin_contract_address="0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5",
    base_token_decimals=8,
    quote_token_decimals=6,
    price_precision=2,
    size_precision=8,
    base_symbol="BTC",
    quote_symbol="USDC",
    orderbook_implementation="0xea2Cc8769Fb04Ff1893Ed11cf517b7F040C823CD",
    margin_account_implementation="0x57cF97FE1FAC7D78B07e7e0761410cb2e91F0ca7",
)

MARKETS = {
    "MON-AUSD": MON_AUSD_MARKET,
    "MON-USDC": MON_USDC_MARKET,
    "BTC-AUSD": BTC_AUSD_MARKET,
}


KuruTopicsSignature = {
    # Orderbook events
    "OrderCreated": "OrderCreated(uint40,address,uint96,uint32,bool)",
    "OrdersCanceled": "OrdersCanceled(uint40[],address)",
    "OrderCanceled": "OrderCanceled(uint40,address,uint32,uint96,bool)",
    "Trade": "Trade(uint40,address,bool,uint256,uint96,address,address,uint96)",
    # MM Entrypoint events
    "batchUpdate": "batchUpdate(bytes32[],bytes32[],bytes32[])",
}



def market_config_from_market_address(
    market_address: str,
    mm_entrypoint_address: str = "0xA9d8269ad1Bd6e2a02BD8996a338Dc5C16aef440",
    margin_contract_address: str = "0x2A68ba1833cDf93fa9Da1EEbd7F46242aD8E90c5",
    rpc_url: str = "https://rpc.fullnode.kuru.io/",
    margin_account_implementation: str = "0x57cF97FE1FAC7D78B07e7e0761410cb2e91F0ca7",
    orderbook_implementation: str = "0xea2Cc8769Fb04Ff1893Ed11cf517b7F040C823CD",
) -> MarketConfig:
    try:
        orderbook_abi = load_abi("orderbook")
        erc20_abi = load_abi("erc20")

        w3 = Web3(Web3.HTTPProvider(rpc_url))
        if not w3.is_connected():
            logger.error(f"Failed to connect to RPC at {rpc_url}")
            raise ConnectionError(f"Failed to connect to RPC at {rpc_url}")

        # Convert all addresses to checksum format
        market_address = Web3.to_checksum_address(market_address)
        mm_entrypoint_address = Web3.to_checksum_address(mm_entrypoint_address)
        margin_contract_address = Web3.to_checksum_address(margin_contract_address)
        margin_account_implementation = Web3.to_checksum_address(margin_account_implementation)
        orderbook_implementation = Web3.to_checksum_address(orderbook_implementation)

        orderbook = w3.eth.contract(address=market_address, abi=orderbook_abi)
        params = orderbook.functions.getMarketParams().call()

        price_precision = int(params[0])
        size_precision = int(params[1])
        base_token = Web3.to_checksum_address(params[2])
        base_token_decimals = int(params[3])
        quote_token = Web3.to_checksum_address(params[4])
        quote_token_decimals = int(params[5])

        if is_native_token(base_token):
            base_symbol = "MON"
        else:
            base_contract = w3.eth.contract(address=base_token, abi=erc20_abi)
            try:
                base_symbol = base_contract.functions.symbol().call()
            except Exception as e:
                logger.warning(f"Failed to fetch base token symbol: {e}")
                base_symbol = ""

        if is_native_token(quote_token):
            quote_symbol = "MON"
        else:
            quote_contract = w3.eth.contract(address=quote_token, abi=erc20_abi)
            try:
                quote_symbol = quote_contract.functions.symbol().call()
            except Exception as e:
                logger.warning(f"Failed to fetch quote token symbol: {e}")
                quote_symbol = ""

        market_symbol = f"{base_symbol}-{quote_symbol}"

        margin_account_implementation = margin_account_implementation
        orderbook_implementation = orderbook_implementation

        logger.info(f"Successfully fetched market config for {market_symbol}")

        return MarketConfig(
            market_address=market_address,
            base_token=base_token,
            quote_token=quote_token,
            market_symbol=market_symbol,
            mm_entrypoint_address=mm_entrypoint_address,
            margin_contract_address=margin_contract_address,
            base_token_decimals=base_token_decimals,
            quote_token_decimals=quote_token_decimals,
            price_precision=price_precision,
            size_precision=size_precision,
            base_symbol=base_symbol,
            quote_symbol=quote_symbol,
            orderbook_implementation=orderbook_implementation,
            margin_account_implementation=margin_account_implementation,
        )
    except Exception as e:
        logger.error(f"Failed to fetch market config: {e}")
        raise


def initialize_kuru_mm_config(
    private_key: str,
    rpc_url: str = "https://rpc.fullnode.kuru.io/",
    rpc_ws_url: str = "wss://rpc.fullnode.kuru.io/",
    kuru_ws_url: str = "wss://ws.kuru.io/",
    kuru_api_url: str = "https://api.kuru.io/",
) -> KuruMMConfig:
    if not private_key:
        raise ValueError("private_key cannot be None or empty")

    account = Account.from_key(private_key)
    user_address = account.address
    logger.success(f"User address: {user_address}")

    logger.info(f"Initializing Kuru MM config")
    logger.info(f"User address: {user_address}")

    default_rpc = "https://rpc.fullnode.kuru.io/"
    default_ws = "wss://ws.kuru.io/"

    if rpc_url == default_rpc:
        logger.warning(
            "Using default public RPC/Websocket endpoints. You may experience rate limiting. Consider using a custom RPC for production use."
            "For more information, see TODO: docs URL"
        )

    return KuruMMConfig(
        rpc_url=rpc_url,
        rpc_ws_url=rpc_ws_url,
        kuru_ws_url=kuru_ws_url,
        kuru_api_url=kuru_api_url,
        private_key=private_key,
        user_address=user_address,
    )
