package vassistent.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

/**
 * Unit tests for {@link BinaryEventService}.
 */
@ExtendWith(MockitoExtension.class)
class BinaryEventServiceTest {

    @Mock
    private DataPersistenceService persistenceService;

    @Mock
    private EvaluationService evaluationService;

    private BinaryEventService binaryEventService;

    /**
     * Creates the service under test with mocked dependencies.
     */
    @BeforeEach
    void setUp() {
        binaryEventService = new BinaryEventService(
                persistenceService,
                evaluationService
        );
    }

    /**
     * Verifies that a valid payload triggers persistence and evaluation.
     */
    @Test
    void handlePayload_validPayload_persistsAndEvaluates() {
        String payload = "{\"valid\":true,\"_id\":1,\"prediction\":1}";

        binaryEventService.handlePayload(payload);

        verify(persistenceService).store(1);
        verify(evaluationService).evaluate();
    }

    /**
     * Verifies that an invalid "valid" flag prevents processing.
     */
    @Test
    void handlePayload_invalidFlag_doesNotProcess() {
        String payload = "{\"valid\":false,\"_id\":1,\"prediction\":1}";

        binaryEventService.handlePayload(payload);

        verify(persistenceService, never()).store(org.mockito.ArgumentMatchers.anyInt());
        verify(evaluationService, never()).evaluate();
    }

    /**
     * Verifies that payloads missing required fields are ignored.
     */
    @Test
    void handlePayload_missingPrediction_doesNotProcess() {
        String payload = "{\"valid\":true,\"_id\":1}";

        binaryEventService.handlePayload(payload);

        verify(persistenceService, never()).store(org.mockito.ArgumentMatchers.anyInt());
        verify(evaluationService, never()).evaluate();
    }

    /**
     * Verifies that predictions outside the binary domain are ignored.
     */
    @Test
    void handlePayload_invalidPrediction_doesNotProcess() {
        String payload = "{\"valid\":true,\"_id\":1,\"prediction\":3}";

        binaryEventService.handlePayload(payload);

        verify(persistenceService, never()).store(org.mockito.ArgumentMatchers.anyInt());
        verify(evaluationService, never()).evaluate();
    }

    /**
     * Verifies that malformed JSON payloads do not trigger downstream processing.
     */
    @Test
    void handlePayload_malformedJson_doesNotProcess() {
        String payload = "not-json";

        binaryEventService.handlePayload(payload);

        verify(persistenceService, never()).store(org.mockito.ArgumentMatchers.anyInt());
        verify(evaluationService, never()).evaluate();
    }

    /**
     * Verifies current behavior for duplicate IDs.
     */
    @Test
    void handlePayload_duplicateId_isIgnoredAfterFirstMessage() {
        String payload = "{\"valid\":true,\"_id\":7,\"prediction\":0}";

        binaryEventService.handlePayload(payload);
        binaryEventService.handlePayload(payload);

        verify(persistenceService, times(1)).store(0);
        verify(evaluationService, times(1)).evaluate();
    }
}
