"""Tests for duty_teller.handlers.errors (error_handler)."""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from duty_teller.handlers.errors import error_handler


@pytest.mark.asyncio
async def test_error_handler_replies_with_generic_message():
    """error_handler: when update has effective_message, reply_text with errors.generic."""

    # Handler checks isinstance(update, Update); patch Update so our mock passes.
    class FakeUpdate:
        pass

    update = FakeUpdate()
    update.effective_message = MagicMock()
    update.effective_message.reply_text = AsyncMock()
    update.effective_user = MagicMock()
    context = MagicMock()
    context.error = Exception("test error")

    with patch("duty_teller.handlers.errors.Update", FakeUpdate):
        with patch("duty_teller.handlers.errors.get_lang", return_value="en"):
            with patch("duty_teller.handlers.errors.t") as mock_t:
                mock_t.return_value = "An error occurred."
                await error_handler(update, context)
    update.effective_message.reply_text.assert_called_once_with("An error occurred.")
    mock_t.assert_called_with("en", "errors.generic")


@pytest.mark.asyncio
async def test_error_handler_no_effective_message_does_not_send():
    """error_handler: when update has no effective_message, does not call reply_text."""
    update = MagicMock()
    update.effective_message = None
    update.effective_user = MagicMock()
    context = MagicMock()
    context.error = Exception("test")

    with patch("duty_teller.handlers.errors.get_lang", return_value="en"):
        with patch("duty_teller.handlers.errors.t") as mock_t:
            await error_handler(update, context)
    mock_t.assert_not_called()


@pytest.mark.asyncio
async def test_error_handler_update_none_does_not_crash():
    """error_handler: when update is None, does not crash (no reply)."""
    context = MagicMock()
    context.error = Exception("test")
    await error_handler(None, context)


@pytest.mark.asyncio
async def test_error_handler_reply_text_raises_does_not_propagate():
    """error_handler: when reply_text raises, exception is caught and logged; does not propagate."""

    class FakeUpdate:
        pass

    update = FakeUpdate()
    update.effective_message = MagicMock()
    update.effective_message.reply_text = AsyncMock(
        side_effect=Exception("reply failed")
    )
    update.effective_user = MagicMock()
    context = MagicMock()
    context.error = Exception("test error")

    with patch("duty_teller.handlers.errors.Update", FakeUpdate):
        with patch("duty_teller.handlers.errors.get_lang", return_value="en"):
            with patch(
                "duty_teller.handlers.errors.t", return_value="An error occurred."
            ):
                await error_handler(update, context)
    # Handler must not raise; reply_text was attempted
    update.effective_message.reply_text.assert_called_once()
