"""Chain configuration, contract addresses, ABI loading, and token/pair constants.

All addresses are checksummed.  The SDK ships with a bundled copy of
``base-sepolia.json`` from ``sdks/shared/chains/`` so that no filesystem
access is needed at runtime.
"""

from __future__ import annotations

import json
import re
from pathlib import Path
from typing import Any, Dict, List

# ---------------------------------------------------------------------------
# ABI loader
# ---------------------------------------------------------------------------

_ABI_DIR = Path(__file__).resolve().parent.parent.parent / "shared" / "abis"


def _load_abi(name: str) -> list:
    """Load a JSON ABI file from the shared abis directory.

    Falls back to an empty list if the file is unavailable (e.g. when the
    package is installed outside the monorepo).
    """
    path = _ABI_DIR / f"{name}.json"
    if path.exists():
        with open(path, "r") as fh:
            return json.load(fh)
    return []


# Pre-loaded ABIs
ABIS: Dict[str, List[Dict[str, Any]]] = {
    "TraderVault": _load_abi("TraderVault"),
    "VaultFactory": _load_abi("VaultFactory"),
    "TradeRouter": _load_abi("TradeRouter"),
    "AgentController": _load_abi("AgentController"),
    "UniswapV3Adapter": _load_abi("UniswapV3Adapter"),
    "AaveAdapter": _load_abi("AaveAdapter"),
    "GainsAdapter": _load_abi("GainsAdapter"),
    "ERC20": _load_abi("ERC20"),
}

# ---------------------------------------------------------------------------
# Chain configurations
# ---------------------------------------------------------------------------

CHAIN_CONFIGS: Dict[str, Dict[str, Any]] = {
    "base-testnet": {
        "chain_id": 84532,
        "name": "Base Sepolia",
        "rpc_url": "https://sepolia.base.org",
        "block_explorer": "https://sepolia.basescan.org",
        "contracts": {
            "vault_factory": "0x41a616FAf537cd014244B928A04b29A1Aa63F18c",
            "trade_router": "0xdFb66161871c8Dd119c55C73acf80f52B3B454Da",
            "agent_controller": "0x054c6CF6b65D5bFDE510659E21cA45B2E3D5b895",
            "trader_registry": "0x82288f1BA0ED4A6131F4Ef3C8d2b27f05072678C",
            "adapters": {
                "uniswap": "0xe676e31165A163cd243153B04aE681A5EEe733B5",
                "aave": "0xB299E2891e5526136c077e330ED6473466F7A0E2",
                "gains": "0xd6d3bcB1daa85336a114F1F18b94F1C4B335e97e",
            },
            "tokens": {
                "usdc": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
            },
        },
        "api": {
            "gateway": "https://api.openhedge.io",
            "feed": "wss://api.openhedge.io/feed",
        },
    },
    "base-mainnet": {
        "chain_id": 8453,
        "name": "Base Mainnet",
        "rpc_url": "https://mainnet.base.org",
        "block_explorer": "https://basescan.org",
        "contracts": {
            "vault_factory": "0x0000000000000000000000000000000000000000",
            "trade_router": "0x0000000000000000000000000000000000000000",
            "agent_controller": "0x0000000000000000000000000000000000000000",
            "trader_registry": "0x0000000000000000000000000000000000000000",
            "adapters": {
                "uniswap": "0x0000000000000000000000000000000000000000",
                "aave": "0x0000000000000000000000000000000000000000",
                "gains": "0x0000000000000000000000000000000000000000",
            },
            "tokens": {
                "usdc": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
            },
        },
        "api": {
            "gateway": "https://api.openhedge.io",
            "feed": "wss://api.openhedge.io/feed",
        },
    },
}


def get_chain_config(network: str) -> Dict[str, Any]:
    """Return the chain configuration for *network*.

    Raises ``ValueError`` for unknown network identifiers.
    """
    if network not in CHAIN_CONFIGS:
        supported = ", ".join(sorted(CHAIN_CONFIGS.keys()))
        raise ValueError(f"Unknown network '{network}'. Supported: {supported}")
    return CHAIN_CONFIGS[network]


# ---------------------------------------------------------------------------
# Token symbol -> address maps  (per-network)
# ---------------------------------------------------------------------------

TOKEN_SYMBOLS: Dict[str, Dict[str, str]] = {
    "base-testnet": {
        "USDC": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
        "WETH": "0x4200000000000000000000000000000000000006",
        "CBETH": "0x4fC531F8Ae7A7689E9fCC47fFF1a9BFcE178691e",
    },
    "base-mainnet": {
        "USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "WETH": "0x4200000000000000000000000000000000000006",
        "CBETH": "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22",
    },
}


def resolve_token(symbol_or_address: str, network: str) -> str:
    """Convert a token symbol (``'USDC'``) to its checksummed address.

    If the input is already a ``0x``-prefixed address it is returned as-is.
    """
    if symbol_or_address.startswith("0x"):
        if not re.match(r'^0x[0-9a-fA-F]{40}$', symbol_or_address):
            raise ValueError(f"Invalid Ethereum address: {symbol_or_address}")
        return symbol_or_address
    tokens = TOKEN_SYMBOLS.get(network, {})
    address = tokens.get(symbol_or_address.upper())
    if address is None:
        raise ValueError(
            f"Unknown token symbol '{symbol_or_address}' on {network}. "
            f"Known: {', '.join(sorted(tokens.keys()))}"
        )
    return address


# ---------------------------------------------------------------------------
# Perpetual pair names -> pairIndex for gTrade
# ---------------------------------------------------------------------------

PAIR_INDEX: Dict[str, int] = {
    "BTC/USD": 0,
    "ETH/USD": 1,
    "LINK/USD": 2,
    "DOGE/USD": 3,
    "SOL/USD": 4,
    "MATIC/USD": 5,
    "BNB/USD": 6,
    "ADA/USD": 7,
    "AVAX/USD": 8,
    "ARB/USD": 9,
}


def resolve_pair_index(pair: str) -> int:
    """Return the on-chain pairIndex for a named pair like ``'BTC/USD'``."""
    idx = PAIR_INDEX.get(pair.upper())
    if idx is None:
        from openhedge.exceptions import InvalidPairError
        raise InvalidPairError(pair)
    return idx


# ---------------------------------------------------------------------------
# Aave action enum (matches AaveAdapter.sol)
# ---------------------------------------------------------------------------

AAVE_ACTION_SUPPLY = 0
AAVE_ACTION_WITHDRAW = 1

# ---------------------------------------------------------------------------
# Gains action enum (matches GainsAdapter.sol)
# ---------------------------------------------------------------------------

GAINS_ACTION_OPEN = 0
GAINS_ACTION_CLOSE = 1
GAINS_ACTION_PARTIAL_CLOSE = 2
GAINS_ACTION_UPDATE_TP_SL = 3
GAINS_ACTION_UPDATE_MARGIN = 4

# ---------------------------------------------------------------------------
# Uniswap default pool fee (bps)
# ---------------------------------------------------------------------------

UNISWAP_DEFAULT_FEE = 3000  # 0.30% pool tier

# ---------------------------------------------------------------------------
# SDK version
# ---------------------------------------------------------------------------

SDK_VERSION = "0.1.2"
