# 🚚 **SISTEMA DE ROTEIRIZAÇÃO TSP - EXPO REACT NATIVE**

## **📋 VISÃO GERAL**

Sistema completo de otimização de rotas de entrega implementando o algoritmo **Traveling Salesman Problem (TSP)** usando **Nearest Neighbor** para organizar entregas pela distância mais eficiente.

**URL Base da API:** `https://api.entrega.homologacao.jurunense.com`

---

## **🏗️ ARQUITETURA DO SISTEMA**

### **Estrutura de Arquivos**
```
src/
├── screens/
│   └── main/
│       └── RoutingScreen.tsx          # Tela principal de roteirização
├── services/
│   └── api.ts                         # Serviços de API e algoritmos TSP
├── types/
│   └── index.ts                       # Tipos TypeScript
├── contexts/
│   └── AuthContext.tsx                # Contexto de autenticação
└── config/
    └── env.ts                         # Configurações de ambiente
```

### **Componentes Principais**
- **RoutingScreen**: Interface para execução de roteirização
- **ApiService**: Classe para comunicação com API
- **Algoritmos TSP**: Funções de otimização de rota

---

## **🔧 IMPLEMENTAÇÃO PASSO A PASSO**

### **PASSO 1: CONFIGURAÇÃO DE AMBIENTE**

```typescript
// src/config/env.ts
export const API_BASE_URL = 'https://api.entrega.homologacao.jurunense.com';
export const AUTH_TOKEN_KEY = 'AUTH_TOKEN';
export const USER_DATA_KEY = 'USER_DATA';

// Função para converter coordenadas (vírgula → ponto)
export const convertCoordinate = (coord: any): number => {
  if (coord === null || coord === undefined || coord === '') {
    return 0;
  }
  
  if (typeof coord === 'number') {
    return coord;
  }
  
  if (typeof coord === 'string') {
    const normalized = coord.trim().replace(',', '.');
    const parsed = parseFloat(normalized);
    return isNaN(parsed) ? 0 : parsed;
  }
  
  return 0;
};
```

### **PASSO 2: TIPOS TYPESCRIPT**

```typescript
// src/types/index.ts
export interface Delivery {
  id?: string;
  outId: number;
  customerId: number;
  customerName: string;
  street: string;
  streetNumber: string;
  neighborhood: string;
  city: string;
  state: string;
  zipCode: string;
  lat: number | string | null;
  lng: number | string | null;
  coordinates?: {
    latitude: number | string;
    longitude: number | string;
  };
  deliverySeq: number;
  routing: number; // 0 = não roteirizada, 1 = roteirizada
  status: 'pending' | 'in_progress' | 'delivered' | 'failed';
  outDate: string;
  latFrom?: string;
  lngFrom?: string;
}

export interface RoutingData {
  outId: number;
  customerId: number;
  deliverySeq: number;
  lat: number;
  lng: number;
}
```

### **PASSO 3: FUNÇÕES UTILITÁRIAS**

```typescript
// src/services/api.ts

// 1. Cálculo de distância (Fórmula de Haversine)
export const calculateDistance = (lat1: number, lon1: number, lat2: number, lon2: number): number => {
  const R = 6371; // Raio da Terra em km
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * 
    Math.sin(dLon/2) * Math.sin(dLon/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  return R * c;
};

// 2. Centro de distribuição dinâmico
export const getDistributionCenter = (deliveries: Delivery[]): { 
  latitude: number; 
  longitude: number; 
  address: string 
} => {
  const deliveryWithCoords = deliveries.find(delivery => 
    delivery.latFrom && delivery.lngFrom && 
    delivery.latFrom !== 'null' && delivery.lngFrom !== 'null' &&
    delivery.latFrom !== '' && delivery.lngFrom !== ''
  );

  if (deliveryWithCoords && deliveryWithCoords.latFrom && deliveryWithCoords.lngFrom) {
    const lat = parseFloat(deliveryWithCoords.latFrom);
    const lng = parseFloat(deliveryWithCoords.lngFrom);
    
    if (!isNaN(lat) && !isNaN(lng)) {
      return {
        latitude: lat,
        longitude: lng,
        address: "Centro de Distribuição (API)"
      };
    }
  }

  // Fallback para coordenadas padrão
  return {
    latitude: -1.3654,
    longitude: -48.3722,
    address: "Centro de Distribuição (Padrão)"
  };
};
```

