"""
CurrencyConverter - Real-time currency exchange rates.
Uses exchangerate-api.com (free tier) with caching.
"""

import asyncio
import time
from typing import Dict, List, Optional, Tuple
import logging

logger = logging.getLogger("zehnex.currency")

CURRENCY_NAMES = {
    "USD": ("🇺🇸", "US Dollar"),
    "EUR": ("🇪🇺", "Euro"),
    "UZS": ("🇺🇿", "O'zbek so'mi"),
    "RUB": ("🇷🇺", "Rossiya rubli"),
    "GBP": ("🇬🇧", "Britaniya funt sterlingi"),
    "JPY": ("🇯🇵", "Yapon iyenasi"),
    "CNY": ("🇨🇳", "Xitoy yuani"),
    "KZT": ("🇰🇿", "Qozog'iston tengesi"),
    "TRY": ("🇹🇷", "Turk lirasi"),
    "AED": ("🇦🇪", "BAA dirhami"),
    "KRW": ("🇰🇷", "Janubiy Koreya voni"),
    "INR": ("🇮🇳", "Hindiston rupiyasi"),
    "CAD": ("🇨🇦", "Kanada dollari"),
    "AUD": ("🇦🇺", "Avstraliya dollari"),
    "CHF": ("🇨🇭", "Shveytsariya franki"),
    "SEK": ("🇸🇪", "Shvetsiya kronasi"),
    "NOK": ("🇳🇴", "Norvegiya kronasi"),
    "BTC": ("₿", "Bitcoin"),
    "ETH": ("Ξ", "Ethereum"),
}


class CurrencyResult:
    def __init__(
        self,
        amount: float,
        from_currency: str,
        to_currency: str,
        rate: float,
        result: float,
        timestamp: float,
    ):
        self.amount = amount
        self.from_currency = from_currency.upper()
        self.to_currency = to_currency.upper()
        self.rate = rate
        self.result = result
        self.timestamp = timestamp

    def _fmt(self, currency: str, value: float) -> str:
        info = CURRENCY_NAMES.get(currency, ("💱", currency))
        flag, name = info
        decimals = 0 if value > 1000 else 2 if value > 1 else 6
        return f"{flag} {value:,.{decimals}f} {currency}"

    def __str__(self):
        from_str = self._fmt(self.from_currency, self.amount)
        to_str = self._fmt(self.to_currency, self.result)
        rate_str = f"1 {self.from_currency} = {self.rate:.4f} {self.to_currency}"
        return (
            f"💱 <b>Valyuta konvertatsiyasi</b>\n\n"
            f"{from_str}\n"
            f"⬇️\n"
            f"{to_str}\n\n"
            f"📊 Kurs: {rate_str}"
        )


class CurrencyConverter:
    """
    Real-time currency converter.

    Example:
        converter = CurrencyConverter()

        @bot.command("convert")
        async def convert_cmd(ctx):
            # Usage: /convert 100 USD UZS
            args = ctx.args
            if len(args) < 3:
                await ctx.reply("Foydalanish: /convert 100 USD UZS")
                return

            result = await converter.convert(float(args[0]), args[1], args[2])
            await ctx.reply(str(result))

        @bot.command("rates")
        async def rates_cmd(ctx):
            rates = await converter.get_rates("USD")
            await ctx.reply(converter.format_rates(rates))
    """

    CACHE_TTL = 300  # 5 minutes

    def __init__(self, api_key: Optional[str] = None, cache_ttl: int = 300):
        self.api_key = api_key
        self.cache_ttl = cache_ttl
        self._cache: Dict[str, Tuple[Dict, float]] = {}

    async def get_rates(self, base: str = "USD") -> Dict[str, float]:
        """Fetch exchange rates for a base currency."""
        base = base.upper()
        now = time.time()

        if base in self._cache:
            rates, cached_at = self._cache[base]
            if now - cached_at < self.cache_ttl:
                return rates

        import httpx

        urls = [
            f"https://open.er-api.com/v6/latest/{base}",
            f"https://api.exchangerate-api.com/v4/latest/{base}",
        ]

        async with httpx.AsyncClient(timeout=10) as client:
            for url in urls:
                try:
                    resp = await client.get(url)
                    data = resp.json()
                    rates = data.get("rates") or data.get("conversion_rates", {})
                    if rates:
                        self._cache[base] = (rates, now)
                        return rates
                except Exception as e:
                    logger.warning(f"Rate fetch failed ({url}): {e}")
                    continue

        raise ConnectionError("Valyuta kurslarini olishda xatolik.")

    async def convert(
        self, amount: float, from_currency: str, to_currency: str
    ) -> CurrencyResult:
        """
        Convert amount from one currency to another.

        Args:
            amount: Amount to convert
            from_currency: Source currency code (e.g. "USD")
            to_currency: Target currency code (e.g. "UZS")

        Returns:
            CurrencyResult with formatted output
        """
        from_c = from_currency.upper()
        to_c = to_currency.upper()

        rates = await self.get_rates(from_c)

        if to_c not in rates:
            raise ValueError(f"'{to_c}' valyuta topilmadi.")

        rate = rates[to_c]
        result = amount * rate

        return CurrencyResult(
            amount=amount,
            from_currency=from_c,
            to_currency=to_c,
            rate=rate,
            result=result,
            timestamp=time.time(),
        )

    async def get_popular_rates(self, base: str = "USD") -> Dict[str, float]:
        """Get rates for popular currencies only."""
        popular = ["EUR", "GBP", "UZS", "RUB", "CNY", "JPY", "TRY", "KZT", "AED"]
        all_rates = await self.get_rates(base)
        return {k: v for k, v in all_rates.items() if k in popular}

    def format_rates(self, rates: Dict[str, float], base: str = "USD") -> str:
        """Format rates as a nice message."""
        base_info = CURRENCY_NAMES.get(base, ("💱", base))
        lines = [f"{base_info[0]} <b>1 {base} kurslari:</b>\n"]
        for code, rate in rates.items():
            info = CURRENCY_NAMES.get(code, ("💱", code))
            decimals = 0 if rate > 1000 else 2 if rate > 1 else 6
            lines.append(f"{info[0]} {rate:,.{decimals}f} {code} — {info[1]}")
        return "\n".join(lines)

    @staticmethod
    def parse_convert_command(text: str) -> Optional[Tuple[float, str, str]]:
        """
        Parse conversion from text like '100 USD to UZS' or '50 EUR UZS'.

        Returns:
            (amount, from_currency, to_currency) or None
        """
        import re
        pattern = r"(\d+(?:\.\d+)?)\s+([A-Za-z]{2,4})(?:\s+(?:to|→|in|ga))?\s+([A-Za-z]{2,4})"
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            return float(match.group(1)), match.group(2).upper(), match.group(3).upper()
        return None
