from decimal import Decimal
from typing import Any

import httpx

from app.core.config import settings
from app.core.exceptions import ExternalServiceError
from app.core.logging import get_logger

logger = get_logger("app.ton")


class TonService:
    """All TON operations. Falls back to manual processing when unconfigured."""

    def __init__(self, base_url: str = "", api_key: str = "", timeout: float = 30.0) -> None:
        self.base_url = (base_url or settings.ton_api_url).rstrip("/")
        self.api_key = api_key or settings.ton_api_key
        self.timeout = timeout

    @property
    def configured(self) -> bool:
        return bool(self.base_url and self.api_key)

    async def _post(self, path: str, payload: dict[str, Any]) -> dict[str, Any]:
        if not self.configured:
            logger.warning("ton provider not configured, manual processing: %s", path)
            return {"manual": True, "reason": "ton_not_configured"}

        url = f"{self.base_url}/{path.lstrip('/')}"
        headers = {"Authorization": f"Bearer {self.api_key}"}
        try:
            async with httpx.AsyncClient(timeout=self.timeout) as client:
                response = await client.post(url, json=payload, headers=headers)
        except httpx.HTTPError as exc:
            logger.error("ton request failed: %s", exc)
            raise ExternalServiceError("ton_unavailable") from exc

        if response.status_code >= 400:
            logger.error("ton error %s: %s", response.status_code, response.text[:500])
            raise ExternalServiceError("ton_error")

        data = response.json()
        return data if isinstance(data, dict) else {"result": data}

    async def transfer(self, address: str, amount: Decimal, memo: str | None = None) -> dict[str, Any]:
        return await self._post(
            "transfer", {"address": address, "amount": str(amount), "memo": memo or ""}
        )

    async def charge_balance(self, username: str, amount: Decimal) -> dict[str, Any]:
        return await self._post("balance/charge", {"username": username, "amount": str(amount)})