### **PASSO 4: ALGORITMO TSP - NEAREST NEIGHBOR**

```typescript
// src/services/api.ts

const nearestNeighborTSP = (distanceMatrix: number[][], deliveries: Delivery[]): Delivery[] => {
  console.log('=== 🔍 EXECUTANDO ALGORITMO NEAREST NEIGHBOR ===');
  
  const n = deliveries.length;
  const visited = new Array(n).fill(false);
  const route: Delivery[] = [];
  
  // Começar do centro de distribuição (índice 0 na matriz)
  let currentIndex = 0;
  visited[0] = true;
  
  // Adicionar primeira entrega (mais próxima do centro)
  if (n > 0) {
    route.push(deliveries[0]);
    console.log(`📍 Primeira entrega: ${deliveries[0].customerName} (mais próxima do centro)`);
  }
  
  // Encontrar o próximo ponto mais próximo
  for (let step = 1; step < n; step++) {
    let minDistance = Infinity;
    let nextIndex = -1;
    
    // Procurar o ponto não visitado mais próximo
    for (let i = 1; i < n; i++) { // Pular índice 0 (centro de distribuição)
      if (!visited[i]) {
        const distance = distanceMatrix[currentIndex][i];
        if (distance < minDistance) {
          minDistance = distance;
          nextIndex = i;
        }
      }
    }
    
    if (nextIndex !== -1) {
      visited[nextIndex] = true;
      route.push(deliveries[nextIndex]);
      console.log(`📍 Próxima entrega: ${deliveries[nextIndex].customerName} (distância: ${minDistance.toFixed(2)} km)`);
      currentIndex = nextIndex;
    }
  }
  
  console.log(`✅ Rota otimizada criada com ${route.length} entregas`);
  return route;
};
```

### **PASSO 5: FUNÇÃO PRINCIPAL DE OTIMIZAÇÃO**

