package at.procon.eventhub.processing.model;

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

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class UnifiedRuntimeProcessingRequestTest {

    @Test
    void buildsDriverScopedRuntimeRequest() {
        UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forDriver(
                "default",
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB, UnifiedEventSourceFamily.YELLOWFOX_DB),
                "DRIVER:42",
                "AT",
                "1234567890123457",
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-02T00:00:00Z")
        );

        assertThat(request.tenantKey()).isEqualTo("default");
        assertThat(request.sourceFamilies()).containsExactlyInAnyOrder(
                UnifiedEventSourceFamily.TACHOGRAPH_DB,
                UnifiedEventSourceFamily.YELLOWFOX_DB
        );
        assertThat(request.driverSourceEntityId()).isEqualTo("DRIVER:42");
        assertThat(request.driverCardNation()).isEqualTo("AT");
        assertThat(request.driverCardNumber()).isEqualTo("12345678901234");
        assertThat(request.eventBackend()).isEqualTo(UnifiedRuntimeEventBackend.SOURCE_DB);
        assertThat(request.expandVehicleEvents()).isTrue();
        assertThat(request.vehicleOccurredFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
    }

    @Test
    void canDisableVehicleExpansionExplicitly() {
        UnifiedRuntimeProcessingRequest request = 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,
                30
        );

        assertThat(request.expandVehicleEvents()).isFalse();
        assertThat(request.vehicleExpansionPaddingMinutes()).isEqualTo(30);
    }

    @Test
    void defaultsToBothTachographSourceKindsAndCanRestrictToOne() {
        UnifiedRuntimeProcessingRequest defaultRequest = 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")
        );

        assertThat(defaultRequest.tachographSourceKinds()).containsExactlyInAnyOrder(
                UnifiedTachographSourceKind.DRIVER_CARD,
                UnifiedTachographSourceKind.VEHICLE_UNIT
        );
        assertThat(defaultRequest.includesTachographSourceKind("DRIVER_CARD")).isTrue();
        assertThat(defaultRequest.includesTachographSourceKind("VEHICLE_UNIT")).isTrue();

        UnifiedRuntimeProcessingRequest driverCardOnlyRequest = new UnifiedRuntimeProcessingRequest(
                null,
                List.of(),
                null,
                "default",
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                Set.of(UnifiedTachographSourceKind.DRIVER_CARD),
                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,
                0
        );

        assertThat(driverCardOnlyRequest.tachographSourceKinds()).containsExactly(UnifiedTachographSourceKind.DRIVER_CARD);
        assertThat(driverCardOnlyRequest.includesTachographSourceKind("DRIVER_CARD")).isTrue();
        assertThat(driverCardOnlyRequest.includesTachographSourceKind("VEHICLE_UNIT")).isFalse();
    }

    @Test
    void canBuildEventHubBackedRuntimeRequest() {
        UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forDriverFromEventHub(
                "default",
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB, UnifiedEventSourceFamily.YELLOWFOX_DB),
                "DRIVER:42",
                null,
                null,
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                true,
                15
        );

        assertThat(request.eventBackend()).isEqualTo(UnifiedRuntimeEventBackend.EVENTHUB_DB);
        assertThat(request.vehicleExpansionPaddingMinutes()).isEqualTo(15);
    }

    @Test
    void canBuildFileSessionRuntimeRequest() {
        UUID sessionId = UUID.randomUUID();
        UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forTachographFileSession(
                sessionId,
                "12:123",
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                true,
                10
        );

        assertThat(request.sessionId()).isEqualTo(sessionId);
        assertThat(request.driverKey()).isEqualTo("12:123");
        assertThat(request.sourceFamilies()).containsExactly(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION);
        assertThat(request.eventBackend()).isEqualTo(UnifiedRuntimeEventBackend.SOURCE_DB);
    }



    @Test
    void canBuildMultiFileSessionRuntimeRequest() {
        UUID firstSessionId = UUID.randomUUID();
        UUID secondSessionId = UUID.randomUUID();
        UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forTachographFileSessions(
                List.of(firstSessionId, secondSessionId),
                "12:123",
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-03T00:00:00Z"),
                true,
                10
        );

        assertThat(request.sessionId()).isEqualTo(firstSessionId);
        assertThat(request.sessionIds()).containsExactly(firstSessionId, secondSessionId);
        assertThat(request.compositeSessionId()).isNull();
    }

    @Test
    void canBuildCompositeFileSessionRuntimeRequest() {
        UUID compositeSessionId = UUID.randomUUID();
        UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forTachographCompositeSession(
                compositeSessionId,
                "12:123",
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-03T00:00:00Z"),
                true,
                10
        );

        assertThat(request.sessionId()).isNull();
        assertThat(request.sessionIds()).isEmpty();
        assertThat(request.compositeSessionId()).isEqualTo(compositeSessionId);
    }

    @Test
    void canBuildMultiDriverFileSessionRuntimeScopeRequest() {
        UUID sessionId = UUID.randomUUID();
        UnifiedRuntimeProcessingRequest request = new UnifiedRuntimeProcessingRequest(
                sessionId,
                List.of(),
                null,
                null,
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                null,
                null,
                Set.of("12:123", "12:456"),
                false,
                Set.of(),
                false,
                null,
                null,
                null,
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                true,
                10
        );

        assertThat(request.driverKey()).isNull();
        assertThat(request.driverKeys()).containsExactlyInAnyOrder("12:123", "12:456");
    }

    @Test
    void canBuildIncludeAllDriversRuntimeScopeRequest() {
        UUID sessionId = UUID.randomUUID();
        UnifiedRuntimeProcessingRequest request = new UnifiedRuntimeProcessingRequest(
                sessionId,
                List.of(),
                null,
                null,
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                null,
                null,
                Set.of(),
                true,
                Set.of(),
                false,
                null,
                null,
                null,
                OffsetDateTime.parse("2026-05-01T00:00:00Z"),
                OffsetDateTime.parse("2026-05-02T00:00:00Z"),
                true,
                10
        );

        assertThat(request.includeAllDrivers()).isTrue();
        assertThat(request.driverKey()).isNull();
    }

    @Test
    void rejectsAmbiguousExplicitAndCompositeSessionSelectors() {
        UUID sessionId = UUID.randomUUID();
        UUID compositeSessionId = UUID.randomUUID();
        assertThatThrownBy(() -> new UnifiedRuntimeProcessingRequest(
                sessionId,
                List.of(),
                compositeSessionId,
                null,
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                null,
                "12:123",
                Set.of(),
                false,
                Set.of(),
                false,
                null,
                null,
                null,
                null,
                null,
                true,
                0
        )).isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("Use either compositeSessionId");
    }


    @Test
    void rejectsRequestWithoutDriverSelector() {
        assertThatThrownBy(() -> new UnifiedRuntimeProcessingRequest(
                null,
                List.of(),
                null,
                "default",
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                null,
                null,
                Set.of(),
                false,
                Set.of(),
                false,
                null,
                null,
                null,
                null,
                null,
                true,
                0
        )).isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("At least one driver selector");
    }
}
