from threading import Thread

import pytest
from assertpy import assert_that

import msgbus
from msgbus import (
    MBContext,
    MBService,
    MBTimeout,
    TCP_MSG_TRAILER_OW,
    TK_SYS_ACK,
)

_SERVER_IP = "127.0.0.1"
_SERVER_PORT = 14592
_SENDER_PORT = 14593


def test_reply_to_one_way_message_is_silently_ignored():
    server = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        name="server",
    )
    sender = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SENDER_PORT),
        name="sender",
    )

    def server_thread():
        msg = server.MB_GetMessage()
        assert_that(msg.trailer).is_equal_to(TCP_MSG_TRAILER_OW)
        server.MB_ReplyMessage(message=msg, data=b"ignored")

    t = Thread(target=server_thread)
    t.start()

    sender.MB_SendOneWayMessage(
        destination=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        token=msgbus.TK_CMP_GETSERVICES,
        data=b"one-way data",
    )

    t.join()
    server.MB_Finalize()
    sender.MB_Finalize()


def test_double_reply_is_silently_ignored():
    server = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        name="server",
    )
    sender = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SENDER_PORT),
        name="sender",
    )

    def server_thread():
        msg = server.MB_GetMessage()
        msg.token = TK_SYS_ACK
        server.MB_ReplyMessage(message=msg, data=b"first reply")
        server.MB_ReplyMessage(message=msg, data=b"second reply (silently ignored)")

    t = Thread(target=server_thread)
    t.start()

    reply = sender.MB_SendMessage(
        destination=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        token=msgbus.TK_CMP_GETSERVICES,
    )
    assert_that(reply.token).is_equal_to(TK_SYS_ACK)

    t.join()
    server.MB_Finalize()
    sender.MB_Finalize()


def test_get_message_with_filter_raises_mbtimeout():
    server = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        name="server",
    )

    try:
        server.MB_GetMessage(
            filtermin=msgbus.TK_CMP_GETSERVICES,
            filtermax=msgbus.TK_CMP_START,
            timeout=0.1,
        )
        raise AssertionError("Must raise MBTimeout")
    except MBTimeout:
        pass

    server.MB_Finalize()


def test_get_message_raises_mbtimeout():
    server = MBContext(
        my_service=MBService(address=_SERVER_IP, port=_SERVER_PORT),
        name="server",
    )

    try:
        server.MB_GetMessage(timeout=0.1)
        raise AssertionError("Must raise MBTimeout")
    except MBTimeout:
        pass

    server.MB_Finalize()