```typescript
// src/services/api.ts

export const optimizeRouteWithTSP = async (deliveries: Delivery[]): Promise<Delivery[]> => {
  console.log('=== 🚚 INICIANDO OTIMIZAÇÃO DE ROTA COM ALGORITMO TSP ===');
  console.log('Total de entregas para otimizar:', deliveries.length);

  // 1. Obter centro de distribuição
  const distributionCenter = getDistributionCenter(deliveries);
  console.log('Centro usado:', distributionCenter);

  // 2. Preparar entregas garantindo coordenadas
  const preparedDeliveries: Delivery[] = [];
  for (let index = 0; index < deliveries.length; index++) {
    const delivery = deliveries[index];

    let latNum: number | null = null;
    let lngNum: number | null = null;

    // Tentar usar lat/lng já existentes
    if (typeof delivery.lat === 'number' && typeof delivery.lng === 'number' && 
        !isNaN(delivery.lat) && !isNaN(delivery.lng)) {
      latNum = delivery.lat;
      lngNum = delivery.lng;
    }

    // Normalizar strings (vírgula → ponto)
    if ((latNum === null || lngNum === null) && 
        (typeof delivery.lat === 'string' || typeof delivery.lng === 'string')) {
      const maybeLat = convertCoordinate(delivery.lat);
      const maybeLng = convertCoordinate(delivery.lng);
      if (typeof maybeLat === 'number' && !isNaN(maybeLat)) latNum = maybeLat;
      if (typeof maybeLng === 'number' && !isNaN(maybeLng)) lngNum = maybeLng;
    }

    // Usar coordinates se existirem
    if ((latNum === null || lngNum === null) && delivery.coordinates) {
      const maybeLat = convertCoordinate((delivery.coordinates as any).latitude);
      const maybeLng = convertCoordinate((delivery.coordinates as any).longitude);
      if (typeof maybeLat === 'number' && !isNaN(maybeLat)) latNum = maybeLat;
      if (typeof maybeLng === 'number' && !isNaN(maybeLng)) lngNum = maybeLng;
    }

    // 4. Se ainda não tem coordenadas, tentar geocodificar
    if (latNum === null || lngNum === null) {
      try {
        const coords = await getCoordinatesFromAddress({
          address: delivery.street || '',
          addressNumber: delivery.streetNumber || '',
          neighborhood: delivery.neighborhood || '',
          city: delivery.city || '',
          state: delivery.state || ''
        });
        if (coords) {
          latNum = coords.latitude;
          lngNum = coords.longitude;
          console.log('✅ Geolocalização obtida:', coords);
        }
      } catch (geoErr) {
        console.warn('⚠️ Falha ao geolocalizar:', geoErr);
      }
    }

    preparedDeliveries.push({
      ...delivery,
      lat: typeof latNum === 'number' ? latNum : delivery.lat,
      lng: typeof lngNum === 'number' ? lngNum : delivery.lng,
      coordinates: (typeof latNum === 'number' && typeof lngNum === 'number')
        ? { latitude: latNum, longitude: lngNum }
        : delivery.coordinates
    });
  }

  // 3. Separar entregas com e sem coordenadas
  const withCoords = preparedDeliveries.filter(d => 
    typeof d.lat === 'number' && typeof d.lng === 'number' && 
    !isNaN(d.lat as number) && !isNaN(d.lng as number)
  );
  const withoutCoords = preparedDeliveries.filter(d => 
    !(typeof d.lat === 'number' && typeof d.lng === 'number' && 
      !isNaN(d.lat as number) && !isNaN(d.lng as number))
  );

  if (withCoords.length === 0) {
    console.log('❌ Nenhuma entrega com coordenadas válidas');
    return preparedDeliveries.map((d, i) => ({ ...d, deliverySeq: i + 1 }));
  }

  console.log(`✅ ${withCoords.length} entregas com coordenadas válidas`);

  // 4. Calcular matriz de distâncias
  const distanceMatrix: number[][] = [];
  const allPoints = [distributionCenter, ...withCoords.map(d => ({
    latitude: d.lat as number,
    longitude: d.lng as number
  }))];

  for (let i = 0; i < allPoints.length; i++) {
    distanceMatrix[i] = [];
    for (let j = 0; j < allPoints.length; j++) {
      if (i === j) {
        distanceMatrix[i][j] = 0;
      } else {
        distanceMatrix[i][j] = calculateDistance(
          allPoints[i].latitude,
          allPoints[i].longitude,
          allPoints[j].latitude,
          allPoints[j].longitude
        );
      }
    }
  }

  // 5. Executar algoritmo TSP
  const optimizedWithCoords = nearestNeighborTSP(distanceMatrix, withCoords);

  // 6. Montar rota final
  const finalRoute: Delivery[] = [...optimizedWithCoords, ...withoutCoords];

  // 7. Aplicar deliverySeq sequencialmente
  const finalDeliveries = finalRoute.map((delivery, idx) => {
    const newSeq = idx + 1; // Garantir que comece em 1
    console.log(`🔄 Atualizando ${delivery.customerName}: deliverySeq ${delivery.deliverySeq} → ${newSeq}`);
    return { ...delivery, deliverySeq: newSeq, distance: (delivery as any).distance || 0 };
  });

  console.log('=== 🎯 ENTREGAS COM DELIVERYSEQ ATUALIZADO ===');
  finalDeliveries.forEach((delivery, index) => {
    console.log(`📦 Entrega ${index + 1} (deliverySeq: ${delivery.deliverySeq}): ${delivery.customerName}`);
  });

  return finalDeliveries;
};
```

### **PASSO 6: SERVIÇO DE API**

