import * as FileSystem from 'expo-file-system/legacy';
import { savePhotoUpload, getPendingPhotoUploads, saveDeliveryImage } from './database';
import API_BASE_URL from '../config/env';

export interface PhotoUpload {
  id: string;
  deliveryId: string;
  transactionId: number;
  localPath: string;
  serverUrl?: string;
  uploadStatus: 'pending' | 'uploading' | 'completed' | 'failed';
  uploadProgress: number;
  uploadAttempts: number;
  lastUploadAttempt?: number;
  errorMessage?: string;
}

export interface UploadProgress {
  uploadId: string;
  progress: number;
  status: string;
}

class PhotoUploadService {
  private uploadQueue: PhotoUpload[] = [];
  private isUploading = false;
  private maxConcurrentUploads = 3;
  private uploadTimeout = 30000; // 30 segundos

  /**
   * Adiciona uma foto à fila de upload
   */
  async addPhotoToUpload(
    deliveryId: string,
    transactionId: number,
    localPath: string
  ): Promise<string> {
    try {
      const uploadId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
      
      const photoUpload: PhotoUpload = {
        id: uploadId,
        deliveryId,
        transactionId,
        uploadStatus: 'pending',
        uploadProgress: 0,
        uploadAttempts: 0,
        localPath
      };

      // Salvar no banco de dados
      await savePhotoUpload(photoUpload);
      
      // Adicionar à fila local
      this.uploadQueue.push(photoUpload);

      return uploadId;
    } catch (error: any) {
      throw error;
    }
  }

  /**
   * Verifica conectividade e processa uploads pendentes
   */
  async checkConnectivityAndProcessQueue(): Promise<void> {
    try {
      // Desabilitado temporariamente para evitar uploads automáticos
      // O upload será feito apenas quando o usuário solicitar sincronização
      return;
      
      const NetInfo = await import('@react-native-community/netinfo');
      const netInfo = await NetInfo.default.fetch();
      
      if (netInfo.isConnected && this.uploadQueue.length > 0) {
        await this.processUploadQueue();
      }
    } catch (error: any) {
      // Silently fail
    }
  }

  /**
   * Processa a fila de uploads
   */
  private async processUploadQueue(): Promise<void> {
    if (this.isUploading || this.uploadQueue.length === 0) {
      return;
    }

    this.isUploading = true;

    try {
      // Carregar uploads pendentes do banco
      const pendingUploads = await getPendingPhotoUploads();
      
      // Processar uploads em lotes
      const batches = this.chunkArray(pendingUploads, this.maxConcurrentUploads);
      
      for (const batch of batches) {
        await Promise.allSettled(
          batch.map(upload => this.uploadPhoto(upload))
        );
      }

    } catch (error: any) {
      // Silently fail
    } finally {
      this.isUploading = false;
      this.uploadQueue = [];
    }
  }

