import httpx

from ..config import settings
from .base import BaseAdapter, SendError


class EvolutionAdapter(BaseAdapter):
    name = "evolution"

    def __init__(self):
        self.base = settings.evolution_url
        self.instance = settings.instance_name
        self.http = httpx.Client(timeout=30, headers={"apikey": settings.evolution_api_key})

    # ---------- setup helpers (used by /admin pages) ----------
    def create_instance(self) -> dict:
        r = self.http.post(f"{self.base}/instance/create", json={
            "instanceName": self.instance, "integration": "WHATSAPP-BAILEYS", "qrcode": True,
            "rejectCall": True, "groupsIgnore": True, "alwaysOnline": False,
            "readMessages": False, "readStatus": False, "syncFullHistory": False,
        })
        return {"status": r.status_code, "body": _json(r)}

    def set_webhook(self, url: str) -> dict:
        r = self.http.post(f"{self.base}/webhook/set/{self.instance}", json={"webhook": {
            "enabled": True, "url": url, "byEvents": False, "base64": False,
            "events": ["MESSAGES_UPSERT", "MESSAGES_UPDATE", "CONNECTION_UPDATE"],
        }})
        return {"status": r.status_code, "body": _json(r)}

    def connect(self) -> dict:
        r = self.http.get(f"{self.base}/instance/connect/{self.instance}")
        return _json(r) if r.status_code < 300 else {"error": r.text, "status": r.status_code}

    def logout(self) -> dict:
        r = self.http.delete(f"{self.base}/instance/logout/{self.instance}")
        return {"status": r.status_code, "body": _json(r)}

    # ---------- adapter interface ----------
    def connection_state(self) -> str:
        try:
            r = self.http.get(f"{self.base}/instance/connectionState/{self.instance}")
        except httpx.HTTPError as exc:
            return f"unreachable: {exc.__class__.__name__}"
        if r.status_code == 404:
            return "no_instance"
        if r.status_code >= 300:
            return f"error_{r.status_code}"
        data = _json(r)
        return (data.get("instance") or {}).get("state") or data.get("state") or "unknown"

    def number_exists(self, phone: str):
        try:
            r = self.http.post(f"{self.base}/chat/whatsappNumbers/{self.instance}", json={"numbers": [phone]})
            data = _json(r)
            if r.status_code < 300 and isinstance(data, list) and data:
                return bool(data[0].get("exists"))
        except httpx.HTTPError:
            pass
        return None

    def send(self, msg) -> str | None:
        payload = {"number": msg.to_phone, "text": msg.body, "linkPreview": False}
        if settings.typing_delay_ms > 0:
            payload["delay"] = settings.typing_delay_ms
        try:
            r = self.http.post(f"{self.base}/message/sendText/{self.instance}", json=payload)
        except httpx.HTTPError as exc:
            raise SendError(f"evolution unreachable: {exc}") from exc
        data = _json(r)
        if r.status_code >= 300:
            text = str(data)[:500]
            not_on_wa = r.status_code == 400 and "exists" in text and "false" in text.lower()
            raise SendError(f"HTTP {r.status_code}: {text}", retryable=not not_on_wa)
        return ((data.get("key") or {}).get("id")) if isinstance(data, dict) else None


def _json(r: httpx.Response):
    try:
        return r.json()
    except ValueError:
        return {"raw": r.text[:500]}