```typescript
// src/services/api.ts

class ApiService {
  private baseUrl: string;
  private token: string | null = null;

  constructor() {
    this.baseUrl = 'https://api.entrega.homologacao.jurunense.com';
    this.loadToken();
  }

  // Enviar ordem de roteamento
  async sendRoutingOrder(routingData: RoutingData[]): Promise<any> {
    try {
      console.log('=== DEBUG: INICIANDO sendRoutingOrder ===');
      console.log('Dados recebidos:', JSON.stringify(routingData, null, 2));
      
      // Validar e normalizar coordenadas
      const validatedRoutingData = routingData.map((item, index) => {
        let lat: any = item.lat;
        let lng: any = item.lng;
        
        // Converter strings com vírgula para ponto
        if (typeof lat === 'string') {
          lat = parseFloat(lat.replace(',', '.'));
          if (isNaN(lat)) {
            console.warn(`⚠️ Coordenada lat inválida: ${item.lat}, usando 0`);
            lat = 0;
          }
        }
        
        if (typeof lng === 'string') {
          lng = parseFloat(lng.replace(',', '.'));
          if (isNaN(lng)) {
            console.warn(`⚠️ Coordenada lng inválida: ${item.lng}, usando 0`);
            lng = 0;
          }
        }
        
        // Garantir que sejam números
        lat = Number(lat) || 0;
        lng = Number(lng) || 0;
        
        return { ...item, lat, lng };
      });
      
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      
      const ENDPOINT = `${this.baseUrl}/v1/driver/routing`;
      const headers = {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      };
      
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers,
        body: JSON.stringify(validatedRoutingData)
      });
      
      if (response.status === 401) {
        throw new Error('Sessão expirada. Faça login novamente.');
      }
      
      const result = await response.json();
      
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao enviar ordem de roteamento');
      }
      
      console.log('✅ Roteirização bem-sucedida');
      return result.data;
    } catch (error) {
      console.error('❌ Erro em sendRoutingOrder:', error);
      throw error;
    }
  }

  // Carregar entregas
  async getDeliveries(): Promise<Delivery[]> {
    try {
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      
      const response = await fetch(`${this.baseUrl}/v1/driver/deliveries`, {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      });
      
      if (response.status === 401) {
        throw new Error('Sessão expirada');
      }
      
      const result = await response.json();
      return Array.isArray(result) ? result : [];
    } catch (error) {
      console.error('❌ Erro ao carregar entregas:', error);
      throw error;
    }
  }

  private async loadToken(): Promise<string | null> {
    try {
      const storedToken = await AsyncStorage.getItem(AUTH_TOKEN_KEY);
      if (storedToken) {
        this.token = storedToken;
        return storedToken;
      }
      return null;
    } catch (error) {
      console.error("Erro ao carregar token:", error);
      return null;
    }
  }
}

export const api = new ApiService();
```

### **PASSO 7: TELA PRINCIPAL DE ROTEIRIZAÇÃO**

