package at.procon.eventhub.processing.model;

import at.procon.eventhub.reference.DriverCardNumberNormalizer;
import java.time.OffsetDateTime;
import java.util.Set;
import java.util.UUID;

public record UnifiedRuntimeProcessingRequest(
        UUID sessionId,
        String tenantKey,
        Set<UnifiedEventSourceFamily> sourceFamilies,
        UnifiedRuntimeEventBackend eventBackend,
        String driverKey,
        String driverSourceEntityId,
        String driverCardNation,
        String driverCardNumber,
        OffsetDateTime occurredFrom,
        OffsetDateTime occurredTo,
        boolean expandVehicleEvents,
        int vehicleExpansionPaddingMinutes
) {
    public UnifiedRuntimeProcessingRequest {
        driverKey = normalize(driverKey);
        tenantKey = normalize(tenantKey);
        driverSourceEntityId = normalize(driverSourceEntityId);
        driverCardNation = normalizeUpper(driverCardNation);
        driverCardNumber = normalizeDriverCardNumber(driverCardNumber);
        boolean includesFileSession = sourceFamilies != null && sourceFamilies.contains(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION);
        boolean includesExternalDb = sourceFamilies != null && sourceFamilies.stream()
                .anyMatch(family -> family == UnifiedEventSourceFamily.TACHOGRAPH_DB || family == UnifiedEventSourceFamily.YELLOWFOX_DB);
        if (tenantKey == null) {
            if (!includesFileSession || includesExternalDb) {
                throw new IllegalArgumentException("tenantKey must not be blank");
            }
        }
        if (sourceFamilies == null || sourceFamilies.isEmpty()) {
            throw new IllegalArgumentException("sourceFamilies must not be empty");
        }
        sourceFamilies = Set.copyOf(sourceFamilies);
        eventBackend = eventBackend == null ? UnifiedRuntimeEventBackend.SOURCE_DB : eventBackend;
        if (includesFileSession && sessionId == null) {
            throw new IllegalArgumentException("sessionId must not be null when TACHOGRAPH_FILE_SESSION is selected.");
        }
        if (includesFileSession && driverKey == null) {
            throw new IllegalArgumentException("driverKey must not be blank when TACHOGRAPH_FILE_SESSION is selected.");
        }
        if (includesExternalDb && driverSourceEntityId == null && driverCardNumber == null) {
            throw new IllegalArgumentException("At least one driver selector must be provided.");
        }
        if (occurredFrom != null && occurredTo != null && occurredTo.isBefore(occurredFrom)) {
            throw new IllegalArgumentException("occurredTo must not be before occurredFrom");
        }
        if (vehicleExpansionPaddingMinutes < 0) {
            throw new IllegalArgumentException("vehicleExpansionPaddingMinutes must not be negative");
        }
    }

    public static UnifiedRuntimeProcessingRequest forDriver(
            String tenantKey,
            Set<UnifiedEventSourceFamily> sourceFamilies,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo
    ) {
        return forDriver(
                tenantKey,
                sourceFamilies,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                occurredFrom,
                occurredTo,
                UnifiedRuntimeEventBackend.SOURCE_DB,
                true,
                0
        );
    }

    public static UnifiedRuntimeProcessingRequest forDriver(
            String tenantKey,
            Set<UnifiedEventSourceFamily> sourceFamilies,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo,
            boolean expandVehicleEvents,
            int vehicleExpansionPaddingMinutes
    ) {
        return forDriver(
                tenantKey,
                sourceFamilies,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                occurredFrom,
                occurredTo,
                UnifiedRuntimeEventBackend.SOURCE_DB,
                expandVehicleEvents,
                vehicleExpansionPaddingMinutes
        );
    }

    public static UnifiedRuntimeProcessingRequest forDriver(
            String tenantKey,
            Set<UnifiedEventSourceFamily> sourceFamilies,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo,
            UnifiedRuntimeEventBackend eventBackend,
            boolean expandVehicleEvents,
            int vehicleExpansionPaddingMinutes
    ) {
        return new UnifiedRuntimeProcessingRequest(
                null,
                tenantKey,
                sourceFamilies,
                eventBackend,
                null,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                occurredFrom,
                occurredTo,
                expandVehicleEvents,
                vehicleExpansionPaddingMinutes
        );
    }

    public static UnifiedRuntimeProcessingRequest forDriverFromEventHub(
            String tenantKey,
            Set<UnifiedEventSourceFamily> sourceFamilies,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo,
            boolean expandVehicleEvents,
            int vehicleExpansionPaddingMinutes
    ) {
        return new UnifiedRuntimeProcessingRequest(
                null,
                tenantKey,
                sourceFamilies,
                UnifiedRuntimeEventBackend.EVENTHUB_DB,
                null,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                occurredFrom,
                occurredTo,
                expandVehicleEvents,
                vehicleExpansionPaddingMinutes
        );
    }

    public static UnifiedRuntimeProcessingRequest forTachographFileSession(
            UUID sessionId,
            String driverKey,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo,
            boolean expandVehicleEvents,
            int vehicleExpansionPaddingMinutes
    ) {
        return new UnifiedRuntimeProcessingRequest(
                sessionId,
                null,
                Set.of(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION),
                UnifiedRuntimeEventBackend.SOURCE_DB,
                driverKey,
                null,
                null,
                null,
                occurredFrom,
                occurredTo,
                expandVehicleEvents,
                vehicleExpansionPaddingMinutes
        );
    }

    public OffsetDateTime vehicleOccurredFrom() {
        return occurredFrom == null ? null : occurredFrom.minusMinutes(vehicleExpansionPaddingMinutes);
    }

    public OffsetDateTime vehicleOccurredTo() {
        return occurredTo == null ? null : occurredTo.plusMinutes(vehicleExpansionPaddingMinutes);
    }

    private static String normalize(String value) {
        return value == null || value.isBlank() ? null : value.trim();
    }

    private static String normalizeUpper(String value) {
        return value == null || value.isBlank() ? null : value.trim().toUpperCase();
    }

    private static String normalizeDriverCardNumber(String value) {
        return DriverCardNumberNormalizer.canonical(value);
    }
}
