package de.renew.net.event;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import de.renew.engine.thread.SimulationThreadPool;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
public class TransitionEventTest {
    @Mock
    private FiringEvent _mockFiringEvent;

    @Spy
    private TransitionEventListener _listener;

    private MockedStatic<SimulationThreadPool> _simulationThreadPoolMockedStatic;

    @BeforeEach
    void setUp() {
        _simulationThreadPoolMockedStatic = mockStatic(SimulationThreadPool.class);
        _simulationThreadPoolMockedStatic.when(SimulationThreadPool::isSimulationThread)
            .thenReturn(true);
    }

    @AfterEach
    public void tearDown() {
        _simulationThreadPoolMockedStatic.close();
    }

    @Test
    public void testEventFlow() {
        //given
        TransitionEventListenerSet producer = new TransitionEventListenerSet();
        when(_listener.wantSynchronousNotification()).thenReturn(true);

        //when
        producer.addTransitionEventListener(_listener);
        producer.firingStarted(_mockFiringEvent);
        producer.firingComplete(_mockFiringEvent);

        //then
        InOrder inOrder = inOrder(_listener);
        inOrder.verify(_listener).firingStarted(_mockFiringEvent);
        inOrder.verify(_listener).firingComplete(_mockFiringEvent);
    }

    @Test
    public void testReceiveEvent() {
        //given
        TransitionEventListenerSet producer = new TransitionEventListenerSet();
        TransitionEventAdapter adapter = new TransitionEventAdapter(true);

        //when
        producer.addTransitionEventListener(adapter);

        //then
        assertDoesNotThrow(() -> producer.firingStarted(_mockFiringEvent));
        assertDoesNotThrow(() -> producer.firingComplete(_mockFiringEvent));
        assertThat(adapter.wantSynchronousNotification()).isTrue();
    }
}