import logging
import sys
import types


if "pymysql" not in sys.modules:
    fake_cursors = types.SimpleNamespace(DictCursor=object)
    
    class _DummyConnection:
        def cursor(self, *args, **kwargs):
            raise Exception("unavailable")

        def close(self):
            return None

    fake_pymysql = types.SimpleNamespace(connect=lambda *args, **kwargs: _DummyConnection(), cursors=fake_cursors)
    sys.modules["pymysql"] = fake_pymysql
    sys.modules["pymysql.cursors"] = fake_cursors

if "aiohttp" not in sys.modules:
    def _passthrough_decorator(*_args, **_kwargs):
        def _inner(func):
            return func

        return _inner

    class _DummyApplication:
        def add_routes(self, *_args, **_kwargs):
            return None

    class _DummyResponse:
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

    def _json_response(*args, **kwargs):
        return {"args": args, "kwargs": kwargs}

    fake_web = types.SimpleNamespace(
        json_response=_json_response,
        Response=_DummyResponse,
        Request=object,
        Application=_DummyApplication,
        RouteTableDef=lambda: types.SimpleNamespace(
            get=_passthrough_decorator,
            post=_passthrough_decorator,
            put=_passthrough_decorator,
            delete=_passthrough_decorator,
        ),
    )
    fake_aiohttp = types.SimpleNamespace(
        ClientSession=object,
        ClientTimeout=object,
        web=fake_web,
    )
    sys.modules["aiohttp"] = fake_aiohttp
    sys.modules["aiohttp.web"] = fake_web

if "websockets" not in sys.modules:
    class _DummyConnectionClosed(Exception):
        def __init__(self, code=0, reason=""):
            super().__init__(reason)
            self.code = code
            self.reason = reason

    class _DummyWebSocketServerProtocol:
        closed = False

        def __init__(self, *args, **kwargs):
            self.ping_handler = None
            self.pong_handler = None

        async def close(self, *_args, **_kwargs):
            self.closed = True

    fake_exceptions = types.SimpleNamespace(
        InvalidMessage=Exception,
        WebSocketException=Exception,
        ConnectionClosed=_DummyConnectionClosed,
    )
    fake_http = types.SimpleNamespace(read_request=lambda *args, **kwargs: None)
    fake_server = types.SimpleNamespace(
        WebSocketServerProtocol=_DummyWebSocketServerProtocol,
        serve=lambda *args, **kwargs: None,
    )
    fake_websockets = types.SimpleNamespace(
        legacy=types.SimpleNamespace(server=fake_server, http=fake_http),
        exceptions=fake_exceptions,
    )
    sys.modules["websockets"] = fake_websockets
    sys.modules["websockets.legacy"] = types.SimpleNamespace(
        server=fake_server,
        http=fake_http,
    )
    sys.modules["websockets.legacy.server"] = fake_server
    sys.modules["websockets.legacy.http"] = fake_http
    sys.modules["websockets.exceptions"] = fake_exceptions

import pipelet_ocpp_server as server


def test_resolve_stale_timeout_expands_for_large_heartbeat(caplog):
    heartbeat_interval = 400
    base_timeout = 30

    with caplog.at_level(logging.WARNING):
        resolved = server.resolve_stale_timeout(heartbeat_interval, base_timeout)

    assert resolved == heartbeat_interval * 2
    assert "Configured stale timeout" in caplog.text


def test_resolve_stale_timeout_prefers_base_when_heartbeat_lower(caplog):
    heartbeat_interval = 10
    base_timeout = 300

    with caplog.at_level(logging.WARNING):
        resolved = server.resolve_stale_timeout(heartbeat_interval, base_timeout)

    assert resolved == base_timeout
    assert "Configured stale timeout" not in caplog.text
