/**
 * 📍 RouteStopsService - Gestão de Paradas de Rotas
 * 
 * Service responsável por todas as operações CRUD de paradas de rotas,
 * seguindo os padrões do projeto com ApiClientService e sistema de fallback robusto.
 * 
 * ✨ Funcionalidades:
 * - CRUD completo de paradas
 * - Sistema de fallback inteligente com dados do arquivo JSON
 * - Indicador de conectividade em tempo real
 * - Cache local para melhor performance
 * - Retry automático com backoff exponencial
 * - Logs detalhados para debugging
 */

import { Injectable } from '@angular/core';
import { Observable, of, map, catchError, BehaviorSubject, timer, throwError } from 'rxjs';
import { retry, retryWhen, delay, take, mergeMap, timeout } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

// Interfaces
import { 
  RouteStop, 
  RouteStopsResponse, 
  RouteStopsFilters,
  RouteOptimization 
} from '../route-stops.interface';

// Services
import { ApiClientService } from '../../../shared/services/api/api-client.service';

// Tipos para controle de conectividade
interface ConnectivityStatus {
  isOnline: boolean;
  lastSuccessfulConnection: Date | null;
  failureCount: number;
  usingFallback: boolean;
}

// Tipo para dados do arquivo JSON
interface RouteStopsData {
  routeId: string;
  routeNumber: string;
  type: string;
  status: string;
  origin: any;
  destination: any;
  vehiclePlate: string;
  driverName: string;
  scheduledDeparture: string;
  scheduledArrival: string;
  stops: any[];
}

@Injectable({
  providedIn: 'root'
})
export class RouteStopsService {

  // 🌐 Estado de conectividade
  private connectivitySubject = new BehaviorSubject<ConnectivityStatus>({
    isOnline: true,
    lastSuccessfulConnection: null,
    failureCount: 0,
    usingFallback: false
  });

  // 💾 Cache local simples
  private cache = new Map<string, { data: any; timestamp: number; ttl: number }>();
  private readonly CACHE_TTL = 5 * 60 * 1000; // 5 minutos

  // ⚙️ Configurações de retry
  private readonly MAX_RETRIES = 3;
  private readonly RETRY_DELAY = 1000; // 1 segundo base

  // 📄 Cache dos dados do arquivo JSON
  private routeStopsData: RouteStopsData[] | null = null;

  constructor(
    private apiClient: ApiClientService,
    private http: HttpClient
  ) {
    this.startConnectivityMonitoring();
    this.loadRouteStopsData();
  }

  // ========================================
  // 🌐 MONITORAMENTO DE CONECTIVIDADE
  // ========================================

  /**
   * Observable para monitorar status de conectividade
   */
  get connectivity$(): Observable<ConnectivityStatus> {
    return this.connectivitySubject.asObservable();
  }

  /**
   * Status atual de conectividade
   */
  get isOnline(): boolean {
    return this.connectivitySubject.value.isOnline;
  }

  /**
   * Está usando dados de fallback?
   */
  get isUsingFallback(): boolean {
    return this.connectivitySubject.value.usingFallback;
  }

  /**
   * Inicia monitoramento periódico de conectividade
   */
  private startConnectivityMonitoring(): void {
    // Verificar conectividade a cada 30 segundos
    timer(0, 30000).subscribe(() => {
      this.checkBackendHealth();
    });
  }

  /**
   * Verifica saúde do backend
   */
  private checkBackendHealth(): void {
    this.apiClient.get<any>('health/route-stops').pipe(
      timeout(5000), // 5 segundos timeout
      catchError(() => of(null))
    ).subscribe(response => {
      const currentStatus = this.connectivitySubject.value;
      
      if (response) {
        // Backend respondeu - está online
        this.updateConnectivityStatus({
          ...currentStatus,
          isOnline: true,
          lastSuccessfulConnection: new Date(),
          failureCount: 0,
          usingFallback: false
        });
        
        console.log('🟢 [RouteStops] Backend conectado e funcionando');
      } else {
        // Backend não respondeu - offline
        this.updateConnectivityStatus({
          ...currentStatus,
          isOnline: false,
          failureCount: currentStatus.failureCount + 1,
          usingFallback: true
        });
        
        console.warn('🔴 [RouteStops] Backend offline, usando dados de fallback');
      }
    });
  }

  /**
   * Atualiza status de conectividade
   */
  private updateConnectivityStatus(status: ConnectivityStatus): void {
    this.connectivitySubject.next(status);
  }

  /**
   * Força verificação de conectividade (botão de reconexão)
   */
  forceReconnect(): Observable<boolean> {
    console.log('🔄 [RouteStops] Tentativa manual de reconexão...');
    
    return this.apiClient.get<any>('health/route-stops').pipe(
      timeout(10000), // 10 segundos para reconexão manual
      map(() => {
        const currentStatus = this.connectivitySubject.value;
        this.updateConnectivityStatus({
          ...currentStatus,
          isOnline: true,
          lastSuccessfulConnection: new Date(),
          failureCount: 0,
          usingFallback: false
        });
        
        console.log('✅ [RouteStops] Reconexão bem-sucedida');
        return true;
      }),
      catchError(error => {
        console.error('❌ [RouteStops] Falha na reconexão:', error);
        return of(false);
      })
    );
  }

  // ========================================
  // 💾 SISTEMA DE CACHE
  // ========================================

  /**
   * Obtém dados do cache se válidos
   */
  private getFromCache<T>(key: string): T | null {
    const cached = this.cache.get(key);
    if (cached && Date.now() - cached.timestamp < cached.ttl) {
      console.log(`📦 [Cache] Dados encontrados para: ${key}`);
      return cached.data as T;
    }
    
    if (cached) {
      this.cache.delete(key); // Remove cache expirado
    }
    
    return null;
  }

  /**
   * Armazena dados no cache
   */
  private setCache(key: string, data: any, ttl: number = this.CACHE_TTL): void {
    this.cache.set(key, {
      data,
      timestamp: Date.now(),
      ttl
    });
    console.log(`💾 [Cache] Dados armazenados para: ${key}`);
  }

  /**
   * Limpa todo o cache
   */
  clearCache(): void {
    this.cache.clear();
    console.log('🧹 [Cache] Cache limpo');
  }

  // ========================================
  // 🔄 SISTEMA DE RETRY INTELIGENTE
  // ========================================

  /**
   * Executa requisição com retry e fallback
   */
  private executeWithFallback<T>(
    request: () => Observable<T>,
    fallbackData: () => T,
    cacheKey?: string
  ): Observable<T> {
    console.log('🔄 [RouteStops] executeWithFallback iniciado');
    
    // Verificar cache primeiro
    if (cacheKey) {
      const cached = this.getFromCache<T>(cacheKey);
      if (cached) {
        console.log('📦 [RouteStops] Dados encontrados em cache');
        return of(cached);
      }
    }

    console.log('🌐 [RouteStops] Tentando requisição ao backend...');
    return request().pipe(
      // Retry com backoff exponencial
      retryWhen(errors => 
        errors.pipe(
          mergeMap((error, index) => {
            const retryCount = index + 1;
            
            if (retryCount > this.MAX_RETRIES) {
              console.warn(`⚠️ [RouteStops] Máximo de tentativas atingido (${this.MAX_RETRIES})`);
              return throwError(error);
            }
            
            const delayTime = this.RETRY_DELAY * Math.pow(2, index); // Backoff exponencial
            console.log(`🔄 [RouteStops] Tentativa ${retryCount}/${this.MAX_RETRIES} em ${delayTime}ms`);
            
            return timer(delayTime);
          }),
          take(this.MAX_RETRIES)
        )
      ),
      map(data => {
        // Sucesso - atualizar conectividade e cache
        console.log('✅ [RouteStops] Backend respondeu com sucesso');
        const currentStatus = this.connectivitySubject.value;
        this.updateConnectivityStatus({
          ...currentStatus,
          isOnline: true,
          lastSuccessfulConnection: new Date(),
          failureCount: 0,
          usingFallback: false
        });

        // Armazenar no cache
        if (cacheKey) {
          this.setCache(cacheKey, data);
        }

        console.log('✅ [RouteStops] Requisição bem-sucedida');
        return data;
      }),
      catchError(error => {
        // Falha - usar fallback
        console.warn('⚠️ [RouteStops] Backend falhou, ativando fallback:', error.message);
        
        const currentStatus = this.connectivitySubject.value;
        this.updateConnectivityStatus({
          ...currentStatus,
          isOnline: false,
          failureCount: currentStatus.failureCount + 1,
          usingFallback: true
        });

        console.log('🎭 [RouteStops] Executando função de fallback...');
        const fallback = fallbackData();
        console.log('🎭 [RouteStops] Dados de fallback obtidos:', fallback);
        
        // Armazenar fallback no cache com TTL menor
        if (cacheKey) {
          this.setCache(cacheKey, fallback, 60000); // 1 minuto para fallback
        }

        return of(fallback);
      })
    );
  }

