from __future__ import annotations

from types import SimpleNamespace

import adapter.matrix.converter as converter
from adapter.matrix.converter import from_command, from_room_event
from core.protocol import IncomingCallback, IncomingCommand, IncomingMessage


def text_event(body: str, sender: str = "@a:m.org", event_id: str = "$e1"):
    return SimpleNamespace(
        sender=sender, body=body, event_id=event_id, msgtype="m.text", replyto_event_id=None
    )


def file_event(url: str = "mxc://x/y", filename: str = "doc.pdf", mime: str = "application/pdf"):
    return SimpleNamespace(
        sender="@a:m.org",
        body=filename,
        event_id="$e2",
        msgtype="m.file",
        replyto_event_id=None,
        url=url,
        mimetype=mime,
    )


def image_event(url: str = "mxc://x/img", mime: str = "image/jpeg"):
    return SimpleNamespace(
        sender="@a:m.org",
        body="img.jpg",
        event_id="$e3",
        msgtype="m.image",
        replyto_event_id=None,
        url=url,
        mimetype=mime,
    )


def content_file_event():
    return SimpleNamespace(
        sender="@a:m.org",
        body="doc.pdf",
        event_id="$e4",
        msgtype=None,
        replyto_event_id=None,
        content={
            "msgtype": "m.file",
            "body": "nested.pdf",
            "url": "mxc://x/nested",
            "info": {"mimetype": "application/pdf"},
        },
    )


def source_only_content_file_event():
    return SimpleNamespace(
        sender="@a:m.org",
        body="doc.pdf",
        event_id="$e5",
        msgtype=None,
        replyto_event_id=None,
        source={
            "content": {
                "msgtype": "m.file",
                "body": "source-only.pdf",
                "url": "mxc://x/source-only",
                "info": {"mimetype": "application/pdf"},
            }
        },
    )


def test_plain_text_to_incoming_message():
    result = from_room_event(text_event("Hello"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingMessage)
    assert result.text == "Hello"
    assert result.platform == "matrix"
    assert result.chat_id == "C1"
    assert result.attachments == []


def test_bang_command_to_incoming_command():
    result = from_room_event(text_event("!new Analysis"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "new"
    assert result.args == ["Analysis"]


def test_list_command_maps_to_matrix_list_attachments():
    result = from_room_event(text_event("!list"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "matrix_list_attachments"
    assert result.args == []


def test_remove_all_maps_to_matrix_remove_attachment():
    result = from_room_event(text_event("!remove all"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "matrix_remove_attachment"
    assert result.args == ["all"]


def test_remove_index_maps_to_matrix_remove_attachment():
    result = from_room_event(text_event("!remove 2"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "matrix_remove_attachment"
    assert result.args == ["2"]


def test_remove_arbitrary_index_maps_to_matrix_remove_attachment():
    result = from_room_event(text_event("!remove 99"), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "matrix_remove_attachment"
    assert result.args == ["99"]


def test_skills_alias_to_settings_command():
    result = from_command("!skills", sender="@a:m.org", chat_id="C1")
    assert isinstance(result, IncomingCommand)
    assert result.command == "settings_skills"


def test_yes_to_callback():
    result = from_room_event(text_event("!yes"), room_id="!room:example.org", chat_id="C7")
    assert isinstance(result, IncomingCallback)
    assert result.action == "confirm"
    assert result.chat_id == "C7"
    assert result.payload["room_id"] == "!room:example.org"


def test_no_to_callback():
    result = from_room_event(text_event("!no"), room_id="!room:example.org", chat_id="C7")
    assert isinstance(result, IncomingCallback)
    assert result.action == "cancel"
    assert result.chat_id == "C7"
    assert result.payload["room_id"] == "!room:example.org"


def test_file_attachment():
    result = from_room_event(file_event(), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingMessage)
    assert len(result.attachments) == 1
    a = result.attachments[0]
    assert a.type == "document"
    assert a.url == "mxc://x/y"
    assert a.filename == "doc.pdf"
    assert a.mime_type == "application/pdf"


def test_image_attachment():
    result = from_room_event(image_event(), room_id="!r:m.org", chat_id="C1")
    assert result.attachments[0].type == "image"
    assert result.attachments[0].filename == "img.jpg"
    assert result.attachments[0].mime_type == "image/jpeg"


def test_attachment_falls_back_to_content_payload():
    result = from_room_event(content_file_event(), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingMessage)
    a = result.attachments[0]
    assert a.type == "document"
    assert a.url == "mxc://x/nested"
    assert a.filename == "nested.pdf"
    assert a.mime_type == "application/pdf"


def test_attachment_falls_back_to_source_content_payload():
    result = from_room_event(source_only_content_file_event(), room_id="!r:m.org", chat_id="C1")
    assert isinstance(result, IncomingMessage)
    a = result.attachments[0]
    assert a.type == "document"
    assert a.url == "mxc://x/source-only"
    assert a.filename == "source-only.pdf"
    assert a.mime_type == "application/pdf"


def test_converter_module_does_not_expose_reaction_callbacks():
    assert not hasattr(converter, "from_reaction")
