import { promises as fs } from 'fs';
import path from 'path';
import { EventEmitter } from 'events';
import { createHash } from 'crypto';
import { gzip, gunzip } from 'zlib';
import { promisify } from 'util';

const gzipAsync = promisify(gzip);
const gunzipAsync = promisify(gunzip);

/**
 * Local File Storage Client for AI-to-AI Data Storage
 * Provides the same interface as DigitalOceanClient but stores data locally
 */
export class LocalStorageClient extends EventEmitter {
  constructor() {
    super();
    
    this.dataDir = path.join(process.cwd(), 'data');
    this.dataPrefix = 'zai-ai-to-ai-data';
    
    // Ensure data directory exists
    this.ensureDataDirectory();
    
    console.log('💾 Local Storage Client initialized');
    console.log(`📁 Data directory: ${this.dataDir}`);
  }

  /**
   * Ensure data directory structure exists
   */
  async ensureDataDirectory() {
    try {
      await fs.mkdir(this.dataDir, { recursive: true });
      await fs.mkdir(path.join(this.dataDir, 'licenses'), { recursive: true });
      await fs.mkdir(path.join(this.dataDir, 'licenses', 'active'), { recursive: true });
      await fs.mkdir(path.join(this.dataDir, 'conversations'), { recursive: true });
      await fs.mkdir(path.join(this.dataDir, 'metrics'), { recursive: true });
      await fs.mkdir(path.join(this.dataDir, 'test'), { recursive: true });
    } catch (error) {
      console.error('❌ Failed to create data directories:', error.message);
    }
  }

  /**
   * Test connection (always succeeds for local storage)
   */
  async testConnection() {
    try {
      console.log('🧪 Testing local storage connection...');
      
      const testData = {
        timestamp: new Date().toISOString(),
        test: 'connection-test',
        message: 'ZAI AI-to-AI System Local Storage Test'
      };
      
      await this.uploadData('test/connection-test.json', testData);
      console.log('✅ Local storage connection successful!');
      
      return true;
    } catch (error) {
      console.error('❌ Local storage connection failed:', error.message);
      throw error;
    }
  }

  /**
   * Upload compressed data to local storage
   */
  async uploadData(key, data, options = {}) {
    try {
      const jsonData = JSON.stringify(data, null, 2);
      const compressedData = await gzipAsync(jsonData);
      
      const filePath = path.join(this.dataDir, key);
      const fileDir = path.dirname(filePath);
      
      // Ensure directory exists
      await fs.mkdir(fileDir, { recursive: true });
      
      // Write compressed data
      await fs.writeFile(filePath, compressedData);
      
      // Write metadata
      const metadataPath = filePath + '.meta';
      const metadata = {
        'original-size': jsonData.length.toString(),
        'compressed-size': compressedData.length.toString(),
        'compression-ratio': (compressedData.length / jsonData.length).toFixed(3),
        'created-at': new Date().toISOString(),
        ...options.metadata
      };
      await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
      
      console.log(`💾 Data stored locally: ${key} (${jsonData.length} → ${compressedData.length} bytes, ${((1 - compressedData.length / jsonData.length) * 100).toFixed(1)}% compression)`);
      
      this.emit('dataUploaded', { key, originalSize: jsonData.length, compressedSize: compressedData.length });
      
      return { Location: filePath, Key: key };
    } catch (error) {
      console.error(`❌ Local storage failed for ${key}:`, error.message);
      throw error;
    }
  }

  /**
   * Download and decompress data from local storage
   */
  async downloadData(key) {
    try {
      const filePath = path.join(this.dataDir, key);
      
      // Check if file exists
      try {
        await fs.access(filePath);
      } catch {
        return null; // File doesn't exist
      }
      
      const compressedData = await fs.readFile(filePath);
      const decompressedData = await gunzipAsync(compressedData);
      const data = JSON.parse(decompressedData.toString());
      
      console.log(`💾 Data loaded locally: ${key}`);
      
      return data;
    } catch (error) {
      console.error(`❌ Local download failed for ${key}:`, error.message);
      throw error;
    }
  }

  /**
   * Store AI-to-AI conversation data
   */
  async storeConversation(userId, conversationData) {
    const userHash = this.hashUserId(userId);
    const timestamp = new Date().toISOString();
    const date = timestamp.split('T')[0];
    
    const key = `conversations/${date}/${userHash}/${Date.now()}.json`;
    
    const data = {
      timestamp,
      userId: userHash,
      conversation: conversationData,
      metadata: {
        messageCount: conversationData.messages?.length || 0,
        duration: conversationData.duration || 0,
        model: conversationData.model || 'unknown',
        success: conversationData.success || false
      }
    };
    
    return await this.uploadData(key, data);
  }

