# app/src/telegram/ui/currency_ui.py

from __future__ import annotations

from src.integrations.exchange.exceptions import ExchangeError
from src.integrations.exchange.models import BalanceSummary
from src.integrations.exchange.service import ExchangeService
from src.market_data.acquisition.models.instrument import Instrument


FIAT_CURRENCIES = {"USD", "USDT", "EUR", "RUB", "BYN"}

CURRENCY_ICONS = {
    "USD": "$",
    "USDT": "$",
    "EUR": "€",
    "RUB": "₽",
    "BYN": "Br",
    "BTC": "₿",
    "ETH": "Ξ",
    "LTC": "LTC",
    "BNB": "BNB",
    "SOL": "SOL",
    "ADA": "ADA",
    "XRP": "XRP",
    "DOGE": "DOGE",
}


def is_fiat_currency(currency: str) -> bool:
    return currency.upper() in FIAT_CURRENCIES


def get_currency_icon(currency: str) -> str:
    return CURRENCY_ICONS.get(
        currency.upper(),
        currency.upper(),
    )


def get_currency_label(currency: str) -> str:
    return f"{get_currency_icon(currency)} {currency.upper()}"


def render_currency_title(currency: str) -> str:
    return get_currency_label(currency)


def format_amount(currency: str, value: float) -> str:
    if is_fiat_currency(currency):
        return f"{value:,.2f}".replace(",", " ")

    return f"{value:,.8f}".replace(",", " ")


def format_usd_amount(value: float) -> str:
    return f"{value:,.2f}".replace(",", " ")


def format_usd_price(
    value: float | int | str | None,
) -> str:
    if value is None:
        return "—"

    try:
        return f"{float(value):,.2f}".replace(",", " ")
    except (TypeError, ValueError):
        return "—"


def format_usd_pnl(
    value: float | int | str | None,
) -> str:
    if value is None:
        return "—"

    try:
        pnl = float(value)
    except (TypeError, ValueError):
        return "—"

    if pnl > 0:
        return f"🟢 +{format_usd_price(pnl)} USD"

    if pnl < 0:
        return f"🔴 -{format_usd_price(abs(pnl))} USD"

    return f"⚪ {format_usd_price(0)} USD"


def render_currency_line(
    *,
    currency: str,
    value: float,
    show_code: bool = True,
) -> str:
    icon = get_currency_icon(currency)
    amount = format_amount(
        currency,
        value,
    )

    if show_code:
        return f"{icon} {currency.upper()} · {amount}"

    return f"{icon} {amount}"


def balance_total(item: BalanceSummary) -> float:
    return item.available + item.locked


def is_zero_balance(item: BalanceSummary) -> bool:
    return (
        abs(item.available) < 1e-12
        and abs(item.locked) < 1e-12
    )


def _quote_priority(quote_asset: str) -> int:
    value = (quote_asset or "").upper()

    if value == "USD":
        return 3

    if value == "USDT":
        return 2

    return 0


def _status_priority(status: str) -> int:
    value = (status or "").upper()

    if value == "TRADING":
        return 2

    if value in {"HALT", "BREAK"}:
        return 0

    return 1


def _market_type_priority(market_type: str) -> int:
    value = (market_type or "").upper()

    if value == "SPOT":
        return 3

    if value == "LEVERAGE":
        return 2

    return 1


def _instrument_priority(
    instrument: Instrument,
) -> tuple[int, int, int, str]:
    return (
        _quote_priority(instrument.quote_asset),
        _status_priority(instrument.status),
        _market_type_priority(instrument.market_type),
        instrument.symbol.upper(),
    )


def _resolve_asset_quote_instrument(
    exchange_service: ExchangeService,
    asset: str,
) -> Instrument | None:
    asset_upper = asset.upper()

    try:
        instruments = exchange_service.get_instruments()
    except ExchangeError:
        return None

    candidates: list[Instrument] = []

    for instrument in instruments:
        base_asset = (
            instrument.base_asset or ""
        ).upper()
        quote_asset = (
            instrument.quote_asset or ""
        ).upper()

        if base_asset != asset_upper:
            continue

        if quote_asset not in {"USD", "USDT"}:
            continue

        candidates.append(instrument)

    if not candidates:
        return None

    candidates.sort(
        key=_instrument_priority,
        reverse=True,
    )

    return candidates[0]


def get_asset_usd_rate(
    exchange_service: ExchangeService,
    currency: str,
    price_cache: dict[str, float | None],
) -> float | None:
    asset = currency.upper()

    if asset in {"USD", "USDT"}:
        return 1.0

    if asset in price_cache:
        return price_cache[asset]

    instrument = _resolve_asset_quote_instrument(
        exchange_service,
        asset,
    )

    if instrument is None:
        price_cache[asset] = None
        return None

    try:
        quote = exchange_service.get_quote(
            instrument.symbol
        )
        rate = float(quote.last_price)

        # Пока считаем USDT ~= USD.
        price_cache[asset] = rate

        return rate

    except ExchangeError:
        price_cache[asset] = None
        return None


def estimate_balance_usd(
    item: BalanceSummary,
    exchange_service: ExchangeService,
    price_cache: dict[str, float | None],
) -> float | None:
    total = balance_total(item)

    if total <= 0:
        return None

    rate = get_asset_usd_rate(
        exchange_service,
        item.currency,
        price_cache,
    )

    if rate is None:
        return None

    return total * rate