  // ========================================
  // 📄 CARREGAMENTO DOS DADOS JSON
  // ========================================

  /**
   * Carrega dados do arquivo JSON
   */
  private loadRouteStopsData(): void {
    this.http.get<RouteStopsData[]>('/assets/data/route-stops-data.json').subscribe({
      next: (data) => {
        this.routeStopsData = data;
        console.log('📄 [RouteStops] Dados JSON carregados com sucesso:', data.length, 'rotas');
      },
      error: (error) => {
        console.error('❌ [RouteStops] Erro ao carregar dados JSON:', error);
        this.routeStopsData = [];
      }
    });
  }

  /**
   * Obtém dados de uma rota específica do arquivo JSON
   */
  private getRouteDataFromJson(routeId: string): RouteStopsData | null {
    if (!this.routeStopsData) {
      console.warn('⚠️ [RouteStops] Dados JSON ainda não carregados');
      return null;
    }

    return this.routeStopsData.find(route => route.routeId === routeId) || null;
  }

  /**
   * Converte dados do JSON para o formato RouteStop
   */
  private convertJsonToRouteStop(jsonStop: any, routeId: string): RouteStop {
    return {
      id: jsonStop.stopId,
      routeId: routeId,
      sequence: jsonStop.sequence,
      type: jsonStop.type,
      location: {
        address: jsonStop.address,
        coordinates: jsonStop.coordinates,
        contact: jsonStop.customerName,
        phone: jsonStop.contactPhone,
        cep: jsonStop.zipCode,
        city: jsonStop.city,
        state: jsonStop.state,
        country: 'Brasil',
        facility: jsonStop.customerName,
        accessInstructions: jsonStop.notes || ''
      },
      scheduledTime: new Date(jsonStop.scheduledTime),
      actualTime: jsonStop.actualTime ? new Date(jsonStop.actualTime) : undefined,
      estimatedDuration: jsonStop.estimatedDuration,
      status: jsonStop.status,
      packages: jsonStop.packages,
      weight: jsonStop.packages * 10, // Estimativa: 10kg por pacote
      volume: jsonStop.packages * 0.1, // Estimativa: 0.1m³ por pacote
      referenceNumber: `REF-${jsonStop.stopId.toUpperCase()}`,
      fiscalDocument: undefined, // Por enquanto não temos documentos fiscais no JSON
      photos: [],
      signature: undefined,
      notes: jsonStop.notes || '',
      attempts: 0,
      delayReason: undefined,
      temperature: undefined,
      createdAt: new Date(),
      updatedAt: new Date(),
      createdBy: 'system'
    };
  }

  // ========================================
  // 📊 BUSCA E LISTAGEM (COM FALLBACK)
  // ========================================

  getRouteStops(filters: RouteStopsFilters): Observable<RouteStopsResponse> {
    console.log('🎯 [RouteStops] getRouteStops chamado com filtros:', filters);
    
    // 🚨 TEMPORÁRIO: Forçar uso de fallback para debug
    console.log('🎭 [RouteStops] FORÇANDO uso de fallback para debug');
    const fallbackData = this.getFallbackRouteStops(filters);
    console.log('🎭 [RouteStops] Dados de fallback obtidos:', fallbackData);
    
    // Atualizar status de conectividade para indicar uso de fallback
    const currentStatus = this.connectivitySubject.value;
    this.updateConnectivityStatus({
      ...currentStatus,
      isOnline: false,
      usingFallback: true
    });
    
    return of(fallbackData);
    
    /* CÓDIGO ORIGINAL (comentado temporariamente):
    const cacheKey = `route-stops-${JSON.stringify(filters)}`;
    
    return this.executeWithFallback(
      () => {
        let url = 'route-stops?';
        
        // Construir query parameters
        const params = new URLSearchParams();
        
        if (filters.routeId) params.append('routeId', filters.routeId);
        if (filters.type?.length) params.append('type', filters.type.join(','));
        if (filters.status?.length) params.append('status', filters.status.join(','));
        if (filters.city) params.append('city', filters.city);
        if (filters.state) params.append('state', filters.state);
        if (filters.hasDocument !== undefined) params.append('hasDocument', filters.hasDocument.toString());
        if (filters.documentType?.length) params.append('documentType', filters.documentType.join(','));
        if (filters.page) params.append('page', filters.page.toString());
        if (filters.limit) params.append('limit', filters.limit.toString());
        
        if (filters.dateRange) {
          params.append('startDate', filters.dateRange.start.toISOString());
          params.append('endDate', filters.dateRange.end.toISOString());
        }
        
        url += params.toString();
        
        console.log(`🌐 [RouteStops] Tentando buscar no backend: ${url}`);
        return this.apiClient.get<RouteStopsResponse>(url);
      },
      () => {
        console.log('🎭 [RouteStops] Usando dados de fallback para filtros:', filters);
        return this.getFallbackRouteStops(filters);
      },
      cacheKey
    );
    */
  }

