/**
 * TimeSafari Storage Adapter
 * 
 * Implements storage adapter pattern for TimeSafari database integration.
 * Supports SQLite (native) and fallback storage.
 * 
 * @author Matthew Raymer
 * @version 1.0.0
 */

import { TimeSafariStorageAdapter } from './timesafari-integration';

/**
 * TimeSafari Storage Adapter Implementation
 * 
 * Provides unified storage interface across Android (SQLite) and iOS (SQLite)
 * platforms with TimeSafari-specific patterns.
 */
export class TimeSafariStorageAdapterImpl implements TimeSafariStorageAdapter {
  private storage: StorageInterface;
  private prefix: string;
  private ttlManager: TTLManager;

  constructor(storage: StorageInterface, prefix = 'timesafari_notifications') {
    this.storage = storage;
    this.prefix = prefix;
    this.ttlManager = new TTLManager();
  }

  /**
   * Store data with TTL support
   * 
   * @param key - Storage key
   * @param value - Value to store
   * @param ttlSeconds - Optional TTL in seconds
   */
  async store(key: string, value: unknown, ttlSeconds?: number): Promise<void> {
    try {
      const prefixedKey = this.getPrefixedKey(key);
      const storageValue = {
        data: value,
        timestamp: Date.now(),
        ttl: ttlSeconds ? Date.now() + (ttlSeconds * 1000) : null
      };

      await this.storage.setItem(prefixedKey, JSON.stringify(storageValue));
      
      // Register TTL if provided
      if (ttlSeconds) {
        this.ttlManager.registerTTL(prefixedKey, ttlSeconds);
      }

      // Successfully stored key
    } catch (error) {
      throw new Error(`Failed to store key: ${key}`);
    }
  }

  /**
   * Retrieve data with TTL validation
   * 
   * @param key - Storage key
   * @returns Stored value or null if not found/expired
   */
  async retrieve(key: string): Promise<unknown> {
    try {
      const prefixedKey = this.getPrefixedKey(key);
      const stored = await this.storage.getItem(prefixedKey);
      
      if (!stored) {
        return null;
      }

      const storageValue = JSON.parse(stored);
      
      // Check TTL
      if (storageValue.ttl && Date.now() > storageValue.ttl) {
        // Key expired, cleaning up
        await this.remove(key); // Clean up expired data
        return null;
      }

      // Successfully retrieved key
      return storageValue.data;
    } catch (error) {
      // Failed to retrieve key, returning null
      return null;
    }
  }

  /**
   * Remove data from storage
   * 
   * @param key - Storage key
   */
  async remove(key: string): Promise<void> {
    try {
      const prefixedKey = this.getPrefixedKey(key);
      await this.storage.removeItem(prefixedKey);
      this.ttlManager.unregisterTTL(prefixedKey);
      
      // Successfully removed key
    } catch (error) {
      throw new Error(`Failed to remove key: ${key}`);
    }
  }

  /**
   * Clear all data with prefix
   */
  async clear(): Promise<void> {
    try {
      const keys = await this.storage.getAllKeys();
      const prefixedKeys = keys.filter(key => key.startsWith(this.prefix));
      
      for (const key of prefixedKeys) {
        await this.storage.removeItem(key);
        this.ttlManager.unregisterTTL(key);
      }
      
      // Successfully cleared storage
    } catch (error) {
      throw new Error('Failed to clear storage');
    }
  }

  /**
   * Get prefixed key
   * 
   * @param key - Original key
   * @returns Prefixed key
   */
  private getPrefixedKey(key: string): string {
    return `${this.prefix}_${key}`;
  }

  /**
   * Clean up expired data
   */
  async cleanupExpired(): Promise<void> {
    try {
      const keys = await this.storage.getAllKeys();
      const prefixedKeys = keys.filter(key => key.startsWith(this.prefix));
      
      for (const key of prefixedKeys) {
        const stored = await this.storage.getItem(key);
        if (stored) {
          const storageValue = JSON.parse(stored);
          if (storageValue.ttl && Date.now() > storageValue.ttl) {
            await this.storage.removeItem(key);
            this.ttlManager.unregisterTTL(key);
            // Cleaned up expired key
          }
        }
      }
    } catch (error) {
      // Failed to cleanup expired data, continuing
    }
  }

