package sd.analysis;

import java.util.HashMap;
import java.util.Map;

import sd.model.VehicleType;

/**
 * Encapsula os dados telemétricos e estatísticos resultantes de uma única execução da simulação.
 * <p>
 * Esta classe atua como um registo estruturado de métricas de desempenho, armazenando
 * dados de latência (tempos de sistema/espera), vazão (throughput) e ocupação de recursos
 * (tamanhos de fila). Os dados aqui contidos servem como base para a análise
 * estatística agregada realizada pelo {@link MultiRunAnalyzer}.
 */
public class SimulationRunResult {
    
    private final int runNumber;
    private final String configurationFile;
    private final long startTimeMillis;
    private final long endTimeMillis;
    
    // Global metrics
    /** Total de veículos instanciados pelos geradores durante a execução. */
    private int totalVehiclesGenerated;
    
    /** Total de veículos que completaram o percurso e saíram do sistema com sucesso. */
    private int totalVehiclesCompleted;
    
    /** Média global do tempo total (em segundos) desde a geração até a saída. */
    private double averageSystemTime;        // seconds
    
    /** Menor tempo de sistema registado (em segundos). */
    private double minSystemTime;            // seconds
    
    /** Maior tempo de sistema registado (em segundos). */
    private double maxSystemTime;            // seconds
    
    /** Média global do tempo (em segundos) que os veículos passaram parados em filas. */
    private double averageWaitingTime;       // seconds
    
    // Per-type metrics
    private final Map<VehicleType, Integer> vehicleCountByType;
    private final Map<VehicleType, Double> avgSystemTimeByType;
    private final Map<VehicleType, Double> avgWaitTimeByType;
    
    // Per-intersection metrics
    private final Map<String, Integer> maxQueueSizeByIntersection;
    private final Map<String, Double> avgQueueSizeByIntersection;
    private final Map<String, Integer> vehiclesProcessedByIntersection;
    
    /**
     * Inicializa um novo contentor de resultados para uma execução específica.
     *
     * @param runNumber O identificador sequencial desta execução.
     * @param configurationFile O ficheiro de configuração utilizado.
     */
    public SimulationRunResult(int runNumber, String configurationFile) {
        this.runNumber = runNumber;
        this.configurationFile = configurationFile;
        this.startTimeMillis = System.currentTimeMillis();
        this.endTimeMillis = 0;
        
        this.vehicleCountByType = new HashMap<>();
        this.avgSystemTimeByType = new HashMap<>();
        this.avgWaitTimeByType = new HashMap<>();
        this.maxQueueSizeByIntersection = new HashMap<>();
        this.avgQueueSizeByIntersection = new HashMap<>();
        this.vehiclesProcessedByIntersection = new HashMap<>();
    }
    
    /**
     * Sinaliza o fim da recolha de dados para esta execução.
     * (Placeholder para lógica de finalização de timestamps).
     */
    public void markCompleted() {
        // This will be called when the run finishes
    }
    
    // Getters
    public int getRunNumber() { return runNumber; }
    public String getConfigurationFile() { return configurationFile; }
    public long getStartTimeMillis() { return startTimeMillis; }
    public long getEndTimeMillis() { return endTimeMillis; }
    
    /**
     * Calcula a duração total da execução em milissegundos.
     * @return Delta entre fim e início.
     */
    public long getDurationMillis() { return endTimeMillis - startTimeMillis; }
    
    public int getTotalVehiclesGenerated() { return totalVehiclesGenerated; }
    public int getTotalVehiclesCompleted() { return totalVehiclesCompleted; }
    public double getAverageSystemTime() { return averageSystemTime; }
    public double getMinSystemTime() { return minSystemTime; }
    public double getMaxSystemTime() { return maxSystemTime; }
    public double getAverageWaitingTime() { return averageWaitingTime; }
    
    /**
     * Retorna o mapeamento de contagem de veículos por tipo.
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<VehicleType, Integer> getVehicleCountByType() { 
        return new HashMap<>(vehicleCountByType); 
    }

    /**
     * Retorna o tempo médio no sistema segmentado por tipo de veículo.
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<VehicleType, Double> getAvgSystemTimeByType() { 
        return new HashMap<>(avgSystemTimeByType); 
    }

    /**
     * Retorna o tempo médio de espera segmentado por tipo de veículo.
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<VehicleType, Double> getAvgWaitTimeByType() { 
        return new HashMap<>(avgWaitTimeByType); 
    }

    /**
     * Retorna o tamanho máximo de fila registado por interseção (gargalos).
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<String, Integer> getMaxQueueSizeByIntersection() { 
        return new HashMap<>(maxQueueSizeByIntersection); 
    }

    /**
     * Retorna o tamanho médio das filas por interseção.
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<String, Double> getAvgQueueSizeByIntersection() { 
        return new HashMap<>(avgQueueSizeByIntersection); 
    }

    /**
     * Retorna o total de veículos processados (throughput) por interseção.
     * @return Uma cópia defensiva do mapa (snapshot).
     */
    public Map<String, Integer> getVehiclesProcessedByIntersection() { 
        return new HashMap<>(vehiclesProcessedByIntersection); 
    }
    
    // Setters
    public void setTotalVehiclesGenerated(int count) { 
        this.totalVehiclesGenerated = count; 
    }
    public void setTotalVehiclesCompleted(int count) { 
        this.totalVehiclesCompleted = count; 
    }
    public void setAverageSystemTime(double time) { 
        this.averageSystemTime = time; 
    }
    public void setMinSystemTime(double time) { 
        this.minSystemTime = time; 
    }
    public void setMaxSystemTime(double time) { 
        this.maxSystemTime = time; 
    }
    public void setAverageWaitingTime(double time) { 
        this.averageWaitingTime = time; 
    }
    
    public void setVehicleCountByType(VehicleType type, int count) {
        vehicleCountByType.put(type, count);
    }
    public void setAvgSystemTimeByType(VehicleType type, double time) {
        avgSystemTimeByType.put(type, time);
    }
    public void setAvgWaitTimeByType(VehicleType type, double time) {
        avgWaitTimeByType.put(type, time);
    }
    public void setMaxQueueSize(String intersection, int size) {
        maxQueueSizeByIntersection.put(intersection, size);
    }
    public void setAvgQueueSize(String intersection, double size) {
        avgQueueSizeByIntersection.put(intersection, size);
    }
    public void setVehiclesProcessed(String intersection, int count) {
        vehiclesProcessedByIntersection.put(intersection, count);
    }
    
    /**
     * Gera uma representação textual resumida das métricas principais da execução.
     * Útil para logs rápidos e debugging.
     */
    @Override
    public String toString() {
        return String.format(
            "Execução #%d [%s]:\n" +
            "  Gerados: %d, Completados: %d (%.1f%%)\n" +
            "  Tempo Médio no Sistema: %.2fs\n" +
            "  Tempo Médio de Espera: %.2fs",
            runNumber,
            configurationFile,
            totalVehiclesGenerated,
            totalVehiclesCompleted,
            totalVehiclesGenerated > 0 ? 100.0 * totalVehiclesCompleted / totalVehiclesGenerated : 0.0,
            averageSystemTime,
            averageWaitingTime
        );
    }
}