  /**
   * Store user metrics and analytics
   */
  async storeUserMetrics(userId, metrics) {
    const userHash = this.hashUserId(userId);
    const timestamp = new Date().toISOString();
    const date = timestamp.split('T')[0];
    
    const key = `metrics/${date}/${userHash}.json`;
    
    // Try to get existing metrics for the day
    let existingMetrics = await this.downloadData(key);
    if (!existingMetrics) {
      existingMetrics = {
        date,
        userId: userHash,
        sessions: [],
        totalUsage: {
          conversations: 0,
          totalMessages: 0,
          totalDuration: 0,
          successRate: 0
        }
      };
    }
    
    // Add new session
    existingMetrics.sessions.push({
      timestamp,
      ...metrics
    });
    
    // Update totals
    existingMetrics.totalUsage.conversations++;
    existingMetrics.totalUsage.totalMessages += metrics.messageCount || 0;
    existingMetrics.totalUsage.totalDuration += metrics.duration || 0;
    
    const successfulSessions = existingMetrics.sessions.filter(s => s.success).length;
    existingMetrics.totalUsage.successRate = successfulSessions / existingMetrics.sessions.length;
    
    return await this.uploadData(key, existingMetrics);
  }

  /**
   * Store license information
   */
  async storeLicense(licenseData) {
    const key = `licenses/active/${licenseData.licenseId}.json`;
    
    const data = {
      ...licenseData,
      createdAt: licenseData.createdAt || new Date().toISOString(),
      lastUpdated: new Date().toISOString()
    };
    
    return await this.uploadData(key, data);
  }

  /**
   * Get all licenses
   */
  async getAllLicenses() {
    try {
      const licensesDir = path.join(this.dataDir, 'licenses', 'active');
      const files = await fs.readdir(licensesDir);
      const licenses = [];
      
      for (const file of files) {
        if (file.endsWith('.json') && !file.endsWith('.meta')) {
          const licenseData = await this.downloadData(`licenses/active/${file}`);
          if (licenseData) {
            licenses.push(licenseData);
          }
        }
      }
      
      return licenses.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
    } catch (error) {
      console.error('❌ Failed to get all licenses:', error.message);
      return [];
    }
  }

  /**
   * Delete a license
   */
  async deleteLicense(licenseId) {
    try {
      const key = `licenses/active/${licenseId}.json`;
      const filePath = path.join(this.dataDir, key);
      const metaPath = filePath + '.meta';
      
      await fs.unlink(filePath);
      
      // Also delete metadata file if it exists
      try {
        await fs.unlink(metaPath);
      } catch {
        // Metadata file might not exist, ignore
      }
      
      console.log(`🗑️ License deleted: ${licenseId}`);
      return { success: true, message: 'License deleted successfully' };
    } catch (error) {
      console.error(`❌ Failed to delete license ${licenseId}:`, error.message);
      throw error;
    }
  }

  /**
   * Get aggregated analytics data
   */
  async getAnalytics(dateRange = null) {
    try {
      const metricsDir = path.join(this.dataDir, 'metrics');
      const analytics = {
        totalUsers: 0,
        totalConversations: 0,
        totalMessages: 0,
        averageSuccessRate: 0,
        dailyStats: {}
      };
      
      const userMetrics = new Set();
      let totalSuccessRate = 0;
      let metricsCount = 0;
      
      // Read all metric files
      const walkDir = async (dir) => {
        try {
          const files = await fs.readdir(dir);
          for (const file of files) {
            const filePath = path.join(dir, file);
            const stat = await fs.stat(filePath);
            
            if (stat.isDirectory()) {
              await walkDir(filePath);
            } else if (file.endsWith('.json') && !file.endsWith('.meta')) {
              const relativePath = path.relative(this.dataDir, filePath);
              const metrics = await this.downloadData(relativePath);
              
              if (metrics) {
                userMetrics.add(metrics.userId);
                analytics.totalConversations += metrics.totalUsage.conversations;
                analytics.totalMessages += metrics.totalUsage.totalMessages;
                totalSuccessRate += metrics.totalUsage.successRate;
                metricsCount++;
                
                analytics.dailyStats[metrics.date] = analytics.dailyStats[metrics.date] || {
                  users: 0,
                  conversations: 0,
                  messages: 0
                };
                
                analytics.dailyStats[metrics.date].users++;
                analytics.dailyStats[metrics.date].conversations += metrics.totalUsage.conversations;
                analytics.dailyStats[metrics.date].messages += metrics.totalUsage.totalMessages;
              }
            }
          }
        } catch (error) {
          // Directory might not exist yet
        }
      };
      
      await walkDir(metricsDir);
      
      analytics.totalUsers = userMetrics.size;
      analytics.averageSuccessRate = metricsCount > 0 ? totalSuccessRate / metricsCount : 0;
      
      return analytics;
    } catch (error) {
      console.error('❌ Failed to get analytics:', error.message);
      return {
        totalUsers: 0,
        totalConversations: 0,
        totalMessages: 0,
        averageSuccessRate: 0,
        dailyStats: {}
      };
    }
  }

  /**
   * Hash user ID for privacy
   */
  hashUserId(userId) {
    return createHash('sha256').update(userId.toString()).digest('hex').substring(0, 16);
  }
}
