import logging
import time
from decimal import Decimal, InvalidOperation
from typing import Any

from bot.services.api import ApiClient, ApiError, api

logger = logging.getLogger("bot.texts")

CACHE_TTL = 60.0


class TextStore:
    """Bot texts, menu and settings, fetched from the backend and cached."""

    def __init__(self, client: ApiClient) -> None:
        self.client = client
        self._messages: dict[str, str] = {}
        self._menu: list[dict[str, Any]] = []
        self._settings: dict[str, Any] = {}
        self._loaded_at = 0.0

    async def refresh(self, force: bool = False) -> None:
        if not force and self._messages and time.monotonic() - self._loaded_at < CACHE_TTL:
            return
        try:
            config = await self.client.config()
        except ApiError as exc:
            logger.error("could not load bot config: %s", exc.code)
            return
        self._messages = config.get("messages", {})
        self._menu = config.get("menu", [])
        self._settings = config.get("settings", {})
        self._loaded_at = time.monotonic()

    async def text(self, key: str, **kwargs: Any) -> str:
        await self.refresh()
        template = self._messages.get(key, key)
        if not kwargs:
            return template
        try:
            return template.format(**kwargs)
        except (KeyError, IndexError, ValueError):
            return template

    async def menu(self) -> list[dict[str, Any]]:
        await self.refresh()
        return self._menu

    async def settings(self) -> dict[str, Any]:
        await self.refresh()
        return self._settings

    async def setting(self, key: str, default: Any = "") -> Any:
        return (await self.settings()).get(key, default)

    async def error(self, code: str) -> str:
        await self.refresh()
        return self._messages.get(f"error_{code}", self._messages.get("error_generic", code))


texts = TextStore(api)


def money(value: Any) -> str:
    """Format an amount with thousands separators (Toman)."""
    try:
        amount = Decimal(str(value))
    except (InvalidOperation, TypeError):
        return str(value)
    quantized = amount.quantize(Decimal("1")) if amount == amount.to_integral() else amount
    return f"{quantized:,}"


def crypto(value: Any) -> str:
    try:
        return format(Decimal(str(value)).normalize(), "f")
    except (InvalidOperation, TypeError):
        return str(value)
