import httpx
from loguru import logger
from tenacity import retry, stop_after_attempt, wait_exponential
from app.config import settings

COINGECKO_BASE = "https://api.coingecko.com/api/v3"

COIN_ID_MAP = {
    "BTC": "bitcoin",
    "ETH": "ethereum",
    "LTC": "litecoin",
    "DOGE": "dogecoin",
    "BCH": "bitcoin-cash",
    "BSV": "bitcoin-sv",
    "ETC": "ethereum-classic",
    "RVN": "ravencoin",
    "ERGO": "ergo",
    "FLUX": "flux",
    "KDA": "kadena",
    "XMR": "monero",
    "ZEC": "zcash",
    "DASH": "dash",
    "DGB": "digibyte",
}

FALLBACK_PRICES = {
    "BTC": 65000.0,
    "ETH": 3200.0,
    "LTC": 85.0,
    "DOGE": 0.12,
    "BCH": 380.0,
    "BSV": 55.0,
    "ETC": 25.0,
    "RVN": 0.025,
    "ERGO": 1.8,
    "FLUX": 0.8,
    "KDA": 0.9,
    "XMR": 145.0,
    "ZEC": 25.0,
    "DASH": 30.0,
    "DGB": 0.015,
}

MINING_PARAMS = {
    "BTC": {
        "block_reward": 3.125,
        "block_time": 600,
        "difficulty": 88_000_000_000_000,
        "network_hashrate": 650_000_000,  # TH/s
        "algorithm": "SHA-256",
    },
    "ETH": {
        "block_reward": 2.0,
        "block_time": 12,
        "difficulty": 0,
        "network_hashrate": 0,
        "algorithm": "Ethash (PoS - not mineable)",
    },
    "LTC": {
        "block_reward": 6.25,
        "block_time": 150,
        "difficulty": 30_000_000,
        "network_hashrate": 900,  # TH/s
        "algorithm": "Scrypt",
    },
    "DOGE": {
        "block_reward": 10000,
        "block_time": 60,
        "difficulty": 15_000_000,
        "network_hashrate": 1300,  # TH/s
        "algorithm": "Scrypt",
    },
    "ETC": {
        "block_reward": 2.56,
        "block_time": 13,
        "difficulty": 2_000_000_000_000,
        "network_hashrate": 150_000,  # GH/s → converted to TH/s = 150
        "algorithm": "Etchash",
    },
    "BCH": {
        "block_reward": 3.125,
        "block_time": 600,
        "difficulty": 600_000_000_000,
        "network_hashrate": 4000,  # TH/s
        "algorithm": "SHA-256",
    },
}


@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
async def get_coin_price(coin_symbol: str) -> float:
    coin_id = COIN_ID_MAP.get(coin_symbol.upper())
    if not coin_id:
        logger.warning(f"Unknown coin: {coin_symbol}, using fallback price")
        return FALLBACK_PRICES.get(coin_symbol.upper(), 0.0)

    headers = {}
    if settings.coingecko_api_key:
        headers["x-cg-demo-api-key"] = settings.coingecko_api_key

    try:
        async with httpx.AsyncClient(timeout=15.0) as client:
            response = await client.get(
                f"{COINGECKO_BASE}/simple/price",
                params={"ids": coin_id, "vs_currencies": "usd"},
                headers=headers,
            )
            response.raise_for_status()
            data = response.json()
            price = data[coin_id]["usd"]
            logger.info(f"Fetched price for {coin_symbol}: ${price}")
            return float(price)
    except Exception as e:
        logger.error(f"CoinGecko error for {coin_symbol}: {e}")
        return FALLBACK_PRICES.get(coin_symbol.upper(), 0.0)


async def get_multiple_prices(coins: list[str]) -> dict[str, float]:
    coin_ids = [COIN_ID_MAP.get(c.upper()) for c in coins if COIN_ID_MAP.get(c.upper())]
    if not coin_ids:
        return {c: FALLBACK_PRICES.get(c.upper(), 0.0) for c in coins}

    headers = {}
    if settings.coingecko_api_key:
        headers["x-cg-demo-api-key"] = settings.coingecko_api_key

    try:
        async with httpx.AsyncClient(timeout=15.0) as client:
            response = await client.get(
                f"{COINGECKO_BASE}/simple/price",
                params={"ids": ",".join(coin_ids), "vs_currencies": "usd"},
                headers=headers,
            )
            response.raise_for_status()
            data = response.json()

        result = {}
        for coin in coins:
            coin_id = COIN_ID_MAP.get(coin.upper())
            if coin_id and coin_id in data:
                result[coin.upper()] = data[coin_id]["usd"]
            else:
                result[coin.upper()] = FALLBACK_PRICES.get(coin.upper(), 0.0)
        return result
    except Exception as e:
        logger.error(f"CoinGecko bulk price error: {e}")
        return {c: FALLBACK_PRICES.get(c.upper(), 0.0) for c in coins}


def get_mining_params(coin: str) -> dict:
    return MINING_PARAMS.get(coin.upper(), {
        "block_reward": 2.0,
        "block_time": 600,
        "difficulty": 1_000_000_000,
        "network_hashrate": 100,
        "algorithm": "Unknown",
    })
