from __future__ import annotations from types import SimpleNamespace from unittest.mock import AsyncMock from adapter.matrix.bot import send_outgoing from adapter.matrix.converter import from_room_event from adapter.matrix.handlers.confirm import make_handle_cancel, make_handle_confirm from adapter.matrix.store import get_pending_confirm, set_room_meta from core.auth import AuthManager from core.chat import ChatManager from core.protocol import OutgoingUI, UIButton from core.settings import SettingsManager from core.store import InMemoryStore from sdk.mock import MockPlatformClient async def test_mat06_outgoing_ui_renders_text_with_yes_no(): client = SimpleNamespace(room_send=AsyncMock()) store = InMemoryStore() await set_room_meta(store, "!confirm:example.org", {"matrix_user_id": "@alice:example.org"}) event = OutgoingUI( chat_id="C7", text="Удалить файл?", buttons=[UIButton(label="Подтвердить", action="confirm")], ) await send_outgoing(client, "!confirm:example.org", event, store=store) client.room_send.assert_awaited_once() body = client.room_send.call_args.args[2]["body"] assert "Удалить файл?" in body assert "!yes" in body assert "!no" in body assert "Подтвердить" in body async def test_mat07_outgoing_ui_no_reaction_sent(): client = SimpleNamespace(room_send=AsyncMock()) store = InMemoryStore() await set_room_meta(store, "!confirm:example.org", {"matrix_user_id": "@alice:example.org"}) event = OutgoingUI( chat_id="C7", text="Confirm action?", buttons=[UIButton(label="OK", action="confirm", payload={"id": 1})], ) await send_outgoing(client, "!confirm:example.org", event, store=store) assert client.room_send.await_count == 1 assert client.room_send.call_args.args[1] == "m.room.message" for call in client.room_send.call_args_list: assert call.args[1] != "m.reaction" pending = await get_pending_confirm(store, "@alice:example.org", "!confirm:example.org") assert pending == { "action_id": "confirm", "description": "Confirm action?", "payload": {"id": 1}, } async def test_outgoing_ui_yes_round_trip_uses_user_and_room_scope(): client = SimpleNamespace(room_send=AsyncMock()) store = InMemoryStore() platform = MockPlatformClient() chat_mgr = ChatManager(platform, store) auth_mgr = AuthManager(platform, store) settings_mgr = SettingsManager(platform, store) await set_room_meta(store, "!confirm:example.org", {"matrix_user_id": "@alice:example.org"}) await set_room_meta(store, "!other:example.org", {"matrix_user_id": "@bob:example.org"}) await send_outgoing( client, "!confirm:example.org", OutgoingUI( chat_id="C7", text="Archive room", buttons=[UIButton(label="Confirm", action="archive", payload={"id": 7})], ), store=store, ) await send_outgoing( client, "!other:example.org", OutgoingUI( chat_id="C8", text="Keep other room", buttons=[UIButton(label="Confirm", action="archive", payload={"id": 8})], ), store=store, ) callback = from_room_event( SimpleNamespace( sender="@alice:example.org", body="!yes", event_id="$yes", msgtype="m.text", replyto_event_id=None, ), room_id="!confirm:example.org", chat_id="C7", ) result = await make_handle_confirm(store)(callback, auth_mgr, platform, chat_mgr, settings_mgr) assert "Archive room" in result[0].text assert await get_pending_confirm(store, "@alice:example.org", "!confirm:example.org") is None assert await get_pending_confirm(store, "@bob:example.org", "!other:example.org") is not None async def test_outgoing_ui_no_round_trip_uses_user_and_room_scope(): client = SimpleNamespace(room_send=AsyncMock()) store = InMemoryStore() platform = MockPlatformClient() chat_mgr = ChatManager(platform, store) auth_mgr = AuthManager(platform, store) settings_mgr = SettingsManager(platform, store) await set_room_meta(store, "!confirm:example.org", {"matrix_user_id": "@alice:example.org"}) await set_room_meta(store, "!other:example.org", {"matrix_user_id": "@bob:example.org"}) await send_outgoing( client, "!confirm:example.org", OutgoingUI( chat_id="C7", text="Delete room", buttons=[UIButton(label="Confirm", action="delete", payload={"id": 7})], ), store=store, ) await send_outgoing( client, "!other:example.org", OutgoingUI( chat_id="C8", text="Keep other room", buttons=[UIButton(label="Confirm", action="archive", payload={"id": 8})], ), store=store, ) callback = from_room_event( SimpleNamespace( sender="@alice:example.org", body="!no", event_id="$no", msgtype="m.text", replyto_event_id=None, ), room_id="!confirm:example.org", chat_id="C7", ) result = await make_handle_cancel(store)(callback, auth_mgr, platform, chat_mgr, settings_mgr) assert "отменено" in result[0].text.lower() assert await get_pending_confirm(store, "@alice:example.org", "!confirm:example.org") is None assert await get_pending_confirm(store, "@bob:example.org", "!other:example.org") is not None