```typescript
// src/screens/main/RoutingScreen.tsx

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  ActivityIndicator,
  Alert,
  RefreshControl
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import { COLORS, SHADOWS } from '../../constants/theme';
import { Delivery } from '../../types';
import { api, optimizeRouteWithTSP } from '../../services/api';

const RoutingScreen: React.FC<{ navigation: any; route: any }> = ({ navigation, route }) => {
  const [deliveries, setDeliveries] = useState<Delivery[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isRouting, setIsRouting] = useState(false);
  const [routingProgress, setRoutingProgress] = useState(0);
  const [error, setError] = useState<string | null>(null);

  // Carregar entregas iniciais
  useEffect(() => {
    loadDeliveries();
  }, []);

  // Carregar entregas do endpoint
  const loadDeliveries = async () => {
    try {
      setIsLoading(true);
      setError(null);
      
      const response = await api.getDeliveries();
      
      if (response) {
        const deliveriesData = Array.isArray(response) ? response : [];
        console.log('📦 Entregas processadas:', deliveriesData.length);
        
        // Ordenar entregas usando algoritmo TSP
        try {
          const sortedDeliveries = await optimizeRouteWithTSP(deliveriesData);
          console.log('✅ Entregas ordenadas com sucesso:', sortedDeliveries.length);
          setDeliveries(sortedDeliveries);
          
          // Verificar se já tem roteirização
          const hasRouting = deliveriesData.some((delivery: Delivery) => delivery.routing === 1);
          if (hasRouting) {
            console.log('✅ Já tem roteirização - Redirecionando');
            navigation.reset({
              index: 0,
              routes: [{ name: 'Main' as never }],
            });
          }
        } catch (sortError) {
          console.error('❌ Erro ao ordenar entregas:', sortError);
          setDeliveries(deliveriesData);
        }
      }
    } catch (error: any) {
      console.error('❌ Erro ao carregar entregas:', error);
      setError(error.message || 'Erro ao carregar entregas');
    } finally {
      setIsLoading(false);
    }
  };

  // Executar roteirização
  const executeRouting = async () => {
    try {
      setIsRouting(true);
      setRoutingProgress(0);
      setError(null);

      // Filtrar entregas sem roteirização
      const deliveriesToRoute = deliveries.filter(delivery => delivery.routing === 0);
      
      if (deliveriesToRoute.length === 0) {
        Alert.alert('Info', 'Todas as entregas já estão roteirizadas');
        return;
      }

      setRoutingProgress(20);

      // SOLUÇÃO DEFINITIVA: OTIMIZAR ROTA ANTES DE ENVIAR PARA API
      console.log('🎯 OTIMIZANDO ROTA COM ALGORITMO TSP ANTES DO ENVIO...');
      
      const optimizedDeliveries = await optimizeRouteWithTSP(deliveriesToRoute);
      console.log('✅ Rota otimizada com sucesso');
      
      if (optimizedDeliveries && optimizedDeliveries.length > 0) {
        // Preparar dados OTIMIZADOS para roteirização
        const optimizedRoutingData = optimizedDeliveries.map((delivery) => ({
          outId: delivery.outId,
          customerId: delivery.customerId,
          deliverySeq: delivery.deliverySeq, // JÁ OTIMIZADO (1, 2, 3, ...)
          lat: delivery.lat as number,
          lng: delivery.lng as number
        }));
        
        setRoutingProgress(60);
        
        // Executar roteirização com dados OTIMIZADOS
        const routingResponse = await api.sendRoutingOrder(optimizedRoutingData);
        
        setRoutingProgress(80);
        
        if (routingResponse) {
          console.log('✅ Roteirização com sequência otimizada executada com sucesso!');
          
          // Atualizar estado local
          setDeliveries(optimizedDeliveries);
          
          setRoutingProgress(100);
          
          Alert.alert(
            'Roteirização Concluída! 🎉',
            `As entregas foram organizadas e ordenadas com sucesso!\n\nTotal: ${optimizedDeliveries.length} entregas\nPróxima: ${optimizedDeliveries[0]?.customerName || 'N/A'}`,
            [
              {
                text: 'OK',
                onPress: () => {
                  navigation.reset({
                    index: 0,
                    routes: [{ 
                      name: 'Main' as never,
                      params: {
                        screen: 'Home',
                        params: {
                          routingUpdated: true,
                          refreshDeliveries: true
                        }
                      }
                    }],
                  });
                }
              }
            ]
          );
        }
      }
    } catch (error: any) {
      console.error('Erro na roteirização:', error);
      setError(error.message || 'Erro ao executar roteirização');
      Alert.alert('Erro', 'Falha na roteirização. Tente novamente.');
    } finally {
      setIsRouting(false);
      setRoutingProgress(0);
    }
  };

  // Refresh control
  const onRefresh = async () => {
    try {
      await loadDeliveries();
    } catch (error: any) {
      console.error('Erro no refresh:', error);
    }
  };

  if (isLoading) {
    return (
      <View style={styles.loadingContainer}>
        <ActivityIndicator size="large" color={COLORS.primary} />
        <Text style={styles.loadingText}>Carregando entregas...</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      {/* Header */}
      <LinearGradient colors={[COLORS.primary, COLORS.primary]} style={styles.header}>
        <TouchableOpacity
          style={styles.backButton}
          onPress={() => navigation.reset({
            index: 0,
            routes: [{ name: 'Main' as never }],
          })}
        >
          <Ionicons name="arrow-back" size={24} color="white" />
        </TouchableOpacity>
        
        <Text style={styles.headerTitle}>Roteirização de Entregas</Text>
        
        <TouchableOpacity style={styles.refreshButton} onPress={onRefresh}>
          <Ionicons name="refresh" size={24} color="white" />
        </TouchableOpacity>
      </LinearGradient>

      {/* Conteúdo */}
      <ScrollView style={styles.content} refreshControl={
        <RefreshControl refreshing={false} onRefresh={onRefresh} />
      }>
        {/* Resumo */}
        <View style={styles.summaryCard}>
          <Text style={styles.summaryTitle}>Resumo das Entregas</Text>
          <View style={styles.summaryStats}>
            <View style={styles.statItem}>
              <Text style={styles.statNumber}>{deliveries.length}</Text>
              <Text style={styles.statLabel}>Total</Text>
            </View>
            <View style={styles.statItem}>
              <Text style={styles.statNumber}>
                {deliveries.filter(d => d.routing === 0).length}
              </Text>
              <Text style={styles.statLabel}>Pendentes</Text>
            </View>
            <View style={styles.statItem}>
              <Text style={styles.statNumber}>
                {deliveries.filter(d => d.routing === 1).length}
              </Text>
              <Text style={styles.statLabel}>Roteirizadas</Text>
            </View>
          </View>
          
          {/* Informações de Ordenação */}
          {deliveries.length > 0 && (
            <View style={styles.orderingInfo}>
              <Text style={styles.orderingTitle}>📍 Ordenação por Sequência</Text>
              <Text style={styles.orderingText}>
                Próxima entrega: {deliveries[0]?.customerName || 'N/A'}
              </Text>
              <Text style={styles.orderingText}>
                Sequência: #{deliveries[0]?.deliverySeq || 'N/A'}
              </Text>
              {deliveries[0]?.distance && (
                <Text style={styles.orderingText}>
                  Distância: {deliveries[0].distance.toFixed(2)} km
                </Text>
              )}
            </View>
          )}
        </View>

        {/* Botão de Roteirização */}
        {deliveries.some(d => d.routing === 0) && (
          <TouchableOpacity
            style={[styles.routingButton, isRouting && styles.routingButtonDisabled]}
            onPress={executeRouting}
            disabled={isRouting}
          >
            <LinearGradient
              colors={isRouting ? [COLORS.textLight, COLORS.textLight] : [COLORS.success, '#059669']}
              style={styles.routingButtonGradient}
            >
              {isRouting ? (
                <View style={styles.routingProgress}>
                  <ActivityIndicator size="small" color="white" />
                  <Text style={styles.routingProgressText}>
                    Roteirizando... {routingProgress}%
                  </Text>
                </View>
              ) : (
                <>
                  <Ionicons name="map" size={24} color="white" />
                  <Text style={styles.routingButtonText}>
                    Executar Roteirização
                  </Text>
                </>
              )}
            </LinearGradient>
          </TouchableOpacity>
        )}

        {/* Lista de Entregas */}
        <View style={styles.deliveriesSection}>
          <Text style={styles.sectionTitle}>
            Entregas ({deliveries.length})
          </Text>
          
          {deliveries.map((delivery, index) => (
            <View key={delivery.id || index} style={styles.deliveryItem}>
              <View style={styles.deliveryHeader}>
                <Text style={styles.deliveryNumber}>
                  #{delivery.outId}
                </Text>
                <View style={[styles.statusBadge, { backgroundColor: getStatusColor(delivery.status) }]}>
                  <Text style={styles.statusText}>
                    {getStatusText(delivery.status)}
                  </Text>
                </View>
              </View>
              
              <Text style={styles.customerName}>
                {delivery.customerName}
              </Text>
              
              <Text style={styles.address}>
                {delivery.street}, {delivery.streetNumber}
              </Text>
              
              <View style={styles.deliveryMeta}>
                <View style={styles.metaItem}>
                  <Ionicons name="location" size={16} color={COLORS.textLight} />
                  <Text style={styles.metaText}>
                    {delivery.neighborhood}, {delivery.city}
                  </Text>
                </View>
                
                <View style={styles.metaItem}>
                  <Ionicons name="time" size={16} color={COLORS.textLight} />
                  <Text style={styles.metaText}>
                    {delivery.routing === 0 ? 'Aguardando roteirização' : 'Roteirizada'}
                  </Text>
                </View>
              </View>
            </View>
          ))}
        </View>

        {/* Mensagem de erro */}
        {error && (
          <View style={styles.errorContainer}>
            <Ionicons name="alert-circle" size={24} color={COLORS.danger} />
            <Text style={styles.errorText}>{error}</Text>
          </View>
        )}
      </ScrollView>
    </View>
  );
};

// Funções auxiliares
const getStatusColor = (status: string) => {
  switch (status) {
    case 'delivered': return COLORS.success;
    case 'in_progress': return COLORS.info;
    case 'failed': return COLORS.danger;
    default: return COLORS.warning;
  }
};

const getStatusText = (status: string) => {
  switch (status) {
    case 'delivered': return 'Entregue';
    case 'in_progress': return 'Em andamento';
    case 'failed': return 'Falhou';
    default: return 'Pendente';
  }
};

// Estilos (implementar conforme necessário)
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5F5F5',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingTop: 50,
    paddingBottom: 20,
    paddingHorizontal: 20,
  },
  backButton: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: 'rgba(255, 255, 255, 0.2)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: 'white',
    flex: 1,
    textAlign: 'center',
  },
  refreshButton: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: 'rgba(255, 255, 255, 0.2)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  content: {
    flex: 1,
    padding: 20,
  },
  summaryCard: {
    backgroundColor: 'white',
    borderRadius: 12,
    padding: 20,
    marginBottom: 20,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  summaryTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#333',
    marginBottom: 16,
  },
  summaryStats: {
    flexDirection: 'row',
    justifyContent: 'space-around',
  },
  statItem: {
    alignItems: 'center',
  },
  statNumber: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#007AFF',
  },
  statLabel: {
    fontSize: 12,
    color: '#666',
    marginTop: 4,
  },
  routingButton: {
    marginBottom: 20,
    borderRadius: 12,
    overflow: 'hidden',
  },
  routingButtonDisabled: {
    opacity: 0.7,
  },
  routingButtonGradient: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    paddingVertical: 16,
    paddingHorizontal: 24,
  },
  routingButtonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
    marginLeft: 8,
  },
  routingProgress: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  routingProgressText: {
    color: 'white',
    fontSize: 14,
    fontWeight: '500',
    marginLeft: 8,
  },
  deliveriesSection: {
    marginBottom: 20,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    color: '#333',
    marginBottom: 16,
  },
  deliveryItem: {
    backgroundColor: 'white',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.05,
    shadowRadius: 2,
    elevation: 2,
  },
  deliveryHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 8,
  },
  deliveryNumber: {
    fontSize: 14,
    fontWeight: '600',
    color: '#007AFF',
  },
  statusBadge: {
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 8,
  },
  statusText: {
    fontSize: 10,
    fontWeight: '500',
    color: 'white',
  },
  customerName: {
    fontSize: 16,
    fontWeight: '600',
    color: '#333',
    marginBottom: 4,
  },
  address: {
    fontSize: 14,
    color: '#666',
    marginBottom: 8,
  },
  deliveryMeta: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  metaItem: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  metaText: {
    fontSize: 12,
    color: '#666',
    marginLeft: 4,
  },
  loadingContainer: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#F5F5F5',
  },
  loadingText: {
    marginTop: 16,
    fontSize: 16,
    color: '#333',
  },
  errorContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#FEE2E2',
    padding: 16,
    borderRadius: 12,
    marginTop: 20,
  },
  errorText: {
    marginLeft: 8,
    fontSize: 14,
    color: '#DC2626',
    flex: 1,
  },
  orderingInfo: {
    marginTop: 16,
    padding: 16,
    backgroundColor: '#E0F2FE',
    borderRadius: 8,
    borderLeftWidth: 4,
    borderLeftColor: '#007AFF',
  },
  orderingTitle: {
    fontSize: 14,
    fontWeight: '600',
    color: '#007AFF',
    marginBottom: 8,
  },
  orderingText: {
    fontSize: 12,
    color: '#666',
    marginBottom: 4,
  },
});

export default RoutingScreen;
```

