from __future__ import annotations

import importlib
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch

import pytest


@pytest.fixture(autouse=True)
def fresh_db(tmp_path, monkeypatch):
    monkeypatch.setenv("DB_PATH", str(tmp_path / "test.db"))
    import adapter.telegram.db as db_mod
    importlib.reload(db_mod)
    db_mod.init_db()
    return db_mod


def make_message(*, user_id=1, thread_id=42, chat_id=100):
    m = SimpleNamespace()
    m.from_user = SimpleNamespace(id=user_id, full_name="Alice")
    m.message_thread_id = thread_id
    m.chat = SimpleNamespace(id=chat_id)
    m.text = "Hello"
    m.photo = None
    m.document = None
    m.voice = None
    m.video = None
    m.sticker = None
    m.answer = AsyncMock()
    placeholder = MagicMock()
    placeholder.edit_text = AsyncMock()
    m.reply = AsyncMock(return_value=placeholder)
    m.bot = MagicMock()
    return m, placeholder


def make_dispatcher(chunks=None, raise_exc=None):
    """Build a mock EventDispatcher with configurable stream_message behaviour."""
    async def _stream(*args, **kwargs):
        if raise_exc is not None:
            raise raise_exc
        for chunk in (chunks or []):
            yield chunk

    platform = MagicMock()
    platform.get_or_create_user = AsyncMock(
        return_value=SimpleNamespace(user_id="uid-1")
    )
    platform.stream_message = _stream

    dispatcher = MagicMock()
    dispatcher._platform = platform
    return dispatcher


async def test_stream_exception_shows_error(fresh_db):
    """When stream_message raises, the placeholder is updated with an error message."""
    fresh_db.create_chat(1, 42, "Чат #1")
    import adapter.telegram.handlers.message as mod
    importlib.reload(mod)

    msg, placeholder = make_message()
    dispatcher = make_dispatcher(raise_exc=RuntimeError("boom"))

    await mod.handle_topic_message(msg, dispatcher)

    placeholder.edit_text.assert_called()
    last_call_text = placeholder.edit_text.call_args[0][0]
    assert "недоступен" in last_call_text or "ошибка" in last_call_text.lower()


async def test_stream_success_edits_placeholder(fresh_db):
    """When stream_message succeeds, the placeholder is updated with the response."""
    fresh_db.create_chat(1, 42, "Чат #1")
    import adapter.telegram.handlers.message as mod
    importlib.reload(mod)

    chunks = [SimpleNamespace(delta="Hello "), SimpleNamespace(delta="world")]
    msg, placeholder = make_message()
    dispatcher = make_dispatcher(chunks=chunks)

    await mod.handle_topic_message(msg, dispatcher)

    placeholder.edit_text.assert_called()
    last_call_text = placeholder.edit_text.call_args[0][0]
    assert "Hello world" in last_call_text
