from threading import Thread

from assertpy import (
    assert_that,
)
from msgbus import (
    FM_UNDEFINED,
    MBContext,
    MBService,
    TK_SYS_ACK,
)


def test_receives_only_the_message_within_specified_filters():
    sender_service1 = MBService(
        address="127.0.0.1",
        port=15001,
    )
    sender1 = MBContext(
        my_service=sender_service1,
        name="Sender1",
    )
    sender_service2 = MBService(
        address="127.0.0.1",
        port=15002,
    )
    sender2 = MBContext(
        my_service=sender_service2,
        name="Sender2",
    )
    sender_service3 = MBService(
        address="127.0.0.1",
        port=15003,
    )
    sender3 = MBContext(
        my_service=sender_service3,
        name="Sender3",
    )

    receiver_service = MBService(
        address="127.0.0.1",
        port=14581,
    )
    receiver = MBContext(
        my_service=receiver_service,
        name="Receiver",
    )

    def receiver_thread():
        msg = receiver.MB_GetMessage(filtermin=10, filtermax=20)
        assert_that(msg.token).is_equal_to(15)

        msg.token = TK_SYS_ACK
        receiver.MB_ReplyMessage(
            message=msg,
            format=FM_UNDEFINED,
            data=b"",
        )

        msg = receiver.MB_GetMessage()
        assert_that(msg.token).is_in(9, 21)

        msg.token = TK_SYS_ACK
        receiver.MB_ReplyMessage(
            message=msg,
            format=FM_UNDEFINED,
            data=b"",
        )

        msg = receiver.MB_GetMessage()
        assert_that(msg.token).is_in(9, 21)

        msg.token = TK_SYS_ACK
        receiver.MB_ReplyMessage(
            message=msg,
            format=FM_UNDEFINED,
            data=b"",
        )

        receiver.MB_Finalize()


    def sender_thread(sender: MBContext, token: int):
        reply = sender.MB_SendFullMessage(
            destination=receiver_service,
            token=token,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)
        sender.MB_Finalize()

    receiver_thread = Thread(target=receiver_thread)
    sender1_thread = Thread(target=sender_thread, args=(sender1, 9))
    sender2_thread = Thread(target=sender_thread, args=(sender2, 21))
    sender3_thread = Thread(target=sender_thread, args=(sender3, 15))

    receiver_thread.start()
    sender1_thread.start()
    sender2_thread.start()
    sender3_thread.start()

    receiver_thread.join()
    sender1_thread.join()
    sender2_thread.join()
    sender3_thread.join()
