from __future__ import annotations

import asyncio

from beaver.interfaces.channels.connections import (
    ChannelConnectionStore,
    CredentialStore,
    TelegramConnector,
)


class FakeTelegramClient:
    async def get_me(self):
        return {"id": 12345, "username": "beaver_bot", "first_name": "Beaver"}


class BrokenTelegramClient:
    async def get_me(self):
        raise RuntimeError("invalid token")


def test_telegram_connector_validates_token_and_updates_connection(tmp_path) -> None:
    async def run() -> None:
        connection_store = ChannelConnectionStore(tmp_path / "connections.json")
        credential_store = CredentialStore(tmp_path / "credentials.json")
        credentials_ref = credential_store.put(kind="telegram", values={"botToken": "token-1"})
        connection = connection_store.create(
            kind="telegram",
            mode="polling",
            display_name="Telegram Main",
            account_id="",
            owner_user_id="user-1",
            auth_type="token",
            credentials_ref=credentials_ref,
            runtime_config={"max_message_chars": 4096},
        )
        connector = TelegramConnector(
            connection_store=connection_store,
            credential_store=credential_store,
            client_factory=lambda token: FakeTelegramClient(),
        )

        result = await connector.validate(connection.connection_id)
        updated = connection_store.get(connection.connection_id)

        assert result.ok is True
        assert result.status == "connected"
        assert result.account_id == "telegram:12345"
        assert updated.account_id == "telegram:12345"
        assert updated.display_name == "Beaver (@beaver_bot)"
        assert updated.capabilities == ["receive_text", "send_text", "receive_media", "groups"]

    asyncio.run(run())


def test_telegram_connector_materializes_runtime_spec(tmp_path) -> None:
    async def run() -> None:
        connection_store = ChannelConnectionStore(tmp_path / "connections.json")
        credential_store = CredentialStore(tmp_path / "credentials.json")
        credentials_ref = credential_store.put(kind="telegram", values={"botToken": "token-1"})
        connection = connection_store.create(
            kind="telegram",
            mode="polling",
            display_name="Telegram Main",
            account_id="telegram:12345",
            owner_user_id=None,
            auth_type="token",
            credentials_ref=credentials_ref,
            runtime_config={"max_message_chars": 4096, "require_mention_in_groups": True},
        )
        connection_store.update_status(connection.connection_id, status="connected", last_error=None)
        connector = TelegramConnector(
            connection_store=connection_store,
            credential_store=credential_store,
            client_factory=lambda token: FakeTelegramClient(),
        )

        spec = await connector.materialize_runtime(connection.connection_id)

        assert spec.channel_id == connection.channel_id
        assert spec.kind == "telegram"
        assert spec.mode == "polling"
        assert spec.account_id == "telegram:12345"
        assert spec.config["max_message_chars"] == 4096
        assert spec.config["require_mention_in_groups"] is True
        assert spec.secrets_ref == credentials_ref

    asyncio.run(run())


def test_telegram_connector_validation_failure_sets_error_status(tmp_path) -> None:
    async def run() -> None:
        connection_store = ChannelConnectionStore(tmp_path / "connections.json")
        credential_store = CredentialStore(tmp_path / "credentials.json")
        credentials_ref = credential_store.put(kind="telegram", values={"botToken": "bad-token"})
        connection = connection_store.create(
            kind="telegram",
            mode="polling",
            display_name="Telegram Main",
            account_id="",
            owner_user_id=None,
            auth_type="token",
            credentials_ref=credentials_ref,
        )
        connector = TelegramConnector(
            connection_store=connection_store,
            credential_store=credential_store,
            client_factory=lambda token: BrokenTelegramClient(),
        )

        result = await connector.validate(connection.connection_id)

        assert result.ok is False
        assert result.status == "error"
        assert "invalid token" in (result.error or "")

    asyncio.run(run())


def test_telegram_connector_revoke_leaves_store_status_to_registry(tmp_path) -> None:
    async def run() -> None:
        connection_store = ChannelConnectionStore(tmp_path / "connections.json")
        credential_store = CredentialStore(tmp_path / "credentials.json")
        connection = connection_store.create(
            kind="telegram",
            mode="polling",
            display_name="Telegram Main",
            account_id="telegram:12345",
            owner_user_id=None,
            auth_type="token",
        )
        connection_store.update_status(connection.connection_id, status="connected", last_error=None)
        connector = TelegramConnector(
            connection_store=connection_store,
            credential_store=credential_store,
            client_factory=lambda token: FakeTelegramClient(),
        )

        await connector.revoke(connection.connection_id)

        assert connection_store.get(connection.connection_id).status == "connected"

    asyncio.run(run())
