interface SKUResponse {
  status: boolean;
  SKU: string | null;
}

interface CacheEntry {
  response: SKUResponse;
  timestamp: number;
}

/**
 * Service for identifying product SKUs from shoe images using external API
 */
export class SKUIdentificationService {
  private cache = new Map<string, CacheEntry>();
  private readonly API_ENDPOINT = 'https://pegasus-working-bison.ngrok-free.app/predictfile';
  private readonly CACHE_TTL = 60 * 60 * 1000; // 1 hour cache
  private readonly MAX_CACHE_SIZE = 100; // Prevent memory leaks

  /**
   * Convert ImageData to File object for form-data upload
   */
  private imageDataToFile(imageData: ImageData, filename: string = 'shoe.jpg'): File {
    // Create canvas from ImageData
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d')!;
    canvas.width = imageData.width;
    canvas.height = imageData.height;
    
    // Put image data onto canvas
    ctx.putImageData(imageData, 0, 0);
    
    // Convert canvas to blob then to File
    return new Promise<File>((resolve) => {
      canvas.toBlob((blob) => {
        if (blob) {
          const file = new File([blob], filename, { type: 'image/jpeg' });
          resolve(file);
        }
      }, 'image/jpeg', 0.8); // 80% quality for optimal size/quality balance
    }) as any; // TypeScript workaround for sync return
  }

  /**
   * Generate a simple hash from image data for caching
   */
  private generateImageHash(imageData: ImageData): string {
    // Sample pixels at regular intervals for hash generation
    const step = Math.floor(imageData.data.length / 1000); // Sample ~1000 pixels
    let hash = 0;
    
    for (let i = 0; i < imageData.data.length; i += step) {
      hash = ((hash << 5) - hash + imageData.data[i]) & 0xffffffff;
    }
    
    return hash.toString(36);
  }

  /**
   * Clean expired cache entries and maintain size limit
   */
  private cleanCache(): void {
    const now = Date.now();
    const entries = Array.from(this.cache.entries());
    
    // Remove expired entries
    for (const [key, entry] of entries) {
      if (now - entry.timestamp > this.CACHE_TTL) {
        this.cache.delete(key);
      }
    }
    
    // If still over limit, remove oldest entries
    if (this.cache.size > this.MAX_CACHE_SIZE) {
      const sortedEntries = Array.from(this.cache.entries())
        .sort((a, b) => a[1].timestamp - b[1].timestamp);
      
      const entriesToRemove = sortedEntries.slice(0, this.cache.size - this.MAX_CACHE_SIZE);
      for (const [key] of entriesToRemove) {
        this.cache.delete(key);
      }
    }
  }

  /**
   * Identify product SKU from shoe image
   * @param imageData - Image data captured from video
   * @returns Promise<string | null> - SKU if found, null otherwise
   */
  async identifySKU(imageData: ImageData): Promise<string | null> {
    try {
      // Generate hash for caching
      const imageHash = this.generateImageHash(imageData);
      
      // Check cache first
      const cached = this.cache.get(imageHash);
      if (cached && (Date.now() - cached.timestamp) < this.CACHE_TTL) {
        console.log('🎯 SKU cache hit:', cached.response);
        return cached.response.status && cached.response.SKU ? cached.response.SKU : null;
      }

      console.log('📡 Calling SKU identification API...');
      
      // Convert ImageData to File synchronously (simplified approach)
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d')!;
      canvas.width = imageData.width;
      canvas.height = imageData.height;
      ctx.putImageData(imageData, 0, 0);
      
      // Convert canvas to blob and create File
      const blob = await new Promise<Blob>((resolve) => {
        canvas.toBlob((blob) => resolve(blob!), 'image/jpeg', 0.9); // Higher quality
      });
      
      const file = new File([blob], 'shoe.jpg', { 
        type: 'image/jpeg',
        lastModified: Date.now()
      });
      
      console.log('📸 Created file:', {
        name: file.name,
        size: file.size,
        type: file.type,
        lastModified: file.lastModified
      });
      
      // Prepare form data
      const formData = new FormData();
      formData.append('file', file);
      
      console.log('📤 FormData prepared with file key');
      
      // Debug FormData contents
      for (let [key, value] of formData.entries()) {
        console.log(`📋 FormData entry: ${key} =`, value);
        if (value instanceof File) {
          console.log(`  📄 File details: ${value.name}, ${value.size} bytes, ${value.type}`);
        }
      }

      console.log('🚀 Making API call to:', this.API_ENDPOINT);
      console.log('🔧 Request method: POST');
      console.log('🔧 Request headers:', { 'ngrok-skip-browser-warning': 'true' });
      console.log('🔧 Request body type:', typeof formData, formData.constructor.name);
      
      // Make API call with CORS headers
      const response = await fetch(this.API_ENDPOINT, {
        method: 'POST',
        body: formData,
        mode: 'cors', // Need CORS headers from server
        headers: {
          // Don't set Content-Type, let browser set it with boundary for multipart/form-data
          'ngrok-skip-browser-warning': 'true', // Skip ngrok browser warning
          'Accept': 'application/json', // Tell server we expect JSON
        }
      });

      console.log('📡 Response status:', response.status, response.statusText);
      console.log('📡 Response headers:', Object.fromEntries(response.headers.entries()));

      if (!response.ok) {
        throw new Error(`API call failed: ${response.status} ${response.statusText}`);
      }

      // Try to get response as text first to debug
      const responseText = await response.text();
      console.log('📡 Raw response text:', responseText);

      // Try to parse as JSON
      let data: SKUResponse;
      try {
        data = JSON.parse(responseText);
        console.log('📦 SKU API response parsed:', data);
      } catch (parseError) {
        console.error('❌ Failed to parse JSON response:', parseError);
        console.error('❌ Response was:', responseText);
        throw new Error(`Invalid JSON response: ${parseError}`);
      }

      // Cache the response (both success and failure)
      this.cleanCache();
      this.cache.set(imageHash, {
        response: data,
        timestamp: Date.now()
      });

      // Return SKU only if status is true and SKU is not null
      return data.status && data.SKU ? data.SKU : null;
      
    } catch (error) {
      console.error('❌ SKU identification failed:', error);
      // Return null on any error (network, parsing, etc.)
      return null;
    }
  }

  /**
   * Clear all cached results
   */
  clearCache(): void {
    this.cache.clear();
    console.log('🗑️ SKU cache cleared');
  }

  /**
   * Get cache statistics for debugging
   */
  getCacheStats() {
    const now = Date.now();
    const entries = Array.from(this.cache.values());
    const validEntries = entries.filter(entry => (now - entry.timestamp) < this.CACHE_TTL);
    
    return {
      totalEntries: this.cache.size,
      validEntries: validEntries.length,
      expiredEntries: this.cache.size - validEntries.length,
      cacheHitRate: validEntries.length / Math.max(1, this.cache.size)
    };
  }
}

// Export singleton instance
export const skuIdentificationService = new SKUIdentificationService();