package at.procon.eventhub.processing.service;

import static org.assertj.core.api.Assertions.assertThat;

import at.procon.eventhub.dto.DriverRefDto;
import at.procon.eventhub.dto.EventDomain;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.dto.EventSourceDto;
import at.procon.eventhub.dto.EventType;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import at.procon.eventhub.processing.model.UnifiedDiscoveredVehicleRef;
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBackend;
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class UnifiedRuntimeEventAssemblyServiceTest {

    @Test
    void assemblesSeedAndExpandedVehicleEventsInMemory() {
        UnifiedRuntimeEventAssemblyService service = new UnifiedRuntimeEventAssemblyService(
                List.of(new FakeLoader()),
                List.of(new FakeLoader())
        );

        UnifiedRuntimeEventBundle bundle = service.assembleDriverScopedEvents(
                new UnifiedRuntimeProcessingRequest(
                        null,
                        List.of(),
                        null,
                        "default",
                        Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB),
                        UnifiedRuntimeEventBackend.SOURCE_DB,
                        null,
                        Set.of(),
                        false,
                        Set.of(),
                        false,
                        "DRIVER:42",
                        null,
                        null,
                        OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                        OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                        true,
                        15
                )
        );

        assertThat(bundle.driverSeedEvents()).hasSize(2);
        assertThat(bundle.discoveredVehicles()).hasSize(2);
        assertThat(bundle.discoveredVehicles()).extracting(UnifiedDiscoveredVehicleRef::stableKey)
                .containsExactly("SOURCE_VEHICLE:VEH-1", "VIN:VIN-2");
        assertThat(bundle.expandedVehicleEvents()).hasSize(2);
        assertThat(bundle.mergedEvents()).hasSize(3);
        assertThat(bundle.mergedEvents()).extracting(EventHubEventDto::externalSourceEventId)
                .containsExactly("SEED-1", "VEHICLE-EXPANDED", "SEED-2");
    }

    @Test
    void canSkipVehicleExpansion() {
        UnifiedRuntimeEventAssemblyService service = new UnifiedRuntimeEventAssemblyService(
                List.of(new FakeLoader()),
                List.of(new FakeLoader())
        );

        UnifiedRuntimeEventBundle bundle = service.assembleDriverScopedEvents(
                UnifiedRuntimeProcessingRequest.forDriver(
                        "default",
                        Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB),
                        "DRIVER:42",
                        null,
                        null,
                        OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                        OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                        false,
                        0
                )
        );

        assertThat(bundle.driverSeedEvents()).hasSize(2);
        assertThat(bundle.discoveredVehicles()).hasSize(2);
        assertThat(bundle.expandedVehicleEvents()).isEmpty();
        assertThat(bundle.mergedEvents()).extracting(EventHubEventDto::externalSourceEventId)
                .containsExactly("SEED-1", "SEED-2");
    }

    private static final class FakeLoader implements RuntimeDriverEventLoader, RuntimeVehicleEventLoader {

        @Override
        public boolean supports(UnifiedRuntimeProcessingRequest request, UnifiedEventSourceFamily sourceFamily) {
            return request.eventBackend() == UnifiedRuntimeEventBackend.SOURCE_DB
                    && sourceFamily == UnifiedEventSourceFamily.TACHOGRAPH_DB;
        }

        @Override
        public List<EventHubEventDto> loadDriverEvents(UnifiedRuntimeProcessingRequest request) {
            return List.of(
                    event("SEED-1", OffsetDateTime.parse("2026-05-01T08:00:00Z"), "VEH-1", "VIN-1", "AT", "W-1"),
                    event("SEED-2", OffsetDateTime.parse("2026-05-01T09:00:00Z"), null, "VIN-2", "AT", "W-2")
            );
        }

        @Override
        public List<EventHubEventDto> loadVehicleEvents(
                UnifiedRuntimeProcessingRequest request,
                UnifiedDiscoveredVehicleRef vehicleRef
        ) {
            if ("SOURCE_VEHICLE:VEH-1".equals(vehicleRef.stableKey())) {
                return List.of(
                        event("SEED-1", OffsetDateTime.parse("2026-05-01T08:00:00Z"), "VEH-1", "VIN-1", "AT", "W-1"),
                        event("VEHICLE-EXPANDED", OffsetDateTime.parse("2026-05-01T08:30:00Z"), "VEH-1", "VIN-1", "AT", "W-1")
                );
            }
            return List.of();
        }

        private EventHubEventDto event(
                String externalId,
                OffsetDateTime occurredAt,
                String sourceVehicleId,
                String vin,
                String registrationNation,
                String registrationNumber
        ) {
            EventSourceDto source = new EventSourceDto("TACHOGRAPH", "DRIVER_CARD", "TACHOGRAPH_DRIVER_CARD", null, null, null);
            return new EventHubEventDto(
                    UUID.randomUUID(),
                    externalId,
                    new DriverRefDto("DRIVER:42", null),
                    new VehicleRefDto(
                            sourceVehicleId,
                            vin,
                            sourceVehicleId,
                            new VehicleRegistrationRefDto(registrationNation, registrationNumber)
                    ),
                    occurredAt,
                    null,
                    occurredAt,
                    EventDomain.DRIVER_ACTIVITY,
                    EventType.DRIVE,
                    EventLifecycle.START,
                    null,
                    null,
                    null,
                    null,
                    null,
                    false,
                    new at.procon.eventhub.dto.EventHubPackageRequest(
                            "default",
                            source,
                            null,
                            ImportScopeDto.tenantAll(
                                    OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                                    OffsetDateTime.parse("2026-05-02T00:00:00Z")
                            ),
                            EventDomain.DRIVER_ACTIVITY.name(),
                            LocalDate.parse("2026-05-01"),
                            source.stableKey() + ":2026-05-01"
                    )
            );
        }
    }
}
