import asyncio

from beaver.foundation.events import OutboundMessage
from beaver.interfaces.channels.platforms.feishu import FeishuAdapter


class FakeSink:
    def __init__(self) -> None:
        self.messages = []

    async def accept_inbound(self, message):
        self.messages.append(message)


class FakeFeishuClient:
    def __init__(self) -> None:
        self.sent = []

    async def send_text(self, *, receive_id_type: str, receive_id: str, text: str):
        self.sent.append({"receive_id_type": receive_id_type, "receive_id": receive_id, "text": text})


def test_feishu_normalizes_direct_text_event() -> None:
    async def run() -> None:
        sink = FakeSink()
        adapter = FeishuAdapter(
            channel_id="feishu-main",
            kind="feishu",
            mode="websocket",
            account_id="tenant-main",
            display_name=None,
            inbound_sink=sink,
            secrets={"appId": "app", "appSecret": "secret"},
            config={},
            client=FakeFeishuClient(),
        )

        await adapter.handle_event_payload(
            {
                "event": {
                    "message": {
                        "message_id": "m1",
                        "chat_id": "oc_chat",
                        "chat_type": "p2p",
                        "message_type": "text",
                        "content": "{\"text\":\"hello\"}",
                    },
                    "sender": {"sender_id": {"open_id": "ou_user"}},
                }
            }
        )

        message = sink.messages[0]
        assert message.content == "hello"
        assert message.session_id == "feishu-main:tenant-main:oc_chat"
        assert message.channel_identity.peer_type == "dm"
        assert message.channel_identity.user_id == "ou_user"

    asyncio.run(run())


def test_feishu_group_mention_gate() -> None:
    async def run() -> None:
        sink = FakeSink()
        adapter = FeishuAdapter(
            channel_id="feishu-main",
            kind="feishu",
            mode="websocket",
            account_id="tenant-main",
            display_name=None,
            inbound_sink=sink,
            secrets={"appId": "app", "appSecret": "secret"},
            config={"requireMentionInGroups": True, "botOpenId": "ou_bot"},
            client=FakeFeishuClient(),
        )

        await adapter.handle_event_payload(
            {
                "event": {
                    "message": {
                        "message_id": "m1",
                        "chat_id": "oc_group",
                        "chat_type": "group",
                        "message_type": "text",
                        "content": "{\"text\":\"hello\"}",
                        "mentions": [],
                    },
                    "sender": {"sender_id": {"open_id": "ou_user"}},
                }
            }
        )
        await adapter.handle_event_payload(
            {
                "event": {
                    "message": {
                        "message_id": "m2",
                        "chat_id": "oc_group",
                        "chat_type": "group",
                        "message_type": "text",
                        "content": "{\"text\":\"hello\"}",
                        "mentions": [{"id": {"open_id": "ou_bot"}}],
                    },
                    "sender": {"sender_id": {"open_id": "ou_user"}},
                }
            }
        )

        assert len(sink.messages) == 1

    asyncio.run(run())


def test_feishu_sends_text_to_chat_id() -> None:
    async def run() -> None:
        sink = FakeSink()
        client = FakeFeishuClient()
        adapter = FeishuAdapter(
            channel_id="feishu-main",
            kind="feishu",
            mode="websocket",
            account_id="tenant-main",
            display_name=None,
            inbound_sink=sink,
            secrets={"appId": "app", "appSecret": "secret"},
            config={},
            client=client,
        )
        await adapter.handle_event_payload(
            {
                "event": {
                    "message": {
                        "message_id": "m1",
                        "chat_id": "oc_chat",
                        "chat_type": "p2p",
                        "message_type": "text",
                        "content": "{\"text\":\"hello\"}",
                    },
                    "sender": {"sender_id": {"open_id": "ou_user"}},
                }
            }
        )
        await adapter.send(
            OutboundMessage(
                channel="feishu-main",
                content="ok",
                session_id=sink.messages[0].session_id,
                finish_reason="stop",
                channel_identity=sink.messages[0].channel_identity,
            )
        )

        assert client.sent == [{"receive_id_type": "chat_id", "receive_id": "oc_chat", "text": "ok"}]

    asyncio.run(run())
