"""Facebook Messenger channel implementation using Meta Graph API."""

from __future__ import annotations

import logging
from collections.abc import Callable
from typing import Any

import httpx

from agntspace.channels.base import Channel, ChannelMessage

log = logging.getLogger(__name__)

GRAPH_API = "https://graph.facebook.com/v21.0"


class MessengerChannel(Channel):
    """Facebook Messenger channel using Webhooks + Send API."""

    name = "messenger"

    def __init__(self, page_access_token: str, verify_token: str = "") -> None:
        self._token = page_access_token
        self._verify_token = verify_token
        self._connected = False
        self._message_callback: Callable | None = None
        self._chat_id: str | None = None

    async def connect(self) -> None:
        """Validate the page access token against the Graph API."""
        async with httpx.AsyncClient() as client:
            resp = await client.get(
                f"{GRAPH_API}/me",
                params={"access_token": self._token},
            )
            data = resp.json()
            if data.get("error"):
                raise ConnectionError(
                    f"Messenger page token invalid: {data['error'].get('message', data)}"
                )
            log.info("Messenger connected: page %s (%s)", data.get("name"), data.get("id"))
        self._connected = True

    async def disconnect(self) -> None:
        self._connected = False
        log.info("Messenger disconnected")

    async def send_message(self, chat_id: str, text: str) -> None:
        """Send a text message via the Send API."""
        # Messenger has a 2000-char limit per message bubble
        chunks = [text[i : i + 2000] for i in range(0, len(text), 2000)]
        async with httpx.AsyncClient() as client:
            for chunk in chunks:
                await client.post(
                    f"{GRAPH_API}/me/messages",
                    params={"access_token": self._token},
                    json={
                        "recipient": {"id": chat_id},
                        "message": {"text": chunk},
                    },
                )

    async def send_notification(self, chat_id: str, text: str) -> None:
        await self.send_message(chat_id, f"\U0001f514 {text}")

    @property
    def is_connected(self) -> bool:
        return self._connected

    def verify_webhook(self, mode: str, token: str, challenge: str) -> str | None:
        """Handle the Meta webhook verification GET request.

        Returns the challenge string if verification passes, None otherwise.
        """
        if mode == "subscribe" and token == self._verify_token:
            log.info("Messenger webhook verified")
            return challenge
        log.warning("Messenger webhook verification failed (bad token)")
        return None

    async def handle_webhook(self, payload: dict[str, Any]) -> str | None:
        """Process an incoming Messenger webhook event.

        Meta sends batched entries; we process the first messaging event.
        Returns the agent's response text, or None.
        """
        if payload.get("object") != "page":
            return None

        for entry in payload.get("entry", []):
            for event in entry.get("messaging", []):
                message = event.get("message", {})
                text = message.get("text", "")
                sender_id = event.get("sender", {}).get("id", "")

                if not text or not sender_id:
                    continue

                # Ignore echo messages (sent by us)
                if message.get("is_echo"):
                    continue

                self._chat_id = sender_id

                channel_msg = ChannelMessage(
                    channel="messenger",
                    sender=sender_id,
                    text=text,
                    metadata={"chat_id": sender_id},
                )

                if self._message_callback:
                    response = await self._message_callback(channel_msg)
                    if response:
                        await self.send_message(sender_id, response)
                    return response

        return None
