from __future__ import annotations

from typing import Any

import httpx

from .config import Settings


class ChatbotBridgeError(RuntimeError):
    """Error funcional al hablar con el bridge PHP del chatbot."""


class ChatbotBridge:
    def __init__(self, settings: Settings) -> None:
        self.settings = settings

    @property
    def enabled(self) -> bool:
        return bool(self.settings.chatbot_bridge_url and self.settings.chatbot_admin_token)

    async def get_overview(self, limit: int = 8) -> dict[str, Any]:
        return await self._request(
            params={
                "action": "overview",
                "limit": max(1, min(limit, 20)),
            }
        )

    async def list_campaigns(
        self,
        limit: int = 12,
        status: str | None = None,
        source: str | None = None,
    ) -> dict[str, Any]:
        params: dict[str, Any] = {
            "action": "campaigns",
            "limit": max(1, min(limit, 50)),
        }
        if status:
            params["status"] = status
        if source:
            params["source"] = source
        return await self._request(params=params)

    async def get_campaign(self, campaign_id: int, source: str | None = None) -> dict[str, Any]:
        params: dict[str, Any] = {
            "action": "campaign-detail",
            "id": int(campaign_id),
        }
        if source:
            params["source"] = source
        return await self._request(params=params)

    async def list_consents(
        self,
        limit: int = 50,
        status: str | None = None,
        source: str | None = None,
        phone: str | None = None,
        advertiser_id: int | None = None,
    ) -> dict[str, Any]:
        params: dict[str, Any] = {
            "action": "consents",
            "limit": max(1, min(limit, 500)),
        }
        if status:
            params["status"] = status
        if source:
            params["source"] = source
        if phone:
            params["phone"] = phone
        if advertiser_id:
            params["advertiser_id"] = int(advertiser_id)
        return await self._request(params=params)

    async def create_consent(
        self,
        phone: str,
        source: str,
        name: str | None = None,
        proof: str | None = None,
        advertiser_id: int | None = None,
    ) -> dict[str, Any]:
        payload: dict[str, Any] = {
            "phone": phone,
            "source": source,
        }
        if name:
            payload["name"] = name
        if proof:
            payload["proof"] = proof
        if advertiser_id:
            payload["advertiser_id"] = int(advertiser_id)
        return await self._request(params={"action": "consent-create"}, method="POST", payload=payload)

    async def create_campaign(
        self,
        advertiser_id: int,
        name: str,
        message_template: str,
        targets: list[dict[str, Any]],
        description: str | None = None,
        scheduled_at: str | None = None,
        use_ai_personalization: bool = False,
    ) -> dict[str, Any]:
        payload: dict[str, Any] = {
            "advertiser_id": int(advertiser_id),
            "name": name,
            "message_template": message_template,
            "targets": targets,
            "use_ai_personalization": use_ai_personalization,
        }
        if description:
            payload["description"] = description
        if scheduled_at:
            payload["scheduled_at"] = scheduled_at
        return await self._request(params={"action": "campaign-create"}, method="POST", payload=payload)

    async def send_campaign(self, campaign_id: int, immediate: bool = True) -> dict[str, Any]:
        return await self._request(
            params={"action": "campaign-send"},
            method="POST",
            payload={
                "id": int(campaign_id),
                "immediate": bool(immediate),
            },
        )

    async def _request(self, params: dict[str, Any], method: str = "GET", payload: dict[str, Any] | None = None) -> dict[str, Any]:
        if not self.enabled:
            raise ChatbotBridgeError("El bridge del chatbot no está configurado en el supervisor")

        headers = {
            "X-Admin-Token": self.settings.chatbot_admin_token,
            "Accept": "application/json",
            "Accept-Language": "es-ES,es;q=0.9,en;q=0.8",
            "Cache-Control": "no-cache",
            "Pragma": "no-cache",
            "Referer": self.settings.public_base_url,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 XZonasSupervisor/0.1",
            "X-Requested-With": "XMLHttpRequest",
        }
        timeout = max(5.0, float(self.settings.chatbot_timeout_seconds))
        http_method = method.upper().strip() or "GET"

        try:
            async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
                response = await client.request(
                    http_method,
                    self.settings.chatbot_bridge_url,
                    params=params,
                    json=payload if http_method != "GET" else None,
                    headers=headers,
                )
        except httpx.HTTPError as exc:
            raise ChatbotBridgeError(f"No he podido conectar con el bridge del chatbot: {exc}") from exc

        try:
            response_payload = response.json()
        except ValueError as exc:
            raise ChatbotBridgeError("El bridge del chatbot ha devuelto una respuesta no JSON") from exc

        if response.is_error:
            if isinstance(response_payload, dict):
                detail = str(response_payload.get("error") or response_payload.get("detail") or f"HTTP {response.status_code}")
            else:
                detail = response.text.strip() or f"HTTP {response.status_code}"
            raise ChatbotBridgeError(f"Bridge del chatbot devolvió error: {detail}")

        if not isinstance(response_payload, dict):
            raise ChatbotBridgeError("El bridge del chatbot ha devuelto un formato inesperado")

        if not response_payload.get("success"):
            raise ChatbotBridgeError(str(response_payload.get("error") or "El bridge del chatbot ha fallado"))

        data = response_payload.get("data")
        if not isinstance(data, dict):
            raise ChatbotBridgeError("El bridge del chatbot ha devuelto un formato inesperado")

        return data
