"""Payamak SMS provider adapter — only used inside Communication service.""" from __future__ import annotations import time from typing import Any from uuid import uuid4 import httpx from app.providers.contracts import ( BalanceResult, ProviderHealth, SendRequest, SendResult, ) class PayamakSMSProvider: provider_kind = "payamak" channel = "sms" async def send(self, request: SendRequest, credentials: dict[str, Any]) -> SendResult: username = credentials.get("username") or credentials.get("api_key") password = credentials.get("password") or credentials.get("api_key") from_number = request.from_address or credentials.get("from") if not username or not password: # Dev-safe path: simulate send when credentials absent return SendResult( success=True, provider_message_id=f"payamak-dev-{uuid4()}", raw_response={"mode": "dev_simulated"}, latency_ms=0, ) started = time.perf_counter() try: async with httpx.AsyncClient(timeout=15.0) as client: response = await client.post( credentials.get( "endpoint", "https://api.payamak-panel.com/post/Send.asmx/SendSimpleSMS", ), data={ "username": username, "password": password, "to": request.to_address, "from": from_number or "", "text": request.body, "isflash": "false", }, ) latency = int((time.perf_counter() - started) * 1000) if response.status_code >= 400: return SendResult( success=False, error_code="payamak_http_error", error_message=response.text[:500], latency_ms=latency, raw_response={"status_code": response.status_code}, ) return SendResult( success=True, provider_message_id=response.text.strip()[:200] or f"payamak-{uuid4()}", raw_response={"body": response.text[:500]}, latency_ms=latency, ) except Exception as exc: # noqa: BLE001 — provider boundary latency = int((time.perf_counter() - started) * 1000) return SendResult( success=False, error_code="payamak_exception", error_message=str(exc), latency_ms=latency, ) async def get_balance(self, credentials: dict[str, Any]) -> BalanceResult: raw = credentials.get("cached_balance") if raw is not None: return BalanceResult(balance=float(raw), currency="IRR") return BalanceResult(balance=None, currency="IRR") async def health_check(self, credentials: dict[str, Any]) -> ProviderHealth: if credentials.get("username") or credentials.get("api_key"): return ProviderHealth(healthy=True, detail="credentials present") return ProviderHealth(healthy=True, detail="dev mode without credentials")