"""Telegram channel connector."""

from __future__ import annotations

from collections.abc import Callable
from typing import Any

from .models import ChannelRuntimeSpec, ValidationResult
from .store import ChannelConnectionStore, CredentialStore


class TelegramConnector:
    kind = "telegram"

    def __init__(
        self,
        *,
        connection_store: ChannelConnectionStore,
        credential_store: CredentialStore,
        client_factory: Callable[[str], Any] | None = None,
    ) -> None:
        self.connection_store = connection_store
        self.credential_store = credential_store
        self.client_factory = client_factory or _default_client_factory

    async def validate(self, connection_id: str) -> ValidationResult:
        connection = self.connection_store.get(connection_id)
        token = self._bot_token(connection.credentials_ref)
        try:
            client = self.client_factory(token)
            raw = await client.get_me()
            bot_id = _value(raw, "id")
            username = _value(raw, "username")
            first_name = _value(raw, "first_name") or "Telegram Bot"
            account_id = f"telegram:{bot_id}" if bot_id else connection.account_id
            display_name = f"{first_name} (@{username})" if username else first_name
            connection.account_id = account_id
            connection.display_name = display_name
            connection.capabilities = ["receive_text", "send_text", "receive_media", "groups"]
            self.connection_store.update(connection)
            return ValidationResult(
                ok=True,
                status="connected",
                account_id=account_id,
                display_name=display_name,
                metadata={"username": username} if username else {},
            )
        except Exception as exc:
            return ValidationResult(ok=False, status="error", error=str(exc))

    async def materialize_runtime(self, connection_id: str) -> ChannelRuntimeSpec:
        connection = self.connection_store.get(connection_id)
        if connection.status not in {"connected", "running"}:
            raise ValueError(f"Connection is not connected: {connection.connection_id}")
        return ChannelRuntimeSpec(
            channel_id=connection.channel_id,
            kind=connection.kind,
            mode=connection.mode,
            account_id=connection.account_id,
            display_name=connection.display_name,
            config=dict(connection.runtime_config),
            secrets_ref=connection.credentials_ref,
        )

    async def revoke(self, connection_id: str) -> None:
        # Telegram bot tokens do not have a Beaver-managed platform revoke action.
        # The registry owns local connection state transitions.
        return None

    def _bot_token(self, credentials_ref: str | None) -> str:
        if not credentials_ref:
            raise ValueError("Telegram credentials are missing")
        token = self.credential_store.get(credentials_ref).get("botToken")
        if not token:
            raise ValueError("botToken is required")
        return token


def _value(raw: Any, key: str) -> str:
    if isinstance(raw, dict):
        value = raw.get(key)
    else:
        value = getattr(raw, key, None)
    return str(value).strip() if value is not None else ""


def _default_client_factory(token: str) -> Any:
    try:
        from telegram import Bot
    except ImportError as exc:  # pragma: no cover - optional live dependency
        raise RuntimeError("Install beaver-backend[telegram] to validate Telegram connections") from exc
    return Bot(token=token)
