/**
 * @ai-summary IndexedDB storage adapter for Auth0 and Zustand persistence
 * @ai-context Replaces localStorage with IndexedDB for mobile browser compatibility
 */

interface StorageAdapter {
  getItem(key: string): string | null;
  setItem(key: string, value: string): void;
  removeItem(key: string): void;
  clear(): void;
  key(index: number): string | null;
  readonly length: number;
}

interface Auth0Cache {
  get(key: string): Promise<any>;
  set(key: string, value: any): Promise<void>;
  remove(key: string): Promise<void>;
}

class IndexedDBStorage implements StorageAdapter, Auth0Cache {
  private dbName = 'motovaultpro-storage';
  private dbVersion = 1;
  private storeName = 'keyvalue';
  private db: IDBDatabase | null = null;
  private memoryCache = new Map<string, string>();
  private initPromise: Promise<void>;
  private isReady = false;

  constructor() {
    this.initPromise = this.initialize();
  }

  private async initialize(): Promise<void> {
    try {
      this.db = await this.openDatabase();
      await this.loadCacheFromDB();
      this.isReady = true;
      console.log('[IndexedDB] Storage initialized successfully');
    } catch (error) {
      console.error('[IndexedDB] Initialization failed, using memory only:', error);
      this.isReady = false;
    }
  }

  private openDatabase(): Promise<IDBDatabase> {
    return new Promise((resolve) => {
      const request = indexedDB.open(this.dbName, this.dbVersion);

      request.onerror = () => {
        console.error(`IndexedDB open failed: ${request.error?.message}`);
        resolve(null as any); // Fallback to memory-only mode
      };

      request.onsuccess = () => {
        resolve(request.result);
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains(this.storeName)) {
          db.createObjectStore(this.storeName);
        }
      };
    });
  }

  private async loadCacheFromDB(): Promise<void> {
    if (!this.db) return;

    return new Promise((resolve) => {
      const transaction = this.db!.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const request = store.getAll();

      request.onsuccess = () => {
        const results = request.result;
        this.memoryCache.clear();

        for (const item of results) {
          if (item.key && typeof item.value === 'string') {
            this.memoryCache.set(item.key, item.value);
          }
        }

        console.log(`[IndexedDB] Loaded ${this.memoryCache.size} items into cache`);
        resolve();
      };

      request.onerror = () => {
        console.warn('[IndexedDB] Failed to load cache from DB:', request.error);
        resolve(); // Don't fail initialization
      };
    });
  }

  private async persistToDB(key: string, value: string | null): Promise<void> {
    if (!this.db) return;

    return new Promise((resolve) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);

      if (value === null) {
        const request = store.delete(key);
        request.onsuccess = () => resolve();
        request.onerror = () => {
          console.warn(`[IndexedDB] Failed to delete ${key}:`, request.error);
          resolve();
        };
      } else {
        const request = store.put(value, key);
        request.onsuccess = () => resolve();
        request.onerror = () => {
          console.warn(`[IndexedDB] Failed to persist ${key}:`, request.error);
          resolve();
        };
      }
    });
  }

  // Synchronous Storage interface (uses memory cache)
  getItem(key: string): string | null {
    return this.memoryCache.get(key) || null;
  }

  setItem(key: string, value: string): void {
    this.memoryCache.set(key, value);

    // Async persist to IndexedDB (non-blocking)
    if (this.isReady) {
      this.persistToDB(key, value).catch(error => {
        console.warn(`[IndexedDB] Background persist failed for ${key}:`, error);
      });
    }
  }

  removeItem(key: string): void {
    this.memoryCache.delete(key);

    // Async remove from IndexedDB (non-blocking)
    if (this.isReady) {
      this.persistToDB(key, null).catch(error => {
        console.warn(`[IndexedDB] Background removal failed for ${key}:`, error);
      });
    }
  }

  clear(): void {
    this.memoryCache.clear();

    // Async clear IndexedDB (non-blocking)
    if (this.db) {
      const transaction = this.db.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      store.clear();
    }
  }

  key(index: number): string | null {
    const keys = Array.from(this.memoryCache.keys());
    return keys[index] || null;
  }

  get length(): number {
    return this.memoryCache.size;
  }

  // Auth0 Cache interface implementation
  async get(key: string): Promise<any> {
    await this.initPromise;
    const value = this.getItem(key);
    return value ? JSON.parse(value) : undefined;
  }

  async set(key: string, value: any): Promise<void> {
    await this.initPromise;
    this.setItem(key, JSON.stringify(value));
  }

  async remove(key: string): Promise<void> {
    await this.initPromise;
    this.removeItem(key);
  }

  // Additional methods for enhanced functionality
  async waitForReady(): Promise<void> {
    return this.initPromise;
  }

  get isInitialized(): boolean {
    return this.isReady;
  }

  // For debugging
  getStats() {
    return {
      cacheSize: this.memoryCache.size,
      isReady: this.isReady,
      hasDB: !!this.db
    };
  }
}

// Create singleton instance
export const indexedDBStorage = new IndexedDBStorage();

// For Auth0 compatibility - ensure storage is ready before use
export const createIndexedDBAdapter = () => {
  return indexedDBStorage;
};