  /**
   * Faz upload de uma foto específica
   */
  private async uploadPhoto(upload: PhotoUpload): Promise<void> {
    try {

      // Verificar conectividade antes de fazer upload
      const NetInfo = await import('@react-native-community/netinfo');
      const netInfo = await NetInfo.default.fetch();
      
      if (!netInfo.isConnected) {
        await this.updateUploadStatus(upload.id, 'pending', 0);
        return;
      }

      // Verificar se o arquivo existe
      const fileInfo = await FileSystem.getInfoAsync(upload.localPath);
      if (!fileInfo.exists) {
        throw new Error('Arquivo não encontrado');
      }

      // Atualizar status para uploading
      await this.updateUploadStatus(upload.id, 'uploading', 0);

      // Preparar dados do formulário
      const formData = new FormData();
      formData.append('files', {
        uri: upload.localPath,
        type: 'image/jpeg',
        name: `delivery_${upload.transactionId}_${Date.now()}.jpg`
      } as any);
      formData.append('transactionId', upload.transactionId.toString());

      // Fazer upload
      const response = await fetch(`${API_BASE_URL}/api/v1/base/send-image`, {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        body: formData,
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'Erro no upload');
      }

      const result = await response.json();
      
      if (result.success && result.data && result.data.length > 0) {
        const serverUrl = result.data[0].url;
        
        // Atualizar com sucesso
        await this.updateUploadStatus(upload.id, 'completed', 100, serverUrl);
        
        // Salvar na tabela de imagens de entrega
        await saveDeliveryImage({
          id: `img_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          deliveryId: upload.deliveryId,
          transactionId: upload.transactionId,
          imagePath: upload.localPath,
          imageUrl: serverUrl,
          uploadStatus: 'uploaded'
        });

      } else {
        throw new Error('Resposta inválida do servidor');
      }

    } catch (error: any) {
      const attempts = upload.uploadAttempts + 1;
      const maxAttempts = 3;
      
      if (attempts < maxAttempts) {
        // Tentar novamente
        await this.updateUploadStatus(
          upload.id, 
          'pending', 
          0, 
          undefined, 
          attempts,
          error.message
        );
        // setTimeout(() => {
        //   this.processUploadQueue();
        // }, Math.pow(2, attempts) * 1000); // Backoff exponencial
      } else {
        // Falha definitiva
        await this.updateUploadStatus(
          upload.id, 
          'failed', 
          0, 
          undefined, 
          attempts,
          error.message
        );
      }
    }
  }

  /**
   * Atualiza o status de um upload
   */
  private async updateUploadStatus(
    uploadId: string,
    status: PhotoUpload['uploadStatus'],
    progress: number,
    serverUrl?: string,
    attempts?: number,
    errorMessage?: string
  ): Promise<void> {
    try {
      const updateData: Partial<PhotoUpload> = {
        uploadStatus: status,
        uploadProgress: progress,
        lastUploadAttempt: Date.now()
      };

      if (serverUrl) {
        updateData.serverUrl = serverUrl;
      }

      if (attempts !== undefined) {
        updateData.uploadAttempts = attempts;
      }

      if (errorMessage) {
        updateData.errorMessage = errorMessage;
      }

      await savePhotoUpload({ id: uploadId, ...updateData } as PhotoUpload);
    } catch (error: any) {
      // Silently fail
    }
  }

  /**
   * Obtém estatísticas de upload
   */
  async getUploadStats(): Promise<{
    pending: number;
    uploading: number;
    completed: number;
    failed: number;
    total: number;
  }> {
    try {
      const pendingUploads = await getPendingPhotoUploads();
      
      const stats = pendingUploads.reduce((acc, upload) => {
        acc[upload.uploadStatus]++;
        acc.total++;
        return acc;
      }, {
        pending: 0,
        uploading: 0,
        completed: 0,
        failed: 0,
        total: 0
      });

      return stats;
    } catch (error: any) {
      return {
        pending: 0,
        uploading: 0,
        completed: 0,
        failed: 0,
        total: 0
      };
    }
  }

  /**
   * Retry uploads falhados
   */
  async retryFailedUploads(): Promise<void> {
    try {
      const pendingUploads = await getPendingPhotoUploads();
      const failedUploads = pendingUploads.filter(upload => upload.uploadStatus === 'failed');
      
      for (const upload of failedUploads) {
        await this.updateUploadStatus(upload.id, 'pending', 0);
      }
    } catch (error: any) {
      // Silently fail
    }
  }

  /**
   * Limpa uploads antigos
   */
  async cleanupOldUploads(daysOld: number = 7): Promise<void> {
    try {
      const cutoffTime = Date.now() - (daysOld * 24 * 60 * 60 * 1000);
      const pendingUploads = await getPendingPhotoUploads();
      
      const oldUploads = pendingUploads.filter(upload => 
        upload.lastUploadAttempt && upload.lastUploadAttempt < cutoffTime
      );
      
      // Aqui você implementaria a lógica para remover uploads antigos
    } catch (error: any) {
      // Silently fail
    }
  }

  /**
   * Utilitário para dividir array em chunks
   */
  private chunkArray<T>(array: T[], chunkSize: number): T[][] {
    const chunks: T[][] = [];
    for (let i = 0; i < array.length; i += chunkSize) {
      chunks.push(array.slice(i, i + chunkSize));
    }
    return chunks;
  }

  /**
   * Inicia o serviço de upload
   */
  async start(): Promise<void> {
    // Processamento automático desabilitado
    // await this.processUploadQueue();
    
    // Configurar limpeza periódica
    setInterval(() => {
      this.cleanupOldUploads();
    }, 24 * 60 * 60 * 1000); // Diariamente
  }

  /**
   * Força o processamento da fila de uploads (para uso manual)
   */
  async forceProcessQueue(): Promise<void> {
    try {
      await this.processUploadQueue();
    } catch (error: any) {
      // Silently fail
    }
  }

  /**
   * Para o serviço de upload
   */
  stop(): void {
    this.isUploading = false;
    this.uploadQueue = [];
  }
}

// Instância singleton
export const photoUploadService = new PhotoUploadService();