  /**
   * Get storage statistics
   * 
   * @returns Storage statistics
   */
  async getStats(): Promise<StorageStats> {
    try {
      const keys = await this.storage.getAllKeys();
      const prefixedKeys = keys.filter(key => key.startsWith(this.prefix));
      
      let totalSize = 0;
      let expiredCount = 0;
      let validCount = 0;
      
      for (const key of prefixedKeys) {
        const stored = await this.storage.getItem(key);
        if (stored) {
          totalSize += stored.length;
          const storageValue = JSON.parse(stored);
          if (storageValue.ttl && Date.now() > storageValue.ttl) {
            expiredCount++;
          } else {
            validCount++;
          }
        }
      }
      
      return {
        totalKeys: prefixedKeys.length,
        validKeys: validCount,
        expiredKeys: expiredCount,
        totalSizeBytes: totalSize,
        prefix: this.prefix
      };
    } catch (error) {
      // Failed to get stats, returning default
      return {
        totalKeys: 0,
        validKeys: 0,
        expiredKeys: 0,
        totalSizeBytes: 0,
        prefix: this.prefix
      };
    }
  }
}

/**
 * Storage Interface
 */
export interface StorageInterface {
  getItem(key: string): Promise<string | null>;
  setItem(key: string, value: string): Promise<void>;
  removeItem(key: string): Promise<void>;
  getAllKeys(): Promise<string[]>;
}

/**
 * TTL Manager for managing time-to-live data
 */
class TTLManager {
  private ttlMap: Map<string, NodeJS.Timeout> = new Map();

  /**
   * Register TTL for a key
   * 
   * @param key - Storage key
   * @param ttlSeconds - TTL in seconds
   */
  registerTTL(key: string, ttlSeconds: number): void {
    // Clear existing TTL if any
    this.unregisterTTL(key);
    
    // Set new TTL
    const timeout = setTimeout(() => {
      // TTL expired for key
      this.ttlMap.delete(key);
    }, ttlSeconds * 1000);
    
    this.ttlMap.set(key, timeout);
  }

  /**
   * Unregister TTL for a key
   * 
   * @param key - Storage key
   */
  unregisterTTL(key: string): void {
    const timeout = this.ttlMap.get(key);
    if (timeout) {
      clearTimeout(timeout);
      this.ttlMap.delete(key);
    }
  }

  /**
   * Clear all TTLs
   */
  clearAll(): void {
    for (const timeout of this.ttlMap.values()) {
      clearTimeout(timeout);
    }
    this.ttlMap.clear();
  }
}

/**
 * Storage Statistics
 */
export interface StorageStats {
  totalKeys: number;
  validKeys: number;
  expiredKeys: number;
  totalSizeBytes: number;
  prefix: string;
}


/**
 * LocalStorage Storage Implementation for Web (fallback)
 */
export class LocalStorageStorage implements StorageInterface {
  async getItem(key: string): Promise<string | null> {
    return localStorage.getItem(key);
  }

  async setItem(key: string, value: string): Promise<void> {
    localStorage.setItem(key, value);
  }

  async removeItem(key: string): Promise<void> {
    localStorage.removeItem(key);
  }

  async getAllKeys(): Promise<string[]> {
    const keys: string[] = [];
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i);
      if (key) keys.push(key);
    }
    return keys;
  }
}

/**
 * Storage Factory
 */
export class StorageFactory {
  /**
   * Create appropriate storage implementation
   * 
   * @param platform - Platform type
   * @returns Storage implementation
   */
  static createStorage(platform: 'android' | 'ios' | 'electron'): StorageInterface {
    switch (platform) {
      case 'android':
      case 'ios':
        // For native platforms, this would integrate with SQLite
        // For now, return localStorage as placeholder
        return new LocalStorageStorage();
      case 'electron':
        // Electron can use either SQLite or localStorage
        // For now, return localStorage as placeholder
        return new LocalStorageStorage();
      default:
        throw new Error(`Unsupported platform: ${platform}`);
    }
  }
}
