package at.procon.eventhub.tachographfilesession.service;

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

import at.procon.eventhub.config.EventHubProperties;
import at.procon.eventhub.dto.EventHubEventDto;
import at.procon.eventhub.service.EventDetailsFactory;
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
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.ExtractionStats;
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
import com.fasterxml.jackson.databind.ObjectMapper;
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 TachographEsperProcessingCoreParityTest {

    @Test
    void fileSessionAndEventInputUseSameCoreAndProduceEquivalentProjectionSections() {
        EventHubProperties properties = new EventHubProperties();
        DriverTimelineBuilder driverTimelineBuilder = new DriverTimelineBuilder();
        IntervalBackedDriverTimelineEventBuilder intervalEventBuilder = new IntervalBackedDriverTimelineEventBuilder(
                driverTimelineBuilder,
                new DriverKeyFactory(),
                new VehicleKeyFactory(),
                new EventDetailsFactory(new ObjectMapper())
        );
        RawSourceDriverTimelineEventBuilder rawSourceEventBuilder = new RawSourceDriverTimelineEventBuilder(intervalEventBuilder);
        DriverTimelineReusableProjectionBuilder projectionBuilder = new DriverTimelineReusableProjectionBuilder(
                driverTimelineBuilder,
                rawSourceEventBuilder,
                properties
        );
        TachographEsperProcessingCore core = new TachographEsperProcessingCore(
                driverTimelineBuilder,
                projectionBuilder,
                properties
        );

        DriverExtractionSession driver = driver();
        TachographFileSession session = session(driver);
        ResolvedDriverTimeline timeline = driverTimelineBuilder.build(session, driver);
        List<EventHubEventDto> rawEvents = rawSourceEventBuilder.buildRawEventBundle(session, driver).allEvents();

        TachographEsperDriverProcessingResultDto fileSessionResult = core.process(TachographEsperProcessingInput.fromFileSession(
                session,
                driver,
                timeline,
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-03T00:00:00Z"),
                3,
                420,
                List.of("file-session-adapter")
        ));
        TachographEsperDriverProcessingResultDto eventInputResult = core.process(TachographEsperProcessingInput.fromEvents(
                session.sessionId(),
                driver.driverKey(),
                timeline,
                rawEvents,
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-03T00:00:00Z"),
                3,
                420,
                List.of("runtime-adapter")
        ));

        assertThat(eventInputResult.activityIntervalCount()).isEqualTo(fileSessionResult.activityIntervalCount());
        assertThat(eventInputResult.drivingIntervalCount()).isEqualTo(fileSessionResult.drivingIntervalCount());
        assertThat(eventInputResult.vehicleUsageIntervalCount()).isEqualTo(fileSessionResult.vehicleUsageIntervalCount());
        assertThat(eventInputResult.vuCardAbsentIntervalCount()).isEqualTo(fileSessionResult.vuCardAbsentIntervalCount());
        assertThat(eventInputResult.dailyWeeklyRestCandidateIntervalCount())
                .isEqualTo(fileSessionResult.dailyWeeklyRestCandidateIntervalCount());
        assertThat(eventInputResult.dailyWeeklyRestCandidateCoverageIntervalCount())
                .isEqualTo(fileSessionResult.dailyWeeklyRestCandidateCoverageIntervalCount());
        assertThat(eventInputResult.potentialInVehicleOvernightStayIntervalCount())
                .isEqualTo(fileSessionResult.potentialInVehicleOvernightStayIntervalCount());
        assertThat(eventInputResult.potentialHomeOvernightStayIntervalCount())
                .isEqualTo(fileSessionResult.potentialHomeOvernightStayIntervalCount());
        assertThat(eventInputResult.notes()).contains("runtime-adapter");
    }

    private DriverExtractionSession driver() {
        return new DriverExtractionSession(
                "12:123",
                null,
                null,
                List.of(),
                List.of(),
                List.of(
                        new ExtractedCardVehicleUsageInterval(
                                "CVU-1",
                                OffsetDateTime.parse("2026-05-01T08:00:00Z"),
                                OffsetDateTime.parse("2026-05-01T23:59:59Z"),
                                100L,
                                200L,
                                "12:REG-1",
                                "VIN-1",
                                "vu-1"
                        ),
                        new ExtractedCardVehicleUsageInterval(
                                "CVU-2",
                                OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                                OffsetDateTime.parse("2026-05-02T10:00:00Z"),
                                200L,
                                260L,
                                "12:REG-1",
                                "VIN-1",
                                "vu-2"
                        )
                ),
                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"
                        ),
                        new ExtractedCardActivityInterval(
                                "ACT-2",
                                OffsetDateTime.parse("2026-05-01T18:30:00Z"),
                                OffsetDateTime.parse("2026-05-01T18:45:00Z"),
                                "DRIVE",
                                "DRIVER",
                                "INSERTED",
                                "SINGLE",
                                "12:REG-1",
                                "VIN-1",
                                "b"
                        )
                ),
                List.of(),
                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, 2, 2, 1, 1, 0),
                List.of(),
                Instant.now(),
                Instant.now().plus(4, ChronoUnit.HOURS)
        );
    }
}
