import { IStore } from './IStore';

/**
 * Database configuration
 */
export interface IDBConfig {
  dbName: string;
  dbVersion?: number;
}

export const defaultDBConfig: IDBConfig = {
  dbName: 'CalendarDB',
  dbVersion: 4
};

/**
 * IndexedDBContext - Database connection manager
 *
 * RESPONSIBILITY:
 * - Opens and manages IDBDatabase connection lifecycle
 * - Creates object stores via injected IStore implementations
 * - Provides shared IDBDatabase instance to all services
 */
export class IndexedDBContext {
  private db: IDBDatabase | null = null;
  private initialized: boolean = false;
  private stores: IStore[];
  private config: IDBConfig;

  constructor(stores: IStore[], config: IDBConfig) {
    this.stores = stores;
    this.config = config;
  }

  get dbName(): string {
    return this.config.dbName;
  }

  /**
   * Initialize and open the database
   */
  async initialize(): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.config.dbName, this.config.dbVersion);

      request.onerror = () => {
        reject(new Error(`Failed to open IndexedDB: ${request.error}`));
      };

      request.onsuccess = () => {
        this.db = request.result;
        this.initialized = true;
        resolve();
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;

        // Create all entity stores via injected IStore implementations
        this.stores.forEach(store => {
          if (!db.objectStoreNames.contains(store.storeName)) {
            store.create(db);
          }
        });
      };
    });
  }

  /**
   * Check if database is initialized
   */
  public isInitialized(): boolean {
    return this.initialized;
  }

  /**
   * Get IDBDatabase instance
   */
  public getDatabase(): IDBDatabase {
    if (!this.db) {
      throw new Error('IndexedDB not initialized. Call initialize() first.');
    }
    return this.db;
  }

  /**
   * Close database connection
   */
  close(): void {
    if (this.db) {
      this.db.close();
      this.db = null;
      this.initialized = false;
    }
  }

  /**
   * Delete entire database (for testing/reset)
   */
  static async deleteDatabase(dbName: string = defaultDBConfig.dbName): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.deleteDatabase(dbName);

      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error(`Failed to delete database: ${request.error}`));
    });
  }
}
