from threading import Thread

from assertpy import (
    assert_that,
)
from msgbus import (
    MBContext,
    MBException,
    MBService,
    SE_MB_ERR,
    SE_SUCCESS,
    TK_CMP_GETDEPENDS,
    TK_CMP_GETSERVICES,
    TK_CMP_START,
    TK_CMP_TERM_NOW,
    TK_SYS_ACK,
    TK_SYS_NAK,
)


def test_correctly_process_all_hv_wait_start_messages_when_component_has_services_and_dependencies():
    hv_simulator_service = MBService(
        address="127.0.0.1",
        port=15001,
    )
    hv_simulator = MBContext(
        my_service=hv_simulator_service,
        name="Sender1",
    )

    service = MBService(
        address="127.0.0.1",
        port=15002,
    )
    mb_context = MBContext(
        my_service=service,
        name="Sender2",
    )

    required_services = "service2|service3"
    exported_services = "service1|service2"

    def hv_thread():
        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_GETDEPENDS,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)
        assert_that(reply.data.decode()).is_equal_to(required_services)

        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_GETSERVICES,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)
        assert_that(reply.data.decode()).is_equal_to(exported_services)

        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_START,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)

        hv_simulator.MB_Finalize()

    hv_thread = Thread(target=hv_thread)
    hv_thread.start()

    ret = mb_context.MB_WaitStart(
        exported_services=exported_services,
        required_services=required_services,
    )

    assert_that(ret).is_equal_to(SE_SUCCESS)

    hv_thread.join()

    mb_context.MB_Finalize()


def test_correctly_process_all_hv_wait_start_messages_when_component_has_no_services_nor_dependencies():
    hv_simulator_service = MBService(
        address="127.0.0.1",
        port=15001,
    )
    hv_simulator = MBContext(
        my_service=hv_simulator_service,
        name="Sender1",
    )

    service = MBService(
        address="127.0.0.1",
        port=15002,
    )
    mb_context = MBContext(
        my_service=service,
        name="Sender2",
    )

    def hv_thread():
        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_GETDEPENDS,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_NAK)

        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_GETSERVICES,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_NAK)

        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_START,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)

        hv_simulator.MB_Finalize()

    hv_thread = Thread(target=hv_thread)
    hv_thread.start()

    ret = mb_context.MB_WaitStart()
    assert_that(ret).is_equal_to(SE_SUCCESS)

    mb_context.MB_Finalize()

    hv_thread.join()


def test_raises_exception_when_component_is_terminating():
    hv_simulator_service = MBService(
        address="127.0.0.1",
        port=15001,
    )
    hv_simulator = MBContext(
        my_service=hv_simulator_service,
        name="Sender1",
    )

    service = MBService(
        address="127.0.0.1",
        port=15002,
    )
    mb_context = MBContext(
        my_service=service,
        name="Sender2",
    )

    def hv_thread():
        reply = hv_simulator.MB_SendFullMessage(
            destination=service,
            token=TK_CMP_TERM_NOW,
        )
        assert_that(reply.token).is_equal_to(TK_SYS_ACK)


        hv_simulator.MB_Finalize()

    hv_thread = Thread(target=hv_thread)
    hv_thread.start()

    try:
        mb_context.MB_WaitStart()
    except MBException as ex:
        assert_that(ex.errorcode).is_equal_to(SE_MB_ERR)

    mb_context.MB_Finalize()

    hv_thread.join()
