"""Cold-boot pending-queue knob for the Telegram adapter.

Contract: a cold boot drops Telegram's server-side pending updates unless
``extra.drop_pending_on_cold_boot`` is false; a watcher reconnect always
preserves them. Conflict recovery is a separate path and is not covered here.
"""

import logging
from types import SimpleNamespace
from unittest.mock import AsyncMock

import pytest

from gateway.config import PlatformConfig
from plugins.platforms.telegram.adapter import TelegramAdapter


def _make_adapter(extra=None) -> TelegramAdapter:
    return TelegramAdapter(PlatformConfig(enabled=True, token="test-token", extra=extra or {}))


async def _capture_drop_pending(adapter: TelegramAdapter, *, is_reconnect: bool):
    """Run _start_polling_mode with staging mocked; return the forwarded flag."""
    captured = {}
    adapter._delete_webhook_best_effort = AsyncMock()

    async def _fake_resilient(*, drop_pending_updates, error_callback, require_progress=False):
        captured["drop_pending_updates"] = drop_pending_updates
        captured["require_progress"] = require_progress
        return True

    adapter._start_polling_resilient = _fake_resilient
    await adapter._start_polling_mode(is_reconnect=is_reconnect)
    return captured


@pytest.mark.asyncio
async def test_cold_boot_drops_queue_by_default():
    """Default config: cold boot drops, reconnect preserves."""
    adapter = _make_adapter()
    assert adapter._drop_pending_on_cold_boot is True

    cold = await _capture_drop_pending(adapter, is_reconnect=False)
    assert cold["drop_pending_updates"] is True

    warm = await _capture_drop_pending(adapter, is_reconnect=True)
    assert warm["drop_pending_updates"] is False


@pytest.mark.asyncio
async def test_cold_boot_preserves_queue_when_opted_out():
    """extra.drop_pending_on_cold_boot=false: cold boot preserves the backlog."""
    adapter = _make_adapter(extra={"drop_pending_on_cold_boot": False})
    assert adapter._drop_pending_on_cold_boot is False

    cold = await _capture_drop_pending(adapter, is_reconnect=False)
    assert cold["drop_pending_updates"] is False

    warm = await _capture_drop_pending(adapter, is_reconnect=True)
    assert warm["drop_pending_updates"] is False


async def _capture_webhook_drop_pending(
    adapter: TelegramAdapter, monkeypatch, *, is_reconnect: bool
):
    """Run _start_webhook_mode against a stub updater; return the forwarded flag."""
    captured = {}

    async def _fake_start_webhook(**kwargs):
        captured.update(kwargs)

    adapter._app = SimpleNamespace(
        updater=SimpleNamespace(start_webhook=AsyncMock(side_effect=_fake_start_webhook))
    )
    monkeypatch.setenv("TELEGRAM_WEBHOOK_URL", "https://example.test/telegram")
    monkeypatch.setenv("TELEGRAM_WEBHOOK_SECRET", "test-secret")
    await adapter._start_webhook_mode(
        "https://example.test/telegram", is_reconnect=is_reconnect
    )
    return captured


@pytest.mark.asyncio
async def test_webhook_cold_boot_honors_the_knob_and_logs_the_decision(monkeypatch, caplog):
    """The webhook start path forwards the same policy as polling, and says which one
    it applied. The flag is not a no-op there: PTB feeds it to delete_webhook /
    set_webhook, which drop Telegram's stored updates."""
    adapter = _make_adapter(extra={"drop_pending_on_cold_boot": False})

    with caplog.at_level(logging.INFO, logger="plugins.platforms.telegram.adapter"):
        captured = await _capture_webhook_drop_pending(
            adapter, monkeypatch, is_reconnect=False
        )

    assert captured["drop_pending_updates"] is False


@pytest.mark.asyncio
async def test_webhook_reconnect_preserves_queue_regardless_of_the_knob(monkeypatch):
    """A watcher reconnect keeps #46621's guarantee even when the knob asks cold
    boots to drop."""
    adapter = _make_adapter()

    captured = await _capture_webhook_drop_pending(adapter, monkeypatch, is_reconnect=True)

    assert captured["drop_pending_updates"] is False
