import type { SecurityCore } from '@core/security';
import { DatabaseProvider } from './DatabaseProvider';
import { SchemaRegistry } from './SchemaRegistry';
import type { StorageConfig, CollectionSchema, DatabaseInstance } from './types';

/**
 * Core Storage SDK
 * Provides encrypted local database management with RxDB/SQLCipher
 * 
 * Key Features (per FRD):
 * - F.STC.001: Abstraction layer over RxDB/SQLite with SQLCipher encryption
 * - F.STC.002: Schema registration for feature SDKs
 * - F.STC.003: Conflict resolution strategies (CRDT configuration, LWW handling)
 * - F.STC.004: Encrypted file vault for local media storage
 * - F.STC.005: Automated database schema migration
 * - F.STC.006: Incremental encryption re-keying
 * - F.STC.007: Selective purge mechanisms
 */
export class StorageCore {
  private config: StorageConfig;
  private securityCore: SecurityCore;
  private databaseProvider: DatabaseProvider;
  private schemaRegistry: SchemaRegistry;
  private initialized = false;

  constructor(config: StorageConfig, securityCore: SecurityCore) {
    this.config = config;
    this.securityCore = securityCore;
    this.databaseProvider = new DatabaseProvider(config, securityCore);
    this.schemaRegistry = new SchemaRegistry();
  }

  /**
   * F.STC.001: Initialize the storage layer with encryption
   */
  async initialize(): Promise<void> {
    if (this.initialized) return;

    await this.databaseProvider.initialize();
    this.initialized = true;
  }

  /**
   * F.STC.002: Register schema for feature SDKs
   */
  registerSchema(collectionName: string, schema: CollectionSchema): void {
    this.schemaRegistry.register(collectionName, schema);
  }

  /**
   * Get the database instance
   */
  getDatabase(): DatabaseInstance {
    this.ensureInitialized();
    return this.databaseProvider.getInstance();
  }

  /**
   * F.STC.002: Create collection with registered schema
   */
  async createCollection(name: string): Promise<void> {
    this.ensureInitialized();
    
    const schema = this.schemaRegistry.getSchema(name);
    if (!schema) {
      throw new Error(`Schema not registered for collection: ${name}`);
    }

    await this.databaseProvider.createCollection(name, schema);
  }

  /**
   * F.STC.004: Store encrypted file
   */
  async storeEncryptedFile(
    filename: string,
    data: Buffer,
    mimeType: string,
    orgId?: string
  ): Promise<string> {
    this.ensureInitialized();

    // Encrypt file content
    const encryptResult = orgId 
      ? await this.securityCore.encryptForOrganization(data.toString('base64'), orgId)
      : await this.encryptFileLocally(data);

    // Store encrypted file to filesystem
    const encryptedPath = await this.writeEncryptedFile(filename, encryptResult.encryptedData);

    // Store metadata in database
    const fileId = this.generateFileId();
    const metadata = {
      id: fileId,
      filename,
      mimeType,
      size: data.length,
      encryptedPath,
      keyReference: JSON.stringify(encryptResult.keyReference),
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString()
    };

    const db = this.getDatabase();
    await db.collections.fileVault.insert(metadata);

    return fileId;
  }

  /**
   * F.STC.004: Retrieve encrypted file
   */
  async retrieveEncryptedFile(fileId: string, orgId?: string): Promise<Buffer> {
    this.ensureInitialized();

    const db = this.getDatabase();
    const metadata = await db.collections.fileVault.findOne(fileId).exec();
    
    if (!metadata) {
      throw new Error(`File not found: ${fileId}`);
    }

    // Read encrypted file
    const encryptedData = await this.readEncryptedFile(metadata.encryptedPath);
    const keyReference = JSON.parse(metadata.keyReference);

    // Decrypt file content
    const decryptedData = orgId
      ? await this.securityCore.decryptForOrganization(encryptedData, keyReference)
      : await this.decryptFileLocally(encryptedData, keyReference);

    return Buffer.from(decryptedData, 'base64');
  }

  /**
   * F.STC.007: Selective purge by organization
   */
  async purgeOrganizationData(orgId: string): Promise<void> {
    this.ensureInitialized();

    const db = this.getDatabase();
    
    // Find all collections and purge org-specific data
    for (const [collectionName, collection] of Object.entries(db.collections)) {
      // Remove documents with matching orgId
      await collection.find({ orgId }).remove();
    }

    // Purge encrypted files belonging to organization
    const orgFiles = await db.collections.fileVault
      .find()
      .where('keyReference')
      .regex(new RegExp(orgId))
      .exec();

    for (const file of orgFiles) {
      await this.deleteEncryptedFile(file.encryptedPath);
      await file.remove();
    }
  }

  /**
   * F.STC.006: Re-encrypt data with new keys
   */
  async reEncryptData(orgId: string, newKeyReference: any): Promise<void> {
    this.ensureInitialized();
    
    // This would implement re-encryption of existing data
    // when organizational keys are rotated
    console.warn('Re-encryption implementation needed');
  }

  /**
   * Get sync status for collections
   */
  getSyncStatus(collectionName: string): any {
    this.ensureInitialized();
    
    const db = this.getDatabase();
    return db.collections[collectionName]?.find({ syncStatus: 'PENDING' });
  }

  private async encryptFileLocally(data: Buffer): Promise<any> {
    // Implementation would use local encryption for non-org files
    throw new Error('Local file encryption not implemented');
  }

  private async decryptFileLocally(encryptedData: string, keyReference: any): Promise<string> {
    // Implementation would use local decryption for non-org files
    throw new Error('Local file decryption not implemented');
  }

  private async writeEncryptedFile(filename: string, encryptedData: string): Promise<string> {
    // Implementation would write to secure app documents directory
    const path = `/secure/${this.generateFileId()}_${filename}`;
    console.warn('File system integration needed');
    return path;
  }

  private async readEncryptedFile(path: string): Promise<string> {
    // Implementation would read from secure app documents directory
    console.warn('File system integration needed');
    return 'mock-encrypted-data';
  }

  private async deleteEncryptedFile(path: string): Promise<void> {
    // Implementation would securely delete file
    console.warn('Secure file deletion needed');
  }

  private generateFileId(): string {
    return `file_${Date.now()}_${Math.random().toString(36).substring(2)}`;
  }

  private ensureInitialized(): void {
    if (!this.initialized) {
      throw new Error('StorageCore must be initialized before use');
    }
  }
}