import AsyncStorage from "@react-native-async-storage/async-storage"
import { API_BASE_URL, AUTH_TOKEN_KEY, USER_DATA_KEY } from "@env"
import { Delivery } from '../types'
import Navigation from "../navigation"
import { navigationRef } from "../navigation"
import { convertCoordinate } from '../config/env'

interface ApiResponse<T> {
  success: boolean
  message: string
  data: T
  timestamp: string
  statusCode: number
}

interface LoginData {
  access_token: string
  user: {
    id: number
    username: string
    sellerId: number | null
    name: string
    storeId: string
    email: string | null
  }
}

interface User {
  id: number
  username: string
  sellerId: number | null
  name: string
  storeId: string
  email: string | null
}

export interface DeliveriesResponse {
  success: boolean;
  message: string;
  data: Delivery[];
}

const API_TIMEOUT = 10000; // 10 segundos

// Coordenadas padrão do Centro de Distribuição (fallback)
const DEFAULT_DISTRIBUTION_CENTER = {
  latitude: -1.3654, // Coordenada aproximada do Distrito Industrial de Ananindeua
  longitude: -48.3722,
  address: "Rua Distrito Industrial, L3, SETOR 1 | Quadra 3, Ananindeua - PA"
};

// Função para obter o centro de distribuição dinâmico baseado nas coordenadas da API
export const getDistributionCenter = (deliveries: Delivery[]): { latitude: number; longitude: number; address: string } => {
  // Procura por uma entrega que tenha latFrom e lngFrom válidos
  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)"
      };
    }
  }

  return DEFAULT_DISTRIBUTION_CENTER;
};

// Token de acesso do Mapbox
const MAPBOX_ACCESS_TOKEN = "pk.eyJ1IjoiYWxlaW5jb25uZXh0IiwiYSI6ImNtOGtvdzFueDBuMGUybHBvYjd4d3kyZDQifQ.MXDcXpxKAXtQkyAwv-_1tQ";

// Função para calcular distância entre duas coordenadas usando a 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;
};

/**
 * Obtém coordenadas usando o endpoint interno Google/Cep
 * @deprecated Este endpoint foi removido do projeto. Esta função retorna null.
 * @param params Objeto com address, addressNumber, neighborhood, city, state
 */
export const getCoordinatesFromAddress = async (
  params: {
    address: string;
    addressNumber: string | number;
    neighborhood: string;
    city: string;
    state: string;
  }
): Promise<{ latitude: number; longitude: number } | null> => {
  // Endpoint /v1/geolocation/google foi removido do projeto
  return null;
};

// Função para ordenar entregas por distância e data
export const sortDeliveriesByDistanceAndDate = async (deliveries: Delivery[]): Promise<Delivery[]> => {
  
  // Obter o centro de distribuição dinâmico
  const distributionCenter = getDistributionCenter(deliveries);
  
  const deliveriesWithDistance = await Promise.all(
    deliveries.map(async (delivery, index) => {
      
      let coordinates = null;
      
      // Verificar se já tem coordenadas válidas
      if (delivery.lat && delivery.lng && 
          typeof delivery.lat === 'number' && typeof delivery.lng === 'number' &&
          !isNaN(delivery.lat) && !isNaN(delivery.lng)) {
        coordinates = { latitude: delivery.lat, longitude: delivery.lng };
      }
      
      // Se não tiver coordenadas válidas, tenta obter do endereço
      if (!coordinates) {
        const coords = await getCoordinatesFromAddress({
          address: delivery.street || '',
          addressNumber: delivery.streetNumber || '',
          neighborhood: delivery.neighborhood || '',
          city: delivery.city || '',
          state: delivery.state || ''
        });
        
        if (coords) {
          coordinates = coords;
        }
      }
      
      // Calcular distância apenas se tiver coordenadas válidas
      let distance = 0;
      if (coordinates) {
        distance = calculateDistance(
          distributionCenter.latitude,
          distributionCenter.longitude,
          coordinates.latitude,
          coordinates.longitude
        );
      }
      
      const result = {
        ...delivery,
        distance,
        coordinates: coordinates || undefined
      };
      
      return result;
    })
  );
  
  // Ordena por distância e depois por data
  const sortedDeliveries = deliveriesWithDistance.sort((a, b) => {
    if (a.distance === b.distance) {
      return new Date(a.outDate).getTime() - new Date(b.outDate).getTime();
    }
    return a.distance - b.distance;
  });
  
  
  return sortedDeliveries;
};

// Nova função para ordenar por deliverySeq (sequência de entrega)
export const sortDeliveriesBySequence = async (deliveries: Delivery[]): Promise<Delivery[]> => {
  
  // Obter o centro de distribuição dinâmico
  const distributionCenter = getDistributionCenter(deliveries);
  
  const deliveriesWithDistance = await Promise.all(
    deliveries.map(async (delivery, index) => {
      let coordinates = null;
      
      // Verificar se já tem coordenadas válidas
      if (delivery.lat && delivery.lng && 
          typeof delivery.lat === 'number' && typeof delivery.lng === 'number' &&
          !isNaN(delivery.lat) && !isNaN(delivery.lng)) {
        coordinates = { latitude: delivery.lat, longitude: delivery.lng };
      }
      
      // Se não tiver coordenadas válidas, tenta obter do endereço
      if (!coordinates) {
        const coords = await getCoordinatesFromAddress({
          address: delivery.street || '',
          addressNumber: delivery.streetNumber || '',
          neighborhood: delivery.neighborhood || '',
          city: delivery.city || '',
          state: delivery.state || ''
        });
        
        if (coords) {
          coordinates = coords;
        }
      }
      
      // Calcular distância apenas se tiver coordenadas válidas
      let distance = 0;
      if (coordinates) {
        distance = calculateDistance(
          distributionCenter.latitude,
          distributionCenter.longitude,
          coordinates.latitude,
          coordinates.longitude
        );
      }
      
      const result = {
        ...delivery,
        distance,
        coordinates: coordinates || undefined
      };
      
      return result;
    })
  );
  
  // Ordena por deliverySeq (sequência de entrega)
  const sortedDeliveries = deliveriesWithDistance.sort((a, b) => {
    // Primeiro ordena por deliverySeq
    if (a.deliverySeq !== b.deliverySeq) {
      return a.deliverySeq - b.deliverySeq;
    }
    
    // Se deliverySeq for igual, ordena por status (in_progress primeiro)
    const getStatusOrder = (status: string): number => {
      switch (status) {
        case "in_progress": return 0;
        case "pending": return 1;
        case "delivered": return 2;
        case "failed": return 3;
        default: return 4;
      }
    };
    
    const statusDiff = getStatusOrder(a.status) - getStatusOrder(b.status);
    if (statusDiff !== 0) return statusDiff;
    
    // Se status for igual, ordena por distância
    if (a.distance !== b.distance) {
      return a.distance - b.distance;
    }
    
    // Por último, ordena por data
    return new Date(a.outDate).getTime() - new Date(b.outDate).getTime();
  });
  
  
  return sortedDeliveries;
};

// Função para otimizar rota usando algoritmo do caixeiro viajante (TSP)
export const optimizeRouteWithTSP = async (deliveries: Delivery[]): Promise<Delivery[]> => {

  // Obter o centro de distribuição dinâmico
  const distributionCenter = getDistributionCenter(deliveries);

  // Preparar entregas garantindo coordenadas (normalizar/completar via geolocalização)
  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;

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

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

    // 3) Usar coordinates se existirem (podem vir como string)
    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 pelo endereço
    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;
        }
      } catch (geoErr) {
        // Silently fail
      }
    }

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

  // Separar entre entregas com coordenadas válidas e sem
  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) {
    // Mesmo sem coordenadas, ainda aplicamos uma sequência básica por ordem atual para não ficar tudo 0
    return preparedDeliveries.map((d, i) => ({ ...d, deliverySeq: i + 1 }));
  }


  // Calcular matriz de distâncias entre todas as entregas (com coordenadas)
  const distanceMatrix: number[][] = [];

  // Adicionar centro de distribuição como primeiro ponto
  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
        );
      }
    }
  }


  // Executar algoritmo Nearest Neighbor para as que possuem coordenadas
  const optimizedWithCoords = nearestNeighborTSP(distanceMatrix, withCoords);

  // Montar rota final: primeiro as com coordenadas otimizadas, depois as sem coordenadas (na ordem original)
  const finalRoute: Delivery[] = [...optimizedWithCoords, ...withoutCoords];

  // Aplicar deliverySeq sequencialmente em TODAS as entregas
  const finalDeliveries = finalRoute.map((delivery, idx) => {
    const newSeq = idx + 1; // Garantir que comece em 1, não em 2
    return { ...delivery, deliverySeq: newSeq, distance: (delivery as any).distance || 0 };
  });

  // Verificar se a sequência está correta
  const sequenceCheck = finalDeliveries.map(d => d.deliverySeq).sort((a, b) => a - b);

  return finalDeliveries;
};

