"""
Verify that every gateway platform — built-in and plugin — has a connection
checker so ``GatewayConfig.get_connected_platforms()`` doesn't silently drop
platforms with bespoke auth requirements.
"""

from unittest.mock import MagicMock

import pytest

from gateway.config import Platform, _PLATFORM_CONNECTED_CHECKERS, _BUILTIN_PLATFORM_VALUES


def test_all_builtins_have_checker_or_generic_token_path():
    """Every built-in Platform member must be reachable by either:

    1. The generic ``config.token or config.api_key`` check, OR
    2. A platform-specific entry in ``_PLATFORM_CONNECTED_CHECKERS``.

    This guarantees ``get_connected_platforms()`` doesn't silently ignore
    a built-in just because nobody added it to the checker dict.
    """
    # Platforms covered by the generic token/api_key branch
    generic_token_values = {p.value for p in {
        Platform.TELEGRAM,
        Platform.DISCORD,
        Platform.SLACK,
        Platform.MATRIX,
        Platform.MATTERMOST,
        Platform.HOMEASSISTANT,
    }}

    # Platforms with a bespoke checker
    checker_values = {p.value for p in set(_PLATFORM_CONNECTED_CHECKERS.keys())}

    # Every built-in should be in one of the two sets
    all_builtins = set(_BUILTIN_PLATFORM_VALUES)
    missing = all_builtins - generic_token_values - checker_values - {"local"}

    assert not missing, (
        f"Built-in platforms missing a connection checker: "
        f"{sorted(missing)}.  "
        f"Add them to _PLATFORM_CONNECTED_CHECKERS or generic_token_platforms."
    )


@pytest.mark.parametrize("platform, checker", list(_PLATFORM_CONNECTED_CHECKERS.items()))
def test_checker_handles_minimal_config(platform, checker):
    """Each bespoke checker must not crash on a minimal PlatformConfig."""
    mock_config = MagicMock()
    mock_config.extra = {}
    mock_config.token = None
    mock_config.api_key = None
    mock_config.enabled = True

    # Should return a bool without raising
    result = checker(mock_config)
    assert isinstance(result, bool)


@pytest.mark.parametrize("platform, checker", list(_PLATFORM_CONNECTED_CHECKERS.items()))
def test_checker_returns_true_when_configured(platform, checker, monkeypatch):
    """Each bespoke checker must return True when the config looks valid."""
    mock_config = MagicMock()
    mock_config.token = None
    mock_config.api_key = None
    mock_config.enabled = True

    # Set up platform-specific mock extra fields so the checker succeeds
    if platform == Platform.WEIXIN:
        mock_config.extra = {"account_id": "123", "token": "***"}
    elif platform == Platform.SIGNAL:
        mock_config.extra = {"http_url": "http://signal:8080"}
    elif platform == Platform.EMAIL:
        mock_config.extra = {"address": "hermes@example.com"}
    elif platform == Platform.SMS:
        monkeypatch.setenv("TWILIO_ACCOUNT_SID", "ACtest")
        mock_config.extra = {}
    elif platform in (
        Platform.API_SERVER,
        Platform.WEBHOOK,
        Platform.MSGRAPH_WEBHOOK,
        Platform.WHATSAPP,
    ):
        mock_config.extra = {}
    elif platform == Platform.FEISHU:
        mock_config.extra = {"app_id": "app"}
    elif platform == Platform.WECOM:
        mock_config.extra = {"bot_id": "bot"}
    elif platform == Platform.WECOM_CALLBACK:
        mock_config.extra = {"corp_id": "corp"}
    elif platform == Platform.BLUEBUBBLES:
        mock_config.extra = {"server_url": "http://bb:1234", "password": "pw"}
    elif platform == Platform.QQBOT:
        mock_config.extra = {"app_id": "app", "client_secret": "sec"}
    elif platform == Platform.YUANBAO:
        mock_config.extra = {"app_id": "app", "app_secret": "sec"}
    elif platform == Platform.DINGTALK:
        mock_config.extra = {"client_id": "id", "client_secret": "sec"}
    else:
        pytest.skip(f"No synthetic config defined for {platform.value}")

    result = checker(mock_config)
    assert result is True, f"{platform.value} checker should return True with valid-looking config"