---

## **🚀 FLUXO COMPLETO DE ROTEIRIZAÇÃO**

### **1. CARREGAMENTO INICIAL**
- ✅ Carregar entregas da API (`/v1/driver/deliveries`)
- ✅ Verificar se já tem roteirização (`routing === 1`)
- ✅ Se sim → redirecionar para Home
- ✅ Se não → mostrar tela de roteirização

### **2. EXECUÇÃO DE ROTEIRIZAÇÃO**
- ✅ Filtrar entregas pendentes (`routing === 0`)
- ✅ **OTIMIZAR ROTA COM TSP** (antes de enviar para API)
- ✅ Preparar dados otimizados
- ✅ Enviar para API com `deliverySeq` já otimizado
- ✅ Atualizar estado local
- ✅ Redirecionar para Home

### **3. ALGORITMO TSP**
- ✅ Obter centro de distribuição
- ✅ Preparar coordenadas (normalizar + geolocalizar)
- ✅ Calcular matriz de distâncias
- ✅ Executar Nearest Neighbor
- ✅ Aplicar sequência sequencial (1, 2, 3, ...)

---

## ** PONTOS CRÍTICOS DE IMPLEMENTAÇÃO**

### **1. ORDEM DE EXECUÇÃO CORRETA**
```typescript
// ❌ ERRADO: Enviar para API primeiro
await api.sendRoutingOrder(routingData);
const optimized = await optimizeRouteWithTSP(deliveries);

// ✅ CORRETO: Otimizar primeiro, depois enviar
const optimized = await optimizeRouteWithTSP(deliveries);
await api.sendRoutingOrder(optimizedRoutingData);
```