// Função para enviar a nova sequência otimizada para a API
export const updateDeliverySequence = async (optimizedDeliveries: Delivery[]): Promise<boolean> => {
  try {
    // Preparar dados com a nova sequência
    const sequenceData = optimizedDeliveries.map(delivery => ({
      outId: delivery.outId,
      customerId: delivery.customerId,
      deliverySeq: delivery.deliverySeq, // NOVA SEQUÊNCIA OTIMIZADA
      lat: delivery.lat || 0,
      lng: delivery.lng || 0
    }));
    
    // Enviar para a API de roteamento
    const response = await api.sendRoutingOrder(sequenceData);
    
    if (response) {
      return true;
    } else {
      return false;
    }
  } catch (error) {
    return false;
  }
};

// Implementação do algoritmo Nearest Neighbor para TSP
const nearestNeighborTSP = (distanceMatrix: number[][], deliveries: Delivery[]): Delivery[] => {
  
  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]);
  }
  
  // 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;
      // CORREÇÃO: Usar nextIndex diretamente, não nextIndex - 1
      route.push(deliveries[nextIndex]);
      currentIndex = nextIndex;
    }
  }
  
  return route;
};

let onUnauthorized: (() => void) | null = null;

export function setOnUnauthorizedCallback(cb: () => void) {
  onUnauthorized = cb;
}

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

  constructor() {
    this.baseUrl = API_BASE_URL
    this.loadToken()
  }

  private async loadToken() {
    try {
      const storedToken = await AsyncStorage.getItem(AUTH_TOKEN_KEY)
      if (storedToken) {
        this.token = storedToken
      }
      return storedToken;
    } catch (error) {
      return null;
    }
  }

  private async setToken(token: string) {
    if (!token) {
      return
    }
    try {
      await AsyncStorage.setItem(AUTH_TOKEN_KEY, token)
      this.token = token
    } catch (error) {
      throw error;
    }
  }

  private async removeToken() {
    try {
      await AsyncStorage.removeItem(AUTH_TOKEN_KEY)
      this.token = null
    } catch (error) {
      // Silently fail
    }
  }

  private async saveUserData(userData: User) {
    if (!userData) {
      return
    }
    try {
      await AsyncStorage.setItem(USER_DATA_KEY, JSON.stringify(userData))
    } catch (error) {
      throw error;
    }
  }

  async login(username: string, password: string): Promise<User> {
    try {
      const myHeaders = new Headers()
      myHeaders.append("Content-Type", "application/json")

      const raw = JSON.stringify({
        username,
        password
      })

      const controller = new AbortController()
      const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 segundos de timeout

      const requestOptions = {
        method: "POST",
        headers: myHeaders,
        body: raw,
        redirect: "follow" as RequestRedirect,
        signal: controller.signal
      }

      try {
        const response = await fetch(`${API_BASE_URL}/auth/login`, requestOptions)
        clearTimeout(timeoutId)
        
        const result = await response.text()
        const data: ApiResponse<LoginData> = JSON.parse(result)

        if (!data.success || !data.data) {
          throw new Error(data.message || "Erro ao fazer login")
        }

        const { access_token, user } = data.data

        if (!access_token || !user) {
          throw new Error("Dados de autenticação incompletos")
        }

        await this.setToken(access_token)
        await this.saveUserData(user)
        
        return user
      } catch (error) {
        if (error instanceof Error) {
          if (error.name === 'AbortError') {
            throw new Error("A requisição demorou muito tempo. Verifique sua conexão e tente novamente.")
          }
          if (error.message.includes('Network request failed')) {
            throw new Error("Erro de conexão. Verifique sua internet e tente novamente.")
          }
        }
        throw error
      }
    } catch (error) {
      throw error
    }
  }

  async logout() {
    try {
      if (this.token) {
        const myHeaders = new Headers()
        myHeaders.append("Authorization", `Bearer ${this.token}`)
        myHeaders.append("Content-Type", "application/json")

        try {
          await fetch(`${this.baseUrl}/auth/logout`, {
            method: "POST",
            headers: myHeaders,
            redirect: "follow" as RequestRedirect
          })
        } catch (apiError) {
          // Continue even if API logout fails
        }
      }
    } catch (error) {
      // Silently fail
    } finally {
      await this.removeToken()
      await AsyncStorage.removeItem(USER_DATA_KEY)
    }
  }

  // Método genérico para fazer requisições autenticadas
  async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
    try {
      const myHeaders = new Headers()
      myHeaders.append("Authorization", `Bearer ${this.token}`)
      myHeaders.append("Content-Type", "application/json")

      const response = await fetch(`${this.baseUrl}${endpoint}`, {
        ...options,
        headers: myHeaders
      })

      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }

      const result = await response.text()
      const data: ApiResponse<T> = JSON.parse(result)

      if (!data.success) {
        throw new Error(data.message || "Erro na requisição")
      }

      return data.data
    } catch (error) {
      throw error
    }
  }

  async getDeliveries(): Promise<Delivery[]> {
    try {
      // SEMPRE tentar dados locais primeiro, independente do estado
      try {
        const { getDeliveriesFromLocal } = await import('./database');
        const localDeliveries = await getDeliveriesFromLocal();
        if (localDeliveries && localDeliveries.length > 0) {
          return localDeliveries;
        }
      } catch (localError) {
        // Continue with API
      }
      
      // Verificar conectividade apenas se não temos dados locais
      const NetInfo = await import('@react-native-community/netinfo');
      const netInfo = await NetInfo.default.fetch();
      
      if (!netInfo.isConnected) {
        // Tentar carregar dados locais como fallback
        try {
          const { getDeliveriesFromLocal } = await import('./database');
          const localDeliveries = await getDeliveriesFromLocal();
          if (localDeliveries && localDeliveries.length > 0) {
            return localDeliveries;
          }
        } catch (fallbackError) {
          // No local data available
        }
        throw new Error('Dispositivo offline - usando dados locais');
      }
      
      const token = await this.loadToken();
      
      if (!token) {
        throw new Error('Token não encontrado');
      }

      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT);

      const myHeaders = new Headers();
      myHeaders.append("Authorization", `Bearer ${token}`);

      // NOVO ENDPOINT
      const ENDPOINT = `${API_BASE_URL}/v1/driver/deliveries`;
      
      const response = await fetch(ENDPOINT, {
        method: "GET",
        headers: myHeaders,
        redirect: "follow",
        signal: controller.signal,
      });

      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }

      clearTimeout(timeoutId);

      if (!response.ok) {
        const errorText = await response.text();
        let errorData;
        try {
          errorData = JSON.parse(errorText);
        } catch (e) {
          errorData = { message: errorText };
        }
        throw new Error(errorData.message || 'Erro ao buscar entregas');
      }

      const responseText = await response.text();
      
      let data: DeliveriesResponse;
      try {
        data = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }

      if (!data.success) {
        throw new Error(data.message || 'Erro ao buscar entregas');
      }

      // Garantir que cada entrega tenha os campos obrigatórios
      const deliveries = (data.data || []).map((item: any) => ({
        ...item,
        id: `${item.outId || 'unknown'}-${item.customerId || 'unknown'}`, // Gera um id único
        deliverySeq: item.deliverySeq ?? 0,
        lat: item.lat ?? null,
        lng: item.lng ?? null,
        latFrom: item.latFrom ?? null, // Coordenada do centro de distribuição (latitude)
        lngFrom: item.lngFrom ?? null, // Coordenada do centro de distribuição (longitude)
        coordinates: (item.lat && item.lng) ? { latitude: item.lat, longitude: item.lng } : undefined,
        notes: item.notes ?? '',
        photos: item.photos ?? [],
        signature: item.signature ?? undefined,
      }));

      return deliveries;
    } catch (error) {
      
      if (error instanceof Error) {
        if (error.name === 'AbortError') {
          throw new Error('Tempo limite excedido ao buscar entregas');
        }
        if (error.message.includes('Network request failed')) {
          throw new Error('Erro de conexão. Verifique sua internet');
        }
        throw error;
      }
      throw new Error('Erro desconhecido ao buscar entregas');
    }
  }

  async getDeliveryById(outId: string | number): Promise<Delivery | null> {
    try {
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
              const ENDPOINT = `${API_BASE_URL}/v1/driver/deliveries/${outId}`;
      const myHeaders = new Headers();
      myHeaders.append("Authorization", `Bearer ${token}`);
      const response = await fetch(ENDPOINT, {
        method: "GET",
        headers: myHeaders,
        redirect: "follow",
      });
      if (!response.ok) {
        const errorText = await response.text();
        let errorData;
        try { errorData = JSON.parse(errorText); } catch (e) { errorData = { message: errorText }; }
        throw new Error(errorData.message || 'Erro ao buscar entrega');
      }
      const responseText = await response.text();
      let data: ApiResponse<any>;
      try { data = JSON.parse(responseText); } catch (e) { throw new Error('Erro ao processar resposta do servidor'); }
      if (!data.success) throw new Error(data.message || 'Erro ao buscar entrega');
      const item = data.data;
      if (!item) return null;
      return {
        ...item,
        id: `${item.outId || 'unknown'}-${item.customerId || 'unknown'}`,
        deliverySeq: item.deliverySeq ?? 0,
        lat: item.lat ?? null,
        lng: item.lng ?? null,
        coordinates: (item.lat && item.lng) ? { latitude: item.lat, longitude: item.lng } : undefined,
        notes: item.notes ?? '',
        photos: item.photos ?? [],
        signature: item.signature ?? undefined,
      };
    } catch (error) {
      console.error('Erro ao buscar entrega por ID:', error);
      return null;
    }
  }

  /**
   * Consulta as notas fiscais de um cliente específico
   */
  async getCustomerInvoices(outId: number, customerId: number): Promise<any[]> {
    try {
      // Verificar se há dados locais disponíveis
      const { getCustomerInvoicesFromLocal } = await import('./database');
      const localInvoices = await getCustomerInvoicesFromLocal(customerId.toString());
      
      if (localInvoices.length > 0) {
        return localInvoices;
      }
      
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      
      const ENDPOINT = `${API_BASE_URL}/v1/driver/deliveries/${outId}/customer/${customerId}`;
      
      const myHeaders = new Headers();
      myHeaders.append("Authorization", `Bearer ${token}`);
      
      const response = await fetch(ENDPOINT, {
        method: "GET",
        headers: myHeaders,
        redirect: "follow",
      });
      
      if (!response.ok) {
        const errorText = await response.text();
        let errorData;
        try { errorData = JSON.parse(errorText); } catch (e) { errorData = { message: errorText }; }
        throw new Error(errorData.message || 'Erro ao consultar notas fiscais');
      }
      
      const responseText = await response.text();
      
      let data: ApiResponse<any[]>;
      try { 
        data = JSON.parse(responseText); 
      } catch (e) { 
        throw new Error('Erro ao processar resposta do servidor'); 
      }
      
      if (!data.success) {
        throw new Error(data.message || 'Erro ao consultar notas fiscais');
      }
      
      const invoices = data.data || [];
      
      return invoices;
    } catch (error) {
      throw error;
    }
  }

    /**
   * Cria/conclui uma entrega usando o endpoint POST /v1/delivery/create
   * @param data Dados da entrega a ser criada/concluída
   */
  async createDelivery(data: any): Promise<any> {
    try {
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      const ENDPOINT = `${API_BASE_URL}/v1/delivery/create`;
      
      const myHeaders = new Headers();
      myHeaders.append('Authorization', `Bearer ${token}`);
      myHeaders.append('Content-Type', 'application/json');
      
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: myHeaders,
        body: JSON.stringify(data),
        redirect: 'follow',
      });
      
      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }
      
      const responseText = await response.text();
      
      let result;
      try {
        result = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }
      
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao concluir entrega');
      }
      
      return result.data;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Cria múltiplas entregas usando o endpoint POST /v1/delivery/create
   * @param deliveries Array de dados das entregas a serem criadas
   */
  async createMultipleDeliveries(deliveries: any[]): Promise<any> {
    try {
      // Validação dos dados antes de enviar
      deliveries.forEach((delivery, index) => {
        // Verificar se há valores null que podem causar problemas
        if (delivery.outId === null || delivery.outId === undefined) {
          throw new Error(`Entrega ${index + 1}: outId é obrigatório`);
        }
        if (delivery.transactionId === null || delivery.transactionId === undefined) {
          throw new Error(`Entrega ${index + 1}: transactionId é obrigatório`);
        }
        if (delivery.userId === null || delivery.userId === undefined) {
          throw new Error(`Entrega ${index + 1}: userId é obrigatório`);
        }
      });
      
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      
      const ENDPOINT = `${API_BASE_URL}/v1/delivery/create`;
      
      const myHeaders = new Headers();
      myHeaders.append('Authorization', `Bearer ${token}`);
      myHeaders.append('Content-Type', 'application/json');
      
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: myHeaders,
        body: JSON.stringify(deliveries),
        redirect: 'follow',
      });
      
      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }
      
      const responseText = await response.text();
      
      let result;
      try {
        result = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }
      
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao criar múltiplas entregas');
      }
      
      return result.data;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Envia ordem de roteamento para o endpoint POST /v1/driver/routing
   * @param routingData Array com dados de roteamento
   */
  async sendRoutingOrder(routingData: Array<{
    outId: number;
    customerId: number;
    deliverySeq: number;
    lat: number;
    lng: number;
  }>): Promise<any> {
    try {
      
      // Validar e normalizar coordenadas antes de enviar
      const validatedRoutingData = routingData.map((item, index) => {
        // Garantir que lat e lng sejam números válidos
        let lat: any = item.lat;
        let lng: any = item.lng;
        
        // Se lat ou lng são strings com vírgula, converter para ponto
        if (typeof lat === 'string') {
          lat = parseFloat(lat.replace(',', '.'));
          if (isNaN(lat)) {
            lat = 0;
          }
        }
        
        if (typeof lng === 'string') {
          lng = parseFloat(lng.replace(',', '.'));
          if (isNaN(lng)) {
            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 = `${API_BASE_URL}/v1/driver/routing`;
      
      const myHeaders = new Headers();
      myHeaders.append('Authorization', `Bearer ${token}`);
      myHeaders.append('Content-Type', 'application/json');
      
      const requestBody = JSON.stringify(validatedRoutingData);
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: myHeaders,
        body: requestBody,
        redirect: 'follow',
      });
      
      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }
      
      const responseText = await response.text();
      
      let result;
      try {
        result = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }
      
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao enviar ordem de roteamento');
      }
      
      return result.data;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Envia roteamento após desenhar a rota no mapa
   * @param deliveries Entregas com coordenadas reais da rota
   */
  async sendRoutingAfterMapRoute(deliveries: Delivery[]): Promise<any> {
    try {
      // Usar todas as entregas otimizadas que já têm deliverySeq
      const optimizedDeliveries = deliveries.filter((delivery: any) => delivery.deliverySeq > 0);
      
      if (optimizedDeliveries.length === 0) {
        return null;
      }


      // Preparar dados para roteamento com coordenadas reais
      const routingData = optimizedDeliveries.map((delivery: any, index: number) => {
        // Usar coordenadas reais da rota desenhada
        let lat: number;
        let lng: number;
        
        // Tentar usar coordinates primeiro (coordenadas reais da rota)
        if (delivery.coordinates && delivery.coordinates.latitude && delivery.coordinates.longitude) {
          lat = convertCoordinate(delivery.coordinates.latitude) || 0;
          lng = convertCoordinate(delivery.coordinates.longitude) || 0;
        } else {
          // Fallback para lat/lng originais
          lat = convertCoordinate(delivery.lat) || 0;
          lng = convertCoordinate(delivery.lng) || 0;
        }
        
        return {
          outId: delivery.outId,
          customerId: delivery.customerId,
          deliverySeq: delivery.deliverySeq,
          lat: lat,
          lng: lng
        };
      });

      // Enviar ordem de roteamento
      const result = await this.sendRoutingOrder(routingData);
      
      return result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Atualiza o status de uma entrega usando o endpoint POST /v1/driver/delivery/status
   * @param data Dados do status da entrega
   */
  async updateDeliveryStatus(data: {
    outId: number;
    customerId: number;
    status: 'pending' | 'in_progress' | 'delivered' | 'failed';
    lat: number | null;
    lng: number | null;
    notes?: string;
  }): Promise<any> {
    try {
      // Verificar se há valores null que podem causar problemas
      if (data.outId === null || data.outId === undefined) {
        throw new Error('outId é obrigatório para atualizar status');
      }
      if (data.customerId === null || data.customerId === undefined) {
        throw new Error('customerId é obrigatório para atualizar status');
      }
      if (!data.status) {
        throw new Error('status é obrigatório para atualizar status');
      }
      
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      
      const ENDPOINT = `${API_BASE_URL}/v1/driver/delivery/status`;
      
      const myHeaders = new Headers();
      myHeaders.append('Authorization', `Bearer ${token}`);
      myHeaders.append('Content-Type', 'application/json');
      
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: myHeaders,
        body: JSON.stringify(data),
        redirect: 'follow',
      });
      
      if (response.status === 401) {
        if (onUnauthorized) onUnauthorized();
        throw new Error('Sessão expirada. Faça login novamente.');
      }
      
      const responseText = await response.text();
      
      let result;
      try {
        result = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }
      
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao atualizar status da entrega');
      }
      
      return result.data;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Envia imagens para o endpoint /api/v1/base/send-image e retorna as URLs
   * @param images Array de objetos { file: base64, transactionId }
   * @returns Array de objetos { url, transactionId }
   */
  async uploadImages(images: Array<{ file: string, transactionId: number }>): Promise<Array<{ url: string, transactionId: number }>> {
    try {
      const token = await this.loadToken();
      if (!token) throw new Error('Token não encontrado');
      const ENDPOINT = `${API_BASE_URL}/api/v1/base/send-image`;
      const formData = new FormData();
      images.forEach((img, idx) => {
        // Adiciona o arquivo (file: uri local)
        formData.append('files', {
          uri: img.file,
          name: `image_${Date.now()}_${idx}.jpg`,
          type: 'image/jpeg',
        } as any);
        // Adiciona o transactionId correspondente
        formData.append('transactionId', String(img.transactionId));
      });
      const myHeaders = new Headers();
      myHeaders.append('Authorization', `Bearer ${token}`);
      // NÃO defina Content-Type manualmente!
      const response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: myHeaders,
        body: formData,
        redirect: 'follow',
      });
      const responseText = await response.text();
      let result: any;
      try {
        result = JSON.parse(responseText);
      } catch (e) {
        throw new Error('Erro ao processar resposta do servidor');
      }
      if (!response.ok || !result.success) {
        throw new Error(result.message || 'Erro ao enviar imagens');
      }
      // O backend pode retornar vários formatos, tratar todos:
      if (Array.isArray(result.data)) {
        return result.data.map((item: any) => ({ url: item.url, transactionId: item.transactionId }));
      } else if (result.data && result.data.url && result.data.transactionId) {
        return [{ url: result.data.url, transactionId: result.data.transactionId }];
      } else if (result.urls && Array.isArray(result.urls) && result.transactionId && Array.isArray(result.transactionId)) {
        // Formato: { success, message, urls: [..], transactionId: [..] }
        return result.urls.map((url: string, idx: number) => ({ url, transactionId: result.transactionId[idx] }));
      } else {
        // Se for sucesso mas formato diferente, retorna urls se existirem
        if (result.success && result.urls && Array.isArray(result.urls)) {
          return result.urls.map((url: string, idx: number) => ({ url, transactionId: result.transactionId ? result.transactionId[idx] : null }));
        }
        throw new Error('Resposta inesperada do servidor ao enviar imagens');
      }
    } catch (error) {
      throw error;
    }
  }
}

export const api = new ApiService()

