/**
 * Storage Service - CRUD operations for IndexedDB stores
 * Implements specific data access patterns for each entity type
 */

import indexedDBService from './indexedDB.js';

class StorageService {
  constructor() {
    this.db = indexedDBService;
  }

  /**
   * Initialize the storage service
   */
  async init() {
    await this.db.init();
  }

  // ==================== AUTH OPERATIONS ====================

  /**
   * Store authentication data
   */
  async setAuth(authData) {
    const store = this.db.getStore('auth', 'readwrite');
    const authRecord = {
      key: 'current_user',
      token: authData.token,
      user: authData.user,
      expiresAt: authData.expiresAt,
      timestamp: Date.now()
    };
    
    return new Promise((resolve, reject) => {
      const request = store.put(authRecord);
      request.onsuccess = () => resolve(authRecord);
      request.onerror = () => reject(new Error('Error storing auth data'));
    });
  }

  /**
   * Get current authentication data
   */
  async getAuth() {
    const store = this.db.getStore('auth', 'readonly');
    
    return new Promise((resolve, reject) => {
      const request = store.get('current_user');
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting auth data'));
    });
  }

  /**
   * Clear authentication data
   */
  async clearAuth() {
    const store = this.db.getStore('auth', 'readwrite');
    
    return new Promise((resolve, reject) => {
      const request = store.delete('current_user');
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error('Error clearing auth data'));
    });
  }

  // ==================== PROYECTOS OPERATIONS ====================

  /**
   * Store a project
   */
  async saveProject(project) {
    const store = this.db.getStore('proyectos', 'readwrite');
    const projectRecord = {
      id: project.id || Date.now(), // Generate ID if not provided
      fechaCreacion: project.fechaCreacion || new Date().toISOString(),
      nombreProyecto: project.nombreProyecto,
      nombreFinca: project.nombreFinca,
      departamento: project.departamento,
      municipio: project.municipio,
      aldea: project.aldea,
      nombrePropietario: project.nombrePropietario,
      nombreRegenteForestal: project.nombreRegenteForestal,
      docTenenciaPath: project.docTenenciaPath || null,
      docRegenciaPath: project.docRegenciaPath || null,
      usuarioId: project.usuarioId,
      syncStatus: project.syncStatus || 'pending',
      lastModified: Date.now()
    };

    return new Promise((resolve, reject) => {
      const request = store.put(projectRecord);
      request.onsuccess = () => resolve(projectRecord);
      request.onerror = () => reject(new Error('Error saving project'));
    });
  }

  /**
   * Get all projects
   */
  async getProjects() {
    const store = this.db.getStore('proyectos', 'readonly');
    
    return new Promise((resolve, reject) => {
      const request = store.getAll();
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting projects'));
    });
  }

  /**
   * Get project by ID
   */
  async getProject(id) {
    const store = this.db.getStore('proyectos', 'readonly');
    
    return new Promise((resolve, reject) => {
      const request = store.get(id);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting project'));
    });
  }

  /**
   * Delete project
   */
  async deleteProject(id) {
    const store = this.db.getStore('proyectos', 'readwrite');
    
    return new Promise((resolve, reject) => {
      const request = store.delete(id);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error('Error deleting project'));
    });
  }

  // ==================== RODALES OPERATIONS ====================

  /**
   * Store a rodal
   */
  async saveRodal(rodal) {
    const store = this.db.getStore('rodales', 'readwrite');
    const rodalRecord = {
      id: rodal.id || Date.now(),
      proyectoId: rodal.proyectoId,
      nombreRodal: rodal.nombreRodal,
      areaHa: rodal.areaHa,
      fechaCreacion: rodal.fechaCreacion || new Date().toISOString(),
      syncStatus: rodal.syncStatus || 'pending',
      lastModified: Date.now()
    };

    return new Promise((resolve, reject) => {
      const request = store.put(rodalRecord);
      request.onsuccess = () => resolve(rodalRecord);
      request.onerror = () => reject(new Error('Error saving rodal'));
    });
  }

  /**
   * Get rodales by project ID
   */
  async getRodalesByProject(projectId) {
    const store = this.db.getStore('rodales', 'readonly');
    const index = store.index('proyectoId');
    
    return new Promise((resolve, reject) => {
      const request = index.getAll(projectId);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting rodales'));
    });
  }

  /**
   * Get rodal by ID
   */
  async getRodal(id) {
    const store = this.db.getStore('rodales', 'readonly');
    
    return new Promise((resolve, reject) => {
      const request = store.get(id);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting rodal'));
    });
  }

  /**
   * Delete rodal
   */
  async deleteRodal(id) {
    const store = this.db.getStore('rodales', 'readwrite');
    
    return new Promise((resolve, reject) => {
      const request = store.delete(id);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error('Error deleting rodal'));
    });
  }

  // ==================== ESPECIES OPERATIONS ====================

  /**
   * Store species data
   */
  async saveSpecies(species) {
    const store = this.db.getStore('especies', 'readwrite');
    
    return new Promise((resolve, reject) => {
      const request = store.put(species);
      request.onsuccess = () => resolve(species);
      request.onerror = () => reject(new Error('Error saving species'));
    });
  }

  /**
   * Store multiple species (bulk operation)
   */
  async saveSpeciesBulk(speciesArray) {
    const store = this.db.getStore('especies', 'readwrite');
    const promises = speciesArray.map(species => {
      return new Promise((resolve, reject) => {
        const request = store.put(species);
        request.onsuccess = () => resolve(species);
        request.onerror = () => reject(new Error('Error saving species'));
      });
    });

    return Promise.all(promises);
  }

  /**
   * Get all species
   */
  async getSpecies() {
    const store = this.db.getStore('especies', 'readonly');
    
    return new Promise((resolve, reject) => {
      const request = store.getAll();
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting species'));
    });
  }

  // ==================== REGISTROS CAMPO OPERATIONS ====================

  /**
   * Store field data record
   */
  async saveFieldRecord(record) {
    const store = this.db.getStore('registrosCampo', 'readwrite');
    const fieldRecord = {
      id: record.id || `temp_${Date.now()}_${Math.random()}`,
      rodalId: record.rodalId,
      numeroParcela: record.numeroParcela,
      fechaCaptura: record.fechaCaptura || new Date().toISOString(),
      latitud: record.latitud,
      longitud: record.longitud,
      especieId: record.especieId,
      especie: record.especie, // Keep species name for offline display
      dapCm: record.dapCm,
      alturaM: record.alturaM,
      condicionArbol: record.condicionArbol,
      estadoSincronizacion: record.estadoSincronizacion || 'Pendiente',
      usuarioId: record.usuarioId,
      lastModified: Date.now()
    };

    return new Promise((resolve, reject) => {
      const request = store.put(fieldRecord);
      request.onsuccess = () => resolve(fieldRecord);
      request.onerror = () => reject(new Error('Error saving field record'));
    });
  }

  /**
   * Get field records by rodal ID
   */
  async getFieldRecordsByRodal(rodalId) {
    const store = this.db.getStore('registrosCampo', 'readonly');
    const index = store.index('rodalId');
    
    return new Promise((resolve, reject) => {
      const request = index.getAll(rodalId);
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting field records'));
    });
  }

  /**
   * Get pending sync records
   */
  async getPendingSyncRecords() {
    const store = this.db.getStore('registrosCampo', 'readonly');
    const index = store.index('estadoSincronizacion');
    
    return new Promise((resolve, reject) => {
      const request = index.getAll('Pendiente');
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting pending records'));
    });
  }

  /**
   * Update sync status of field records
   */
  async updateSyncStatus(recordIds, status) {
    const store = this.db.getStore('registrosCampo', 'readwrite');
    const promises = recordIds.map(id => {
      return new Promise((resolve, reject) => {
        const getRequest = store.get(id);
        getRequest.onsuccess = () => {
          const record = getRequest.result;
          if (record) {
            record.estadoSincronizacion = status;
            record.lastModified = Date.now();
            const putRequest = store.put(record);
            putRequest.onsuccess = () => resolve(record);
            putRequest.onerror = () => reject(new Error('Error updating sync status'));
          } else {
            resolve(null);
          }
        };
        getRequest.onerror = () => reject(new Error('Error getting record for sync update'));
      });
    });

    return Promise.all(promises);
  }

  // ==================== SYNC QUEUE OPERATIONS ====================

  /**
   * Add operation to sync queue
   */
  async addToSyncQueue(operation) {
    const store = this.db.getStore('syncQueue', 'readwrite');
    const queueItem = {
      operation: operation.type, // 'create', 'update', 'delete'
      entity: operation.entity, // 'project', 'rodal', 'fieldRecord'
      data: operation.data,
      timestamp: Date.now(),
      status: 'pending'
    };

    return new Promise((resolve, reject) => {
      const request = store.add(queueItem);
      request.onsuccess = () => resolve({ ...queueItem, id: request.result });
      request.onerror = () => reject(new Error('Error adding to sync queue'));
    });
  }

  /**
   * Get pending sync operations
   */
  async getPendingSyncOperations() {
    const store = this.db.getStore('syncQueue', 'readonly');
    const index = store.index('status');
    
    return new Promise((resolve, reject) => {
      const request = index.getAll('pending');
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(new Error('Error getting sync queue'));
    });
  }

  /**
   * Remove operation from sync queue
   */
  async removeSyncOperation(id) {
    const store = this.db.getStore('syncQueue', 'readwrite');
    
    return new Promise((resolve, reject) => {
      const request = store.delete(id);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error('Error removing sync operation'));
    });
  }

  // ==================== UTILITY OPERATIONS ====================

  /**
   * Clear all data (for testing/reset)
   */
  async clearAllData() {
    const stores = ['auth', 'proyectos', 'rodales', 'especies', 'registrosCampo', 'syncQueue'];
    const promises = stores.map(storeName => {
      const store = this.db.getStore(storeName, 'readwrite');
      return new Promise((resolve, reject) => {
        const request = store.clear();
        request.onsuccess = () => resolve();
        request.onerror = () => reject(new Error(`Error clearing ${storeName}`));
      });
    });

    return Promise.all(promises);
  }

  /**
   * Get storage statistics
   */
  async getStorageStats() {
    const stores = ['proyectos', 'rodales', 'especies', 'registrosCampo'];
    const stats = {};

    for (const storeName of stores) {
      const store = this.db.getStore(storeName, 'readonly');
      stats[storeName] = await new Promise((resolve, reject) => {
        const request = store.count();
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(new Error(`Error counting ${storeName}`));
      });
    }

    return stats;
  }
}

// Create singleton instance
const storageService = new StorageService();

export default storageService;