package at.procon.eventhub.processing.dto;

import at.procon.eventhub.processing.eventprocessing.dto.RuntimeEventProcessingPartitionResultDto;
import at.procon.eventhub.processing.eventprocessing.dto.RuntimeEventProcessingResultDto;
import at.procon.eventhub.processing.model.UnifiedDiscoveredVehicleRef;
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public record UnifiedRuntimeTachographEsperScopeResultDto(
        UnifiedRuntimeProcessingRequest request,
        int inputEventCount,
        int selectedDriverCount,
        int discoveredVehicleCount,
        List<UnifiedDiscoveredVehicleRef> discoveredVehicles,
        Map<String, UnifiedRuntimeDerivedProjectionResultDto> driverResults,
        Map<String, RuntimeDriverPartitionDebugDto> partitionDebugByDriver,
        List<String> notes,
        List<String> warnings
) {
    public UnifiedRuntimeTachographEsperScopeResultDto {
        discoveredVehicles = discoveredVehicles == null ? List.of() : List.copyOf(discoveredVehicles);
        driverResults = driverResults == null ? Map.of() : Collections.unmodifiableMap(new LinkedHashMap<>(driverResults));
        partitionDebugByDriver = partitionDebugByDriver == null ? Map.of() : Collections.unmodifiableMap(new LinkedHashMap<>(partitionDebugByDriver));
        notes = notes == null ? List.of() : List.copyOf(notes);
        warnings = warnings == null ? List.of() : List.copyOf(warnings);
    }

    public static UnifiedRuntimeTachographEsperScopeResultDto fromDriverWorkingTime(
            UnifiedRuntimeDriverWorkingTimeScopeResultDto result
    ) {
        if (result == null) {
            return null;
        }
        return new UnifiedRuntimeTachographEsperScopeResultDto(
                result.request(),
                result.inputEventCount(),
                result.selectedDriverCount(),
                result.discoveredVehicleCount(),
                result.discoveredVehicles(),
                result.driverResults(),
                result.partitionDebugByDriver(),
                result.notes(),
                result.warnings()
        );
    }

    public static UnifiedRuntimeTachographEsperScopeResultDto fromGenericRuntimeEventProcessingResult(
            RuntimeEventProcessingResultDto genericResult
    ) {
        if (genericResult == null) {
            throw new IllegalArgumentException("genericResult must not be null");
        }
        LinkedHashMap<String, UnifiedRuntimeDerivedProjectionResultDto> driverResults = new LinkedHashMap<>();
        for (Map.Entry<String, RuntimeEventProcessingPartitionResultDto> entry : genericResult.partitionResults().entrySet()) {
            Object value = entry.getValue().result();
            if (value instanceof UnifiedRuntimeDerivedProjectionResultDto projectionResult) {
                driverResults.put(entry.getKey(), projectionResult);
            } else {
                throw new IllegalArgumentException("Cannot convert generic partition result for key "
                        + entry.getKey() + " to UnifiedRuntimeDerivedProjectionResultDto: "
                        + (value == null ? "null" : value.getClass().getName()));
            }
        }
        return new UnifiedRuntimeTachographEsperScopeResultDto(
                genericResult.request(),
                genericResult.inputEventCount(),
                genericResult.selectedPartitionCount(),
                genericResult.discoveredVehicleCount(),
                genericResult.discoveredVehicles(),
                driverResults,
                extractPartitionDebug(genericResult),
                genericResult.notes(),
                genericResult.warnings()
        );
    }

    private static Map<String, RuntimeDriverPartitionDebugDto> extractPartitionDebug(
            RuntimeEventProcessingResultDto genericResult
    ) {
        LinkedHashMap<String, RuntimeDriverPartitionDebugDto> debugByDriver = new LinkedHashMap<>();
        for (Map.Entry<String, RuntimeEventProcessingPartitionResultDto> entry : genericResult.partitionResults().entrySet()) {
            Object debug = entry.getValue().metadata().get("partitionDebug");
            if (debug instanceof RuntimeDriverPartitionDebugDto partitionDebug) {
                debugByDriver.put(entry.getKey(), partitionDebug);
            }
        }
        return debugByDriver;
    }

}
