package at.procon.eventhub.processing.eventprocessing.validation;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

import at.procon.eventhub.processing.dto.UnifiedRuntimeDerivedProjectionResultDto;
import at.procon.eventhub.processing.eventprocessing.RuntimeEventProcessingService;
import at.procon.eventhub.processing.eventprocessing.dto.RuntimeEventProcessingPartitionResultDto;
import at.procon.eventhub.processing.eventprocessing.dto.RuntimeEventProcessingResultDto;
import at.procon.eventhub.processing.eventprocessing.partition.RuntimeEventPartitioningStrategy;
import at.procon.eventhub.processing.eventprocessing.profile.TachographDriverEsperRuntimeEventProcessingProfile;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.service.TachographCompositeSessionRepository;
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionRepository;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class RuntimeTachographParityValidationServiceTest {

    @Test
    void reportsEqualWhenRuntimeProfileMatchesFileSessionReferenceCounts() {
        TachographFileSessionRepository fileSessionRepository = org.mockito.Mockito.mock(TachographFileSessionRepository.class);
        TachographCompositeSessionRepository compositeSessionRepository = org.mockito.Mockito.mock(TachographCompositeSessionRepository.class);
        TachographFileSessionProcessingService fileSessionProcessingService = org.mockito.Mockito.mock(TachographFileSessionProcessingService.class);
        RuntimeEventProcessingService runtimeEventProcessingService = org.mockito.Mockito.mock(RuntimeEventProcessingService.class);
        RuntimeTachographParityValidationService service = new RuntimeTachographParityValidationService(
                fileSessionRepository,
                compositeSessionRepository,
                fileSessionProcessingService,
                runtimeEventProcessingService
        );

        UUID sessionId = UUID.randomUUID();
        String driverKey = "12:123";
        TachographFileSession session = session(sessionId, driverKey);
        when(fileSessionRepository.find(sessionId)).thenReturn(Optional.of(session));
        when(fileSessionProcessingService.getEsperDriverProcessingResults(eq(sessionId), eq(driverKey), any()))
                .thenReturn(projection(sessionId, driverKey, 2, 1, 1));

        UnifiedRuntimeProcessingRequest runtimeRequest = UnifiedRuntimeProcessingRequest.forTachographFileSession(
                sessionId,
                driverKey,
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                OffsetDateTime.parse("2026-05-01T10:00:00Z"),
                true,
                0
        );
        UnifiedRuntimeDerivedProjectionResultDto runtimeDriverResult = new UnifiedRuntimeDerivedProjectionResultDto(
                runtimeRequest,
                4,
                1,
                0,
                4,
                List.of(),
                projection(sessionId, driverKey, 2, 1, 1).toDriverWorkingTime(),
                List.of()
        );
        when(runtimeEventProcessingService.process(any()))
                .thenReturn(new RuntimeEventProcessingResultDto(
                        TachographDriverEsperRuntimeEventProcessingProfile.PROFILE_KEY,
                        RuntimeEventPartitioningStrategy.DRIVER,
                        runtimeRequest,
                        4,
                        1,
                        1,
                        List.of(),
                        Map.of(driverKey, new RuntimeEventProcessingPartitionResultDto(
                                "DRIVER",
                                driverKey,
                                "UnifiedRuntimeDerivedProjectionResultDto",
                                runtimeDriverResult,
                                Map.of()
                        )),
                        List.of(),
                        List.of()
                ));

        RuntimeTachographParityValidationResultDto result = service.validate(new RuntimeTachographParityValidationApiRequest(
                sessionId,
                List.of(),
                null,
                driverKey,
                Set.of(),
                false,
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                OffsetDateTime.parse("2026-05-01T10:00:00Z"),
                true,
                0,
                3,
                720,
                true
        ));

        assertThat(result.status()).isEqualTo("EQUAL");
        assertThat(result.driverResults()).containsKey(driverKey);
        assertThat(result.driverResults().get(driverKey).comparisons())
                .anySatisfy(comparison -> {
                    assertThat(comparison.category()).isEqualTo("activityIntervals");
                    assertThat(comparison.fileSessionCount()).isEqualTo(2);
                    assertThat(comparison.runtimeCount()).isEqualTo(2);
                    assertThat(comparison.equal()).isTrue();
                });
    }

    private TachographFileSession session(UUID sessionId, String driverKey) {
        DriverExtractionSession driver = new DriverExtractionSession(
                driverKey,
                null,
                null,
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of()
        );
        return new TachographFileSession(
                sessionId,
                null,
                Map.of(driverKey, driver),
                new ExtractionStats(1, 0, 0, 0, 0, 0),
                List.of(),
                Instant.now(),
                Instant.now().plusSeconds(3600)
        );
    }

    private TachographEsperDriverProcessingResultDto projection(
            UUID sessionId,
            String driverKey,
            int activityCount,
            int drivingCount,
            int interruptionCount
    ) {
        return new TachographEsperDriverProcessingResultDto(
                sessionId,
                driverKey,
                "DRIVER_CARD",
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                OffsetDateTime.parse("2026-05-01T10:00:00Z"),
                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                OffsetDateTime.parse("2026-05-01T10:00:00Z"),
                activityCount,
                drivingCount,
                interruptionCount,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                1,
                0,
                0,
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of(),
                List.of()
        );
    }
}