### **2. NORMALIZAÇÃO DE COORDENADAS**
```typescript
// Sempre converter vírgula para ponto
const lat = parseFloat(coord.replace(',', '.'));
```

### **3. SEQUÊNCIA INICIAL**
```typescript
// Garantir que deliverySeq comece em 1, não em 0
const newSeq = idx + 1; // ✅ Correto
const newSeq = idx;      // ❌ Errado (começa em 0)
```

### **4. TRATAMENTO DE ERROS**
```typescript
try {
  // Lógica principal
} catch (error: any) {
  console.error('Erro detalhado:', error);
  // Sempre reabilitar botões e mostrar feedback
} finally {
  // Limpeza obrigatória
  setIsRouting(false);
  setRoutingProgress(0);
}
```

---

## **📱 DEPENDÊNCIAS NECESSÁRIAS**

```json
{
  "dependencies": {
    "@react-native-async-storage/async-storage": "^1.19.0",
    "expo-linear-gradient": "^12.0.0",
    "@expo/vector-icons": "^13.0.0",
    "react-native-safe-area-context": "^4.7.0"
  }
}
```

---

## **🔗 ENDPOINTS DA API**

### **Base URL:** `https://api.entrega.homologacao.jurunense.com`

| Endpoint | Método | Descrição |
|----------|--------|-----------|
| `/v1/driver/deliveries` | GET | Carregar lista de entregas |
| `/v1/driver/routing` | POST | Enviar ordem de roteirização |
| `/v1/geolocation/google` | GET | Geocodificar endereços |

