"""Test that agents can handle multiple consecutive edits to the same message."""

from __future__ import annotations

from typing import TYPE_CHECKING
from unittest.mock import AsyncMock, MagicMock, patch

import nio
import pytest

from mindroom.bot import AgentBot
from mindroom.config.agent import AgentConfig
from mindroom.config.main import Config
from mindroom.config.models import ModelConfig, RouterConfig
from mindroom.matrix.users import AgentMatrixUser
from tests.conftest import TEST_PASSWORD

if TYPE_CHECKING:
    from pathlib import Path


@pytest.mark.asyncio
async def test_agent_regenerates_on_multiple_edits(tmp_path: Path) -> None:
    """Test that agents regenerate their response on each consecutive edit."""
    # Set up agent and bot
    agent_user = AgentMatrixUser(
        user_id="@mindroom_test:localhost",
        password=TEST_PASSWORD,
        display_name="TestAgent",
        agent_name="test",
    )

    config = Config(
        agents={"test": AgentConfig(display_name="TestAgent", rooms=["!test:localhost"])},
        teams={},
        room_models={},
        models={"default": ModelConfig(provider="ollama", id="test-model")},
        router=RouterConfig(model="default"),
    )

    bot = AgentBot(
        agent_user=agent_user,
        storage_path=tmp_path,
        rooms=["!test:localhost"],
        enable_streaming=False,
        config=config,
    )

    # Mock the orchestrator and client
    mock_orchestrator = MagicMock()
    mock_orchestrator.current_config = config
    bot.orchestrator = mock_orchestrator

    bot.client = AsyncMock(spec=nio.AsyncClient)
    bot.client.rooms = {}
    bot.client.user_id = "@mindroom_test:localhost"

    # Mock room send to return a response event ID
    mock_send_response = MagicMock()
    mock_send_response.__class__ = nio.RoomSendResponse
    mock_send_response.event_id = "$response123"
    bot.client.room_send.return_value = mock_send_response

    # Mock room messages for thread history
    bot.client.room_messages = AsyncMock(
        return_value=nio.RoomMessagesResponse.from_dict(
            {"chunk": [], "start": "s1", "end": "e1"},
            room_id="!test:localhost",
        ),
    )

    # Set up room
    room = nio.MatrixRoom(room_id="!test:localhost", own_user_id=bot.client.user_id)

    # Original message from user
    original_event = nio.RoomMessageText.from_dict(
        {
            "content": {
                "body": "@mindroom_test What's 2+2?",
                "msgtype": "m.text",
                "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},
            },
            "event_id": "$original123",
            "sender": "@user:localhost",
            "origin_server_ts": 1000000,
            "type": "m.room.message",
            "room_id": "!test:localhost",
        },
    )
    original_event.source = original_event.__dict__["source"]

    # Process original message with mocked AI response
    with patch("mindroom.bot.ai_response", AsyncMock(return_value="Original: 4")):
        await bot._on_message(room, original_event)

    # Verify bot responded
    assert bot.client.room_send.call_count == 2  # thinking + final

    # Reset mock
    bot.client.room_send.reset_mock()

    # First edit from user
    edit1_event = nio.RoomMessageText.from_dict(
        {
            "content": {
                "body": "* @mindroom_test What's 3+3?",
                "msgtype": "m.text",
                "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},  # Mentions at top level
                "m.new_content": {
                    "body": "@mindroom_test What's 3+3?",
                    "msgtype": "m.text",
                    "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},
                },
                "m.relates_to": {
                    "rel_type": "m.replace",
                    "event_id": "$original123",  # Points to original
                },
            },
            "event_id": "$edit1",
            "sender": "@user:localhost",
            "origin_server_ts": 1000001,
            "type": "m.room.message",
            "room_id": "!test:localhost",
        },
    )
    edit1_event.source = edit1_event.__dict__["source"]

    # Process first edit with mocked AI response
    with patch("mindroom.bot.ai_response", AsyncMock(return_value="Edit 1: 6")):
        await bot._on_message(room, edit1_event)

    # Verify bot regenerated (sends thinking message when editing)
    assert bot.client.room_send.call_count >= 1
    print(f"After first edit, room_send called {bot.client.room_send.call_count} times")

    # Reset mock
    bot.client.room_send.reset_mock()

    # Second edit from user
    edit2_event = nio.RoomMessageText.from_dict(
        {
            "content": {
                "body": "* @mindroom_test What's 4+4?",
                "msgtype": "m.text",
                "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},  # Mentions at top level
                "m.new_content": {
                    "body": "@mindroom_test What's 4+4?",
                    "msgtype": "m.text",
                    "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},
                },
                "m.relates_to": {
                    "rel_type": "m.replace",
                    "event_id": "$original123",  # Still points to original!
                },
            },
            "event_id": "$edit2",
            "sender": "@user:localhost",
            "origin_server_ts": 1000002,
            "type": "m.room.message",
            "room_id": "!test:localhost",
        },
    )
    edit2_event.source = edit2_event.__dict__["source"]

    # Process second edit with mocked AI response
    with patch("mindroom.bot.ai_response", AsyncMock(return_value="Edit 2: 8")):
        await bot._on_message(room, edit2_event)

    # Verify bot regenerated again
    assert bot.client.room_send.call_count >= 1, "Bot should regenerate on second edit"
    print(f"After second edit, room_send called {bot.client.room_send.call_count} times")

    # Third edit from user
    edit3_event = nio.RoomMessageText.from_dict(
        {
            "content": {
                "body": "* @mindroom_test What's 5+5?",
                "msgtype": "m.text",
                "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},  # Mentions at top level
                "m.new_content": {
                    "body": "@mindroom_test What's 5+5?",
                    "msgtype": "m.text",
                    "m.mentions": {"user_ids": ["@mindroom_test:localhost"]},
                },
                "m.relates_to": {
                    "rel_type": "m.replace",
                    "event_id": "$original123",  # Always points to original
                },
            },
            "event_id": "$edit3",
            "sender": "@user:localhost",
            "origin_server_ts": 1000003,
            "type": "m.room.message",
            "room_id": "!test:localhost",
        },
    )
    edit3_event.source = edit3_event.__dict__["source"]

    # Reset mock
    bot.client.room_send.reset_mock()

    # Process third edit with mocked AI response
    with patch("mindroom.bot.ai_response", AsyncMock(return_value="Edit 3: 10")):
        await bot._on_message(room, edit3_event)

    # Verify bot regenerated yet again
    assert bot.client.room_send.call_count >= 1, "Bot should regenerate on third edit"
    print(f"After third edit, room_send called {bot.client.room_send.call_count} times")