  getRouteStopById(id: string): Observable<RouteStop> {
    const cacheKey = `route-stop-${id}`;
    
    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Buscando parada por ID: ${id}`);
        return this.apiClient.get<RouteStop>(`route-stops/${id}`);
      },
      () => {
        const mockStop = this.convertJsonToRouteStop(this.getRouteDataFromJson(id)?.stops.find(s => s.stopId === id) || {}, id);
        if (!mockStop) {
          throw new Error(`Parada ${id} não encontrada nem no backend nem nos dados mock`);
        }
        return mockStop;
      },
      cacheKey
    );
  }

  // ========================================
  // 💾 OPERAÇÕES CRUD (COM FALLBACK)
  // ========================================

  createRouteStop(stopData: Partial<RouteStop>): Observable<RouteStop> {
    return this.executeWithFallback(
      () => {
        console.log('🌐 [RouteStops] Criando nova parada:', stopData);
        return this.apiClient.post<RouteStop>('route-stops', stopData);
      },
      () => {
        console.log('🎭 [RouteStops] Simulando criação de parada');
        
        // Simular criação com dados mock
        const newStop: RouteStop = {
          id: `stop_${Date.now()}`,
          routeId: stopData.routeId || '',
          sequence: stopData.sequence || 1,
          type: stopData.type || 'delivery',
          location: stopData.location || {
            address: '',
            coordinates: { lat: 0, lng: 0 }
          },
          scheduledTime: stopData.scheduledTime || new Date(),
          status: 'pending',
          createdAt: new Date(),
          updatedAt: new Date(),
          createdBy: 'user_mock',
          ...stopData
        } as RouteStop;
        
        return newStop;
      }
    );
  }

  updateRouteStop(id: string, stopData: Partial<RouteStop>): Observable<RouteStop> {
    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Atualizando parada ${id}:`, stopData);
        return this.apiClient.patch<RouteStop>(`route-stops/${id}`, stopData);
      },
      () => {
        console.log(`🎭 [RouteStops] Simulando atualização da parada ${id}`);
        
        // Simular atualização com dados mock
        const existingStop = this.convertJsonToRouteStop(this.getRouteDataFromJson(id)?.stops.find(s => s.stopId === id) || {}, id);
        if (!existingStop) {
          throw new Error(`Parada ${id} não encontrada para atualização`);
        }
        
        const updatedStop: RouteStop = {
          ...existingStop,
          ...stopData,
          updatedAt: new Date()
        };
        
        // Invalidar cache relacionado
        this.cache.delete(`route-stop-${id}`);
        
        return updatedStop;
      }
    );
  }

  deleteRouteStop(id: string): Observable<void> {
    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Excluindo parada ${id}`);
        return this.apiClient.delete<void>(`route-stops/${id}`);
      },
      () => {
        console.log(`🎭 [RouteStops] Simulando exclusão da parada ${id}`);
        
        // Invalidar cache relacionado
        this.cache.delete(`route-stop-${id}`);
        
        return undefined;
      }
    );
  }

  // ========================================
  // 🔄 OPERAÇÕES ESPECIAIS (COM FALLBACK)
  // ========================================

  updateStopsOrder(routeId: string, stops: RouteStop[]): Observable<RouteStop[]> {
    const orderData = {
      routeId,
      stopsOrder: stops.map(stop => ({
        id: stop.id,
        sequence: stop.sequence
      }))
    };

    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Reordenando paradas da rota ${routeId}`);
        return this.apiClient.patch<RouteStop[]>(`route-stops/reorder`, orderData);
      },
      () => {
        console.log(`🎭 [RouteStops] Simulando reordenação das paradas da rota ${routeId}`);
        return stops;
      }
    );
  }

  optimizeRoute(routeId: string): Observable<RouteStop[]> {
    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Otimizando rota ${routeId}`);
        return this.apiClient.post<RouteStop[]>(`route-stops/optimize`, { routeId });
      },
      () => {
        console.log(`🎭 [RouteStops] Usando otimização mock para rota ${routeId}`);
        
                  // Retornar sequência otimizada mock
          const currentStops = this.getRouteDataFromJson(routeId)?.stops.slice() || [];
          if (currentStops.length > 0) {
            return currentStops.map(stop => this.convertJsonToRouteStop(stop, routeId));
          }
        
        return [];
      }
    );
  }

  // ========================================
  // 📊 ESTATÍSTICAS E MÉTRICAS (COM FALLBACK)
  // ========================================

  getRouteStopsStats(routeId: string): Observable<any> {
    const cacheKey = `route-stops-stats-${routeId}`;
    
    return this.executeWithFallback(
      () => {
        console.log(`🌐 [RouteStops] Buscando estatísticas da rota ${routeId}`);
        return this.apiClient.get<any>(`route-stops/stats/${routeId}`);
      },
      () => {
        console.log(`🎭 [RouteStops] Calculando estatísticas mock para rota ${routeId}`);
        
        const stops = this.getRouteDataFromJson(routeId)?.stops.slice() || [];
        const stats = {
          totalStops: stops.length,
          completedStops: stops.filter(s => s.status === 'completed').length,
          pendingStops: stops.filter(s => s.status === 'pending').length,
          failedStops: stops.filter(s => s.status === 'failed').length,
          completionRate: stops.length > 0 ? 
            (stops.filter(s => s.status === 'completed').length / stops.length) * 100 : 0,
          source: 'fallback',
          generatedAt: new Date().toISOString()
        };
        
        return stats;
      },
      cacheKey
    );
  }

  // ========================================
  // 🔄 DADOS DE FALLBACK
  // ========================================

  private getFallbackRouteStops(filters: RouteStopsFilters): RouteStopsResponse {
    console.log('🎭 [RouteStops] Aplicando filtros aos dados de fallback:', filters);
    
    if (!this.routeStopsData) {
      console.warn('⚠️ [RouteStops] Dados JSON não carregados, retornando lista vazia');
      return {
        data: [],
        pagination: { total: 0, page: 1, limit: 10, totalPages: 0 },
        source: 'fallback',
        timestamp: new Date().toISOString()
      };
    }

    console.log('🎭 [RouteStops] Total de rotas disponíveis:', this.routeStopsData.length);
    
    // Converter todas as paradas de todas as rotas para o formato RouteStop
    let filteredStops: RouteStop[] = [];
    this.routeStopsData.forEach(routeData => {
      const routeStops = routeData.stops.map(stop => this.convertJsonToRouteStop(stop, routeData.routeId));
      filteredStops.push(...routeStops);
    });
    
    console.log('🎭 [RouteStops] Total de paradas disponíveis:', filteredStops.length);

    // Aplicar filtros
    if (filters.routeId) {
      console.log('🎭 [RouteStops] Filtrando por routeId:', filters.routeId);
      filteredStops = filteredStops.filter(stop => stop.routeId === filters.routeId);
      console.log('🎭 [RouteStops] Paradas após filtro de routeId:', filteredStops.length);
    }

    if (filters.type?.length) {
      filteredStops = filteredStops.filter(stop => filters.type!.includes(stop.type));
    }

    if (filters.status?.length) {
      filteredStops = filteredStops.filter(stop => filters.status!.includes(stop.status));
    }

    if (filters.city) {
      filteredStops = filteredStops.filter(stop => 
        stop.location.city?.toLowerCase().includes(filters.city!.toLowerCase())
      );
    }

    if (filters.state) {
      filteredStops = filteredStops.filter(stop => 
        stop.location.state?.toLowerCase().includes(filters.state!.toLowerCase())
      );
    }

    if (filters.hasDocument !== undefined) {
      filteredStops = filteredStops.filter(stop => 
        filters.hasDocument ? !!stop.fiscalDocument : !stop.fiscalDocument
      );
    }

    if (filters.documentType?.length) {
      filteredStops = filteredStops.filter(stop => 
        stop.fiscalDocument && filters.documentType!.includes(stop.fiscalDocument.documentType)
      );
    }

    // Paginação
    const page = filters.page || 1;
    const limit = filters.limit || 10;
    const startIndex = (page - 1) * limit;
    const endIndex = startIndex + limit;
    
    const paginatedStops = filteredStops.slice(startIndex, endIndex);

    console.log(`🎭 [RouteStops] Retornando ${paginatedStops.length} paradas de ${filteredStops.length} filtradas`);

    return {
      data: paginatedStops,
      pagination: {
        total: filteredStops.length,
        page: page,
        limit: limit,
        totalPages: Math.ceil(filteredStops.length / limit)
      },
      source: 'fallback',
      timestamp: new Date().toISOString()
    };
  }
} 