from __future__ import annotations

import json

import httpx

from tests.conftest import json_response, make_client

mock_message = {
    "object": "message",
    "id": "msg_123",
    "mailbox_id": "mbx_456",
    "thread_id": "thr_789",
    "subject": "Hello",
    "from_address": "hello@example.com",
    "to_addresses": [{"address": "user@example.com", "name": "User"}],
    "cc_addresses": None,
    "bcc_addresses": None,
    "source": "api",
    "status": "queued",
    "created_at": "2025-01-01T00:00:00Z",
    "updated_at": "2025-01-01T00:00:00Z",
}


class TestSend:
    def test_sends_post_messages_with_html(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            assert request.method == "POST"
            assert request.url.path == "/v1/messages"
            body = json.loads(request.content)
            assert body == {
                "from": "hello@example.com",
                "to": ["user@example.com"],
                "subject": "Hello",
                "html": "<p>Hi there</p>",
            }
            return json_response(mock_message)

        client = make_client(handler)
        message = client.messages.send({
            "from": "hello@example.com",
            "to": ["user@example.com"],
            "subject": "Hello",
            "html": "<p>Hi there</p>",
        })
        assert message["id"] == "msg_123"
        assert message["status"] == "queued"

    def test_sends_with_mailbox_id(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            body = json.loads(request.content)
            assert body["mailbox_id"] == "mbx_456"
            return json_response(mock_message)

        client = make_client(handler)
        client.messages.send({
            "mailbox_id": "mbx_456",
            "to": [{"address": "user@example.com"}],
            "subject": "Test",
            "html": "<p>Hi</p>",
        })

    def test_sends_with_cc_bcc_and_reply_to(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            body = json.loads(request.content)
            assert body["cc"] == [{"address": "cc@example.com"}]
            assert body["bcc"] == [{"address": "bcc@example.com"}]
            assert body["reply_to"] == {"address": "reply@example.com", "name": "Reply"}
            return json_response(mock_message)

        client = make_client(handler)
        client.messages.send({
            "mailbox_id": "mbx_456",
            "to": [{"address": "user@example.com"}],
            "subject": "Test",
            "text": "test",
            "cc": [{"address": "cc@example.com"}],
            "bcc": [{"address": "bcc@example.com"}],
            "reply_to": {"address": "reply@example.com", "name": "Reply"},
        })

    def test_sends_with_text_only(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            body = json.loads(request.content)
            assert body["text"] == "Plain text"
            assert "html" not in body
            return json_response(mock_message)

        client = make_client(handler)
        client.messages.send({
            "mailbox_id": "mbx_456",
            "to": [{"address": "user@example.com"}],
            "subject": "Test",
            "text": "Plain text",
        })

    def test_sends_with_string_recipients(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            body = json.loads(request.content)
            assert body["to"] == ["user@example.com"]
            return json_response(mock_message)

        client = make_client(handler)
        client.messages.send({
            "from": "hello@example.com",
            "to": ["user@example.com"],
            "subject": "Test",
            "text": "Hi",
        })

    def test_sends_with_in_reply_to_and_references(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            body = json.loads(request.content)
            assert body["in_reply_to"] == "<msg-id-1@example.com>"
            assert body["references"] == ["<msg-id-0@example.com>", "<msg-id-1@example.com>"]
            return json_response(mock_message)

        client = make_client(handler)
        client.messages.send({
            "mailbox_id": "mbx_456",
            "to": [{"address": "user@example.com"}],
            "subject": "Re: Test",
            "html": "<p>Reply</p>",
            "in_reply_to": "<msg-id-1@example.com>",
            "references": ["<msg-id-0@example.com>", "<msg-id-1@example.com>"],
        })


class TestList:
    def test_sends_get_messages_with_mailbox_id(self) -> None:
        response = {
            "data": [mock_message],
            "pagination": {"next_cursor": None, "has_more": False, "limit": 25},
        }

        def handler(request: httpx.Request) -> httpx.Response:
            assert request.method == "GET"
            assert request.url.path == "/v1/messages"
            assert str(request.url.params.get("mailbox_id")) == "mbx_456"
            return json_response(response)

        client = make_client(handler)
        result = client.messages.list({"mailbox_id": "mbx_456"})
        assert len(result["data"]) == 1
        assert result["data"][0]["id"] == "msg_123"
        assert result["pagination"]["limit"] == 25


class TestGet:
    def test_sends_get_messages_id(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            assert request.method == "GET"
            assert request.url.path == "/v1/messages/msg_123"
            return json_response(mock_message)

        client = make_client(handler)
        message = client.messages.get("msg_123")
        assert message["id"] == "msg_123"
        assert message["mailbox_id"] == "mbx_456"
        assert message["thread_id"] == "thr_789"
        assert message["source"] == "api"


class TestReply:
    def test_sends_post_messages_id_reply(self) -> None:
        def handler(request: httpx.Request) -> httpx.Response:
            assert request.method == "POST"
            assert request.url.path == "/v1/messages/msg_123/reply"
            body = json.loads(request.content)
            assert body["to"] == ["user@example.com"]
            assert body["text"] == "Reply text"
            return json_response(mock_message)

        client = make_client(handler)
        message = client.messages.reply("msg_123", {
            "to": ["user@example.com"],
            "text": "Reply text",
        })
        assert message["id"] == "msg_123"