---

## **📊 ESTRUTURA DE DADOS**

### **Entrada da API (sendRoutingOrder)**
```json
[
  {
    "outId": 3673,
    "customerId": 422973,
    "deliverySeq": 1,
    "lat": -1.3461972,
    "lng": -48.3938122
  }
]
```

### **Resposta da API**
```json
{
  "success": true,
  "message": "Roteirização de entrega atualizada com sucesso!",
  "data": {
    "message": "Roteirização de entrega atualizada com sucesso!"
  },
  "timestamp": "2025-08-18T14:50:34.618Z",
  "statusCode": 201
}
```

---

## **🎯 RESULTADO ESPERADO**

Após implementação, o sistema deve:

1. **Carregar entregas** automaticamente da API
2. **Otimizar rotas** usando algoritmo TSP (Nearest Neighbor)
3. **Enviar sequência** otimizada para API (`/v1/driver/routing`)
4. **Persistir dados** no banco de dados
5. **Redirecionar** para tela principal
6. **Manter ordem** das entregas em todas as telas

**Este sistema garante que as entregas sejam sempre ordenadas pela distância mais eficiente, começando do centro de distribuição e seguindo o algoritmo do caixeiro viajante! 🚚✨**

---

## **📝 NOTAS IMPORTANTES**

- **URL da API**: `https://api.entrega.homologacao.jurunense.com`
- **Algoritmo**: Nearest Neighbor TSP
- **Sequência**: Sempre começa em 1 (não em 0)
- **Coordenadas**: Sempre normalizar (vírgula → ponto)
- **Ordem**: Otimizar ANTES de enviar para API
- **Tratamento de Erro**: Sempre implementar try-catch-finally 