from unittest.mock import AsyncMock, patch

from asgiref.sync import async_to_sync
from django.test import SimpleTestCase, TestCase, override_settings

from core.clients import transport
from core.clients.xmpp import XMPPComponent, _resolve_person_from_xmpp_localpart
from core.models import Person, PersonIdentifier, User


class SignalAttachmentFetchTests(SimpleTestCase):
    def test_signal_service_allows_direct_url_fetch(self):
        response = AsyncMock()
        response.status = 200
        response.headers = {"Content-Type": "image/png"}
        response.read = AsyncMock(return_value=b"png-bytes")

        request_ctx = AsyncMock()
        request_ctx.__aenter__.return_value = response
        request_ctx.__aexit__.return_value = False

        session = AsyncMock()
        session.get.return_value = request_ctx

        session_ctx = AsyncMock()
        session_ctx.__aenter__.return_value = session
        session_ctx.__aexit__.return_value = False

        with patch(
            "core.clients.transport.aiohttp.ClientSession",
            return_value=session_ctx,
        ):
            fetched = async_to_sync(transport.fetch_attachment)(
                "signal",
                {
                    "url": "https://example.com/file_share/demo.png",
                    "filename": "demo.png",
                    "content_type": "image/png",
                },
            )

        self.assertEqual(b"png-bytes", fetched["content"])
        self.assertEqual("image/png", fetched["content_type"])
        self.assertEqual("demo.png", fetched["filename"])
        self.assertEqual(9, fetched["size"])


@override_settings(
    XMPP_JID="component.example.test",
    XMPP_USER_DOMAIN="example.test",
)
class XMPPContactJidTests(TestCase):
    def _component(self):
        return XMPPComponent(
            ur=AsyncMock(),
            jid="component.example.test",
            secret="secret",
            server="localhost",
            port=5347,
        )

    def test_resolve_person_from_escaped_localpart(self):
        user = User.objects.create_user(username="user", password="pw")
        person = Person.objects.create(user=user, name="Misinformation Club")

        resolved = _resolve_person_from_xmpp_localpart(
            user=user,
            localpart_value=r"misinformation\20club",
        )

        self.assertEqual(person.id, resolved.id)

    def test_send_from_external_escapes_contact_jid(self):
        user = User.objects.create_user(username="user2", password="pw")
        person = Person.objects.create(user=user, name="Misinformation Club")
        identifier = PersonIdentifier.objects.create(
            user=user,
            person=person,
            service="signal",
            identifier="group.example",
        )
        component = self._component()
        component.send_xmpp_message = AsyncMock(return_value="xmpp-id")

        with (
            patch("core.clients.xmpp.transport.record_bridge_mapping"),
            patch("core.clients.xmpp.history.save_bridge_ref", new=AsyncMock()),
        ):
            async_to_sync(component.send_from_external)(
                user,
                identifier,
                "hello",
                False,
                attachments=[],
                source_ref={},
            )

        component.send_xmpp_message.assert_awaited_once_with(
            "user2@example.test",
            r"misinformation\20club|signal@component.example.test",
            "hello",
            use_omemo_encryption=True,
        )
