package sd.routing;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Implementação da política de roteamento por caminho mais curto.
 * 
 * <p>Esta política sempre escolhe a rota com o menor número de cruzamentos
 * entre o ponto de entrada e a saída. É uma política determinística que
 * não considera o estado da rede (tamanho das filas).</p>
 * 
 * <p>Objetivo: Minimizar a distância teórica percorrida pelos veículos.</p>
 */
public class ShortestPathRouteSelector implements RouteSelector {
    
    /** Rotas possíveis a partir do ponto de entrada E1, ordenadas por comprimento */
    private final List<List<String>> e1Routes;
    /** Rotas possíveis a partir do ponto de entrada E2, ordenadas por comprimento */
    private final List<List<String>> e2Routes;
    /** Rotas possíveis a partir do ponto de entrada E3, ordenadas por comprimento */
    private final List<List<String>> e3Routes;
    
    /**
     * Cria um novo seletor de rotas por caminho mais curto.
     * As rotas são ordenadas por comprimento (número de cruzamentos).
     */
    public ShortestPathRouteSelector() {
        this.e1Routes = new ArrayList<>();
        this.e2Routes = new ArrayList<>();
        this.e3Routes = new ArrayList<>();
        initializeRoutes();
    }
    
    /**
     * Inicializa as rotas possíveis para cada ponto de entrada.
     * As rotas são organizadas da mais curta para a mais longa.
     */
    private void initializeRoutes() {
        // Rotas de E1 (entrada Norte) - ordenadas por comprimento
        e1Routes.add(Arrays.asList("Cr1", "Cr2", "Cr3", "S"));          // 4 nós
        e1Routes.add(Arrays.asList("Cr1", "Cr2", "Cr5", "S"));          // 4 nós
        e1Routes.add(Arrays.asList("Cr1", "Cr4", "Cr5", "S"));          // 4 nós
        
        // Rotas de E2 (entrada Oeste) - ordenadas por comprimento
        e2Routes.add(Arrays.asList("Cr2", "Cr3", "S"));                 // 3 nós (mais curta!)
        e2Routes.add(Arrays.asList("Cr2", "Cr5", "S"));                 // 3 nós
        e2Routes.add(Arrays.asList("Cr2", "Cr1", "Cr4", "Cr5", "S"));  // 5 nós
        
        // Rotas de E3 (entrada Sul) - ordenadas por comprimento
        e3Routes.add(Arrays.asList("Cr3", "S"));                        // 2 nós (mais curta!)
        e3Routes.add(Arrays.asList("Cr3", "Cr2", "Cr5", "S"));         // 4 nós
        e3Routes.add(Arrays.asList("Cr3", "Cr2", "Cr1", "Cr4", "Cr5", "S")); // 6 nós
    }
    
    @Override
    public List<String> selectRoute(String entryPoint, Map<String, Integer> queueSizes) {
        // Ignora queueSizes - política baseada apenas no comprimento do caminho
        
        List<List<String>> availableRoutes = getRoutesForEntryPoint(entryPoint);
        
        // Retorna a rota mais curta (primeira da lista)
        List<String> shortestRoute = availableRoutes.get(0);
        
        return new ArrayList<>(shortestRoute);
    }
    
    /**
     * Obtém as rotas disponíveis para um ponto de entrada.
     * 
     * @param entryPoint ponto de entrada (E1, E2 ou E3)
     * @return lista de rotas ordenadas por comprimento
     */
    private List<List<String>> getRoutesForEntryPoint(String entryPoint) {
        switch (entryPoint.toUpperCase()) {
            case "E1":
                return e1Routes;
            case "E2":
                return e2Routes;
            case "E3":
                return e3Routes;
            default:
                System.err.printf("Unknown entry point: %s, defaulting to E1%n", entryPoint);
                return e1Routes;
        }
    }
}
