package at.procon.eventhub.processing.model;

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

public record UnifiedDriverEventsRequest(
        UnifiedEventSourceFamily sourceFamily,
        List<String> sourceKinds,
        UUID sessionId,
        String driverKey,
        String tenantKey,
        String driverSourceEntityId,
        String driverCardNation,
        String driverCardNumber,
        String vehicleSourceEntityId,
        String vin,
        String registrationNation,
        String registrationNumber,
        OffsetDateTime occurredFrom,
        OffsetDateTime occurredTo
) {
    public UnifiedDriverEventsRequest {
        Objects.requireNonNull(sourceFamily, "sourceFamily must not be null");
        sourceKinds = sourceKinds == null ? List.of() : List.copyOf(sourceKinds);
        driverKey = normalize(driverKey);
        tenantKey = normalize(tenantKey);
        driverSourceEntityId = normalize(driverSourceEntityId);
        driverCardNation = normalizeUpper(driverCardNation);
        driverCardNumber = normalizeDriverCardNumber(driverCardNumber);
        vehicleSourceEntityId = normalize(vehicleSourceEntityId);
        vin = normalizeUpper(vin);
        registrationNation = normalizeUpper(registrationNation);
        registrationNumber = normalize(registrationNumber);
        if (occurredFrom != null && occurredTo != null && occurredTo.isBefore(occurredFrom)) {
            throw new IllegalArgumentException("occurredTo must not be before occurredFrom");
        }
        if (sourceFamily == UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION) {
            Objects.requireNonNull(sessionId, "sessionId must not be null");
        } else {
            if (tenantKey == null) {
                throw new IllegalArgumentException("tenantKey must not be blank");
            }
            if (!hasDriverSelector(driverSourceEntityId, driverCardNumber)
                    && !hasVehicleSelector(vehicleSourceEntityId, vin, registrationNumber)) {
                throw new IllegalArgumentException("At least one driver or vehicle selector must be provided.");
            }
        }
    }

    /**
     * File-session requests may omit driverKey when the caller intentionally wants
     * to load all drivers from the session and partition them later in runtime scope processing.
     */
    public static UnifiedDriverEventsRequest forTachographFileSession(
            UUID sessionId,
            String driverKey,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo
    ) {
        return new UnifiedDriverEventsRequest(
                UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION,
                List.of(),
                sessionId,
                driverKey,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                null,
                occurredFrom,
                occurredTo
        );
    }

    public static UnifiedDriverEventsRequest forTachographDbDriver(
            String tenantKey,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo
    ) {
        return forTachographDbDriver(
                tenantKey,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                occurredFrom,
                occurredTo,
                List.of()
        );
    }

    public static UnifiedDriverEventsRequest forTachographDbDriver(
            String tenantKey,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo,
            List<String> sourceKinds
    ) {
        return new UnifiedDriverEventsRequest(
                UnifiedEventSourceFamily.TACHOGRAPH_DB,
                sourceKinds,
                null,
                null,
                tenantKey,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                null,
                null,
                null,
                null,
                occurredFrom,
                occurredTo
        );
    }

    public static UnifiedDriverEventsRequest forYellowFoxDbVehicle(
            String tenantKey,
            String vehicleSourceEntityId,
            String vin,
            String registrationNation,
            String registrationNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo
    ) {
        return new UnifiedDriverEventsRequest(
                UnifiedEventSourceFamily.YELLOWFOX_DB,
                List.of(),
                null,
                null,
                tenantKey,
                null,
                null,
                null,
                vehicleSourceEntityId,
                vin,
                registrationNation,
                registrationNumber,
                occurredFrom,
                occurredTo
        );
    }

    public static UnifiedDriverEventsRequest forYellowFoxDbDriver(
            String tenantKey,
            String driverSourceEntityId,
            String driverCardNation,
            String driverCardNumber,
            OffsetDateTime occurredFrom,
            OffsetDateTime occurredTo
    ) {
        return new UnifiedDriverEventsRequest(
                UnifiedEventSourceFamily.YELLOWFOX_DB,
                List.of(),
                null,
                null,
                tenantKey,
                driverSourceEntityId,
                driverCardNation,
                driverCardNumber,
                null,
                null,
                null,
                null,
                occurredFrom,
                occurredTo
        );
    }

    public boolean hasDriverSelector() {
        return hasDriverSelector(driverSourceEntityId, driverCardNumber);
    }

    public boolean hasVehicleSelector() {
        return hasVehicleSelector(vehicleSourceEntityId, vin, registrationNumber);
    }

    private static boolean hasDriverSelector(String driverSourceEntityId, String driverCardNumber) {
        return driverSourceEntityId != null || driverCardNumber != null;
    }

    private static boolean hasVehicleSelector(String vehicleSourceEntityId, String vin, String registrationNumber) {
        return vehicleSourceEntityId != null || vin != null || registrationNumber != null;
    }

    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);
    }
}
