import time
from threading import Thread

from assertpy import assert_that
from messagebus import (
    AckMessage,
    Message,
    MessageBusException,
)


def test_multiple_threads_can_send_message(
    sender_message_bus,
    receiver_message_bus,
    receiver_address,
):
    sent_message = AckMessage()
    messages_per_thread = 100

    def send_message():
        for _ in range(messages_per_thread):
            sender_message_bus.send_direct_message(
                address=receiver_address,
                message=sent_message,
            )

    number_of_threads = 10
    for _ in range(number_of_threads):
        t = Thread(target=send_message)
        t.start()

    for i in range(number_of_threads * messages_per_thread):
        received_message = receiver_message_bus.receive()
        receiver_message_bus.reply_message(
            message=received_message,
            reply_message=AckMessage(),
        )


def test_multiple_threads_can_receive_message(
    sender_message_bus,
    receiver_message_bus,
    receiver_address,
):
    messages_per_thread = 100

    def receive_message():
        for _ in range(messages_per_thread):
            received_message = receiver_message_bus.receive()
            receiver_message_bus.reply_message(
                message=received_message,
                reply_message=AckMessage(),
            )

    number_of_threads = 10
    threads = []
    for _ in range(number_of_threads):
        t = Thread(target=receive_message)
        t.start()
        threads.append(t)

    for i in range(number_of_threads * messages_per_thread):
        sender_message_bus.send_direct_message(
            address=receiver_address,
            message=AckMessage(),
        )

    for t in threads:
        t.join()


def test_multiple_threads_can_send_and_receive_messages(
    sender_message_bus,
    receiver_message_bus,
    receiver_address,
):
    messages_per_thread = 100
    number_of_sender_threads = 10

    total_messages_sent = number_of_sender_threads * messages_per_thread
    number_of_receiver_threads = 10

    def send_message():
        for _ in range(messages_per_thread):
            sender_message_bus.send_direct_message(
                address=receiver_address,
                message=AckMessage(),
            )

    def receive_message():
        for _ in range(int(total_messages_sent / number_of_receiver_threads)):
            received_message = receiver_message_bus.receive()
            receiver_message_bus.reply_message(
                message=received_message,
                reply_message=AckMessage(),
            )

    for _ in range(number_of_sender_threads):
        t2 = Thread(target=send_message)
        t2.start()

    threads = []
    for _ in range(number_of_receiver_threads):
        t = Thread(target=receive_message)
        t.start()
        threads.append(t)

    for t in threads:
        t.join()
