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.EventHubPackageRequest;
import at.procon.eventhub.dto.GeoPointDto;
import at.procon.eventhub.dto.ImportScopeDto;
import at.procon.eventhub.dto.VehicleRefDto;
import at.procon.eventhub.dto.VehicleRegistrationRefDto;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class UnifiedEventTimelineReconstructorTest {

    private final UnifiedEventTimelineReconstructor reconstructor = new UnifiedEventTimelineReconstructor();

    @Test
    void reconstructsTimelineFromUnifiedEvents() {
        List<EventHubEventDto> events = List.of(
                activityEvent("ACT-1", EventLifecycle.START, "2026-05-01T08:00:00Z"),
                activityEvent("ACT-1", EventLifecycle.END, "2026-05-01T09:00:00Z"),
                vehicleUsageEvent("CVU-1", EventType.CARD_INSERTED, EventLifecycle.INSERT, "2026-05-01T07:50:00Z", 100_000L),
                vehicleUsageEvent("CVU-1", EventType.CARD_WITHDRAWN, EventLifecycle.WITHDRAW, "2026-05-01T10:10:00Z", 140_000L),
                supportEvent("SUP-1", "2026-05-01T08:30:00Z")
        );

        ResolvedDriverTimeline timeline = reconstructor.reconstruct(
                UUID.randomUUID(),
                "DRIVER:42",
                events
        );

        assertThat(timeline.sourceKind()).isEqualTo("DRIVER_CARD");
        assertThat(timeline.loadedFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T07:50:00Z"));
        assertThat(timeline.loadedTo()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:10:00Z"));
        assertThat(timeline.activityIntervals()).hasSize(1);
        assertThat(timeline.activityIntervals().get(0).intervalId()).isEqualTo("ACT-1");
        assertThat(timeline.activityIntervals().get(0).activityType()).isEqualTo("DRIVE");
        assertThat(timeline.activityIntervals().get(0).registrationKey()).isEqualTo("12:REG-1");
        assertThat(timeline.vehicleUsageIntervals()).hasSize(1);
        assertThat(timeline.vehicleUsageIntervals().get(0).intervalId()).isEqualTo("CVU-1");
        assertThat(timeline.vehicleUsageIntervals().get(0).odometerBeginKm()).isEqualTo(100L);
        assertThat(timeline.vehicleUsageIntervals().get(0).odometerEndKm()).isEqualTo(140L);
        assertThat(timeline.supportEvents()).hasSize(1);
        assertThat(timeline.supportEvents().get(0).eventId()).isEqualTo("SUP-1");
        assertThat(timeline.supportEvents().get(0).eventDomain()).isEqualTo("POSITION");
        assertThat(timeline.supportEvents().get(0).latitude()).isEqualByComparingTo(BigDecimal.valueOf(48.2082));
    }

    private EventHubEventDto activityEvent(String intervalId, EventLifecycle lifecycle, String occurredAt) {
        ObjectNode raw = JsonNodeFactory.instance.objectNode();
        raw.put("intervalId", intervalId);
        raw.put("registrationKey", "12:REG-1");
        raw.put("vehicleKey", "VIN-1");
        raw.put("sourceKind", "DRIVER_CARD");
        raw.putArray("sourceRowIds").add("row-" + intervalId);
        ObjectNode payload = JsonNodeFactory.instance.objectNode();
        payload.set("raw", raw);
        return new EventHubEventDto(
                UUID.randomUUID(),
                intervalId + ":" + lifecycle.name(),
                new DriverRefDto("DRIVER:42", null),
                new VehicleRefDto("VEH-1", "VIN-1", "VR-1", new VehicleRegistrationRefDto("12", 12, "REG-1")),
                OffsetDateTime.parse(occurredAt),
                null,
                OffsetDateTime.parse(occurredAt),
                EventDomain.DRIVER_ACTIVITY,
                EventType.DRIVE,
                lifecycle,
                null,
                null,
                null,
                null,
                payload,
                false,
                packageInfo("DRIVER_CARD", EventDomain.DRIVER_ACTIVITY)
        );
    }

    private EventHubEventDto vehicleUsageEvent(
            String intervalId,
            EventType eventType,
            EventLifecycle lifecycle,
            String occurredAt,
            long odometerM
    ) {
        ObjectNode raw = JsonNodeFactory.instance.objectNode();
        raw.put("intervalId", intervalId);
        raw.put("registrationKey", "12:REG-1");
        raw.put("vehicleKey", "VIN-1");
        raw.put("sourceKind", "DRIVER_CARD");
        raw.putArray("sourceRowIds").add("row-" + intervalId);
        ObjectNode payload = JsonNodeFactory.instance.objectNode();
        payload.set("raw", raw);
        return new EventHubEventDto(
                UUID.randomUUID(),
                intervalId + ":" + eventType.name(),
                new DriverRefDto("DRIVER:42", null),
                new VehicleRefDto("VEH-1", "VIN-1", "VR-1", new VehicleRegistrationRefDto("12", 12, "REG-1")),
                OffsetDateTime.parse(occurredAt),
                null,
                OffsetDateTime.parse(occurredAt),
                EventDomain.DRIVER_CARD,
                eventType,
                lifecycle,
                odometerM,
                null,
                null,
                null,
                payload,
                false,
                packageInfo("DRIVER_CARD", EventDomain.DRIVER_CARD)
        );
    }

    private EventHubEventDto supportEvent(String eventId, String occurredAt) {
        ObjectNode raw = JsonNodeFactory.instance.objectNode();
        raw.put("supportEventId", eventId);
        raw.put("registrationKey", "12:REG-1");
        raw.put("vehicleKey", "VIN-1");
        raw.put("sourceKind", "DRIVER_CARD");
        raw.put("authenticationStatus", "AUTHENTIC");
        raw.put("odometerKm", 120);
        raw.put("rawRecordPath", "card/positions/1");
        ObjectNode payload = JsonNodeFactory.instance.objectNode();
        payload.set("raw", raw);
        return new EventHubEventDto(
                UUID.randomUUID(),
                eventId,
                new DriverRefDto("DRIVER:42", null),
                new VehicleRefDto("VEH-1", "VIN-1", "VR-1", new VehicleRegistrationRefDto("12", 12, "REG-1")),
                OffsetDateTime.parse(occurredAt),
                null,
                OffsetDateTime.parse(occurredAt),
                EventDomain.POSITION,
                EventType.POSITION_RECORDED,
                EventLifecycle.SNAPSHOT,
                120_000L,
                new GeoPointDto(BigDecimal.valueOf(48.2082), BigDecimal.valueOf(16.3738)),
                null,
                null,
                payload,
                false,
                packageInfo("DRIVER_CARD", EventDomain.POSITION)
        );
    }

    private EventHubPackageRequest packageInfo(String sourceKind, EventDomain eventDomain) {
        EventSourceDto source = new EventSourceDto("TACHOGRAPH", sourceKind, "SOURCE", null, null, null);
        return new EventHubPackageRequest(
                "default",
                source,
                null,
                ImportScopeDto.tenantAll(
                        OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                        OffsetDateTime.parse("2026-05-02T00:00:00Z")
                ),
                eventDomain.name(),
                LocalDate.parse("2026-05-01"),
                source.stableKey() + ":" + eventDomain.name() + ":2026-05-01"
        );
    }
}
