package at.procon.eventhub.processing.service;

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

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.EventDomain;
import at.procon.eventhub.dto.EventLifecycle;
import at.procon.eventhub.processing.model.UnifiedDriverEventsRequest;
import at.procon.eventhub.service.EventDetailsFactory;
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
import at.procon.eventhub.tachographfilesession.model.ExtractedCardActivityInterval;
import at.procon.eventhub.tachographfilesession.model.ExtractedCardVehicleUsageInterval;
import at.procon.eventhub.tachographfilesession.model.ExtractedDriver;
import at.procon.eventhub.tachographfilesession.model.ExtractedDriverCard;
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
import at.procon.eventhub.tachographfilesession.model.ExtractedVehicle;
import at.procon.eventhub.tachographfilesession.model.ExtractedVehicleRegistration;
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
import at.procon.eventhub.tachographfilesession.service.DriverKeyFactory;
import at.procon.eventhub.tachographfilesession.service.DriverTimelineBuilder;
import at.procon.eventhub.tachographfilesession.service.InMemoryTachographFileSessionRepository;
import at.procon.eventhub.tachographfilesession.service.IntervalBackedDriverTimelineEventBuilder;
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionRepository;
import at.procon.eventhub.tachographfilesession.service.VehicleKeyFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class UnifiedDriverEventSourceServiceTest {

    @Test
    void loadsNormalizedFileSessionEventsThroughUnifiedService() {
        EventHubProperties properties = new EventHubProperties();
        TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
        DriverTimelineBuilder timelineBuilder = new DriverTimelineBuilder();
        UnifiedDriverEventSourceService service = new UnifiedDriverEventSourceService(List.of(
                new TachographFileSessionUnifiedDriverEventSource(
                        repository,
                        new IntervalBackedDriverTimelineEventBuilder(
                                timelineBuilder,
                                new DriverKeyFactory(),
                                new VehicleKeyFactory(),
                                new EventDetailsFactory(new ObjectMapper())
                        )
                )
        ));

        DriverExtractionSession driver = driver();
        TachographFileSession session = session(driver);
        repository.save(session);

        List<at.procon.eventhub.dto.EventHubEventDto> events = service.loadDriverEvents(
                UnifiedDriverEventsRequest.forTachographFileSession(
                        session.sessionId(),
                        driver.driverKey(),
                        OffsetDateTime.parse("2026-05-01T08:30:00Z"),
                        OffsetDateTime.parse("2026-05-01T09:00:00Z")
                )
        );

        assertThat(events).hasSize(3);
        assertThat(events).extracting(event -> event.occurredAt())
                .containsExactly(
                        OffsetDateTime.parse("2026-05-01T08:30:00Z"),
                        OffsetDateTime.parse("2026-05-01T08:45:00Z"),
                        OffsetDateTime.parse("2026-05-01T09:00:00Z")
                );
        assertThat(events).extracting(event -> event.eventDomain())
                .containsExactly(
                        EventDomain.DRIVER_ACTIVITY,
                        EventDomain.POSITION,
                        EventDomain.DRIVER_ACTIVITY
                );
        assertThat(events.get(0).lifecycle()).isEqualTo(EventLifecycle.START);
        assertThat(events.get(2).lifecycle()).isEqualTo(EventLifecycle.END);
        assertThat(events.get(1).eventDetails().type()).isEqualTo("POSITION");
    }

    private DriverExtractionSession driver() {
        return new DriverExtractionSession(
                "12:123",
                new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
                new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
                List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
                List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
                List.of(new ExtractedCardVehicleUsageInterval(
                        "CVU-1",
                        OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                        OffsetDateTime.parse("2026-05-01T10:00:00Z"),
                        100L,
                        200L,
                        "12:REG-1",
                        "VIN-1",
                        "vu-1"
                )),
                List.of(new ExtractedCardActivityInterval(
                        "ACT-1",
                        OffsetDateTime.parse("2026-05-01T08:30:00Z"),
                        OffsetDateTime.parse("2026-05-01T09:00:00Z"),
                        "DRIVE",
                        "DRIVER",
                        "INSERTED",
                        "SINGLE",
                        "12:REG-1",
                        "VIN-1",
                        "a"
                )),
                List.of(new ExtractedSupportEvent(
                        "SUP-1",
                        "12:123",
                        OffsetDateTime.parse("2026-05-01T08:45:00Z"),
                        "POSITION",
                        "POSITION_RECORDED",
                        "SNAPSHOT",
                        "DRIVER",
                        "12:REG-1",
                        "VIN-1",
                        null,
                        null,
                        null,
                        null,
                        null,
                        BigDecimal.valueOf(48.2082),
                        BigDecimal.valueOf(16.3738),
                        "AUTHENTIC",
                        150L,
                        null,
                        null,
                        null,
                        "raw-path"
                )),
                List.of()
        );
    }

    private TachographFileSession session(DriverExtractionSession driver) {
        return new TachographFileSession(
                UUID.randomUUID(),
                new TachographFileSessionMetadata(
                        "default",
                        "legalrequirements-drivercard",
                        "sample",
                        "sample.ddd",
                        "a",
                        2,
                        "42",
                        "b",
                        true,
                        null
                ),
                Map.of(driver.driverKey(), driver),
                new ExtractionStats(1, 1, 1, 1, 1, 0),
                List.of(),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );
    }
}
