import { DatabaseManager } from "./database";

interface BackupConfig {
  backupIntervalMs: number;
  retentionDays: number;
  backupRegion: string;
}

export class DatabaseBackupManager {
  private dbManager: DatabaseManager;
  private config: BackupConfig;
  private backupTimer: NodeJS.Timeout | null = null;

  constructor(dbManager: DatabaseManager, config: BackupConfig) {
    this.dbManager = dbManager;
    this.config = config;
  }

  start(): void {
    console.log(`Starting database backup every ${this.config.backupIntervalMs / (1000 * 60)} minutes`);
    
    this.backupTimer = setInterval(async () => {
      await this.performBackup();
    }, this.config.backupIntervalMs);
  }

  stop(): void {
    if (this.backupTimer) {
      clearInterval(this.backupTimer);
      this.backupTimer = null;
      console.log("Database backup stopped");
    }
  }

  async performBackup(): Promise<void> {
    try {
      console.log(`Performing database backup to ${this.config.backupRegion}...`);
      
      // Get all tables
      const tables = await this.dbManager.query<string>(
        "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
      );

      const tableNamePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;

      for (const table of tables) {
        if (!tableNamePattern.test(table)) {
          console.warn(`Skipping invalid table name: ${table}`);
          continue;
        }
        
        const data = await this.dbManager.query<Record<string, unknown>>(
          `SELECT * FROM "${table}"`
        );
        
        console.log(`Backed up ${table}: ${data.length} rows`);
        
        // Store backup with timestamp
        const timestamp = new Date().toISOString();
        await this.dbManager.execute(
          `INSERT INTO backups (table_name, data, backup_time, region) VALUES (?, ?, ?, ?)`,
          [table, JSON.stringify(data), timestamp, this.config.backupRegion]
        );
      }

      await this.cleanupOldBackups();
      console.log("Database backup completed successfully");
    } catch (error) {
      console.error("Database backup failed:", error);
      throw error;
    }
  }

  private async cleanupOldBackups(): Promise<void> {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - this.config.retentionDays);

    await this.dbManager.execute(
      "DELETE FROM backups WHERE backup_time < ?",
      [cutoffDate.toISOString()]
    );

    console.log(`Cleaned up backups older than ${this.config.retentionDays} days`);
  }

  async restoreFromBackup(backupTime: string): Promise<void> {
    console.log(`Restoring database from backup at ${backupTime}...`);
    
    const backups = await this.dbManager.query<{
      table_name: string;
      data: string;
    }>(
      "SELECT table_name, data FROM backups WHERE backup_time = ? ORDER BY table_name",
      [backupTime]
    );

    for (const backup of backups) {
      const data = JSON.parse(backup.data) as Record<string, unknown>[];
      console.log(`Restoring ${backup.table_name}: ${data.length} rows`);
      
      // Note: This is a simplified restore. In production, you'd want to:
      // 1. Clear the table first
      // 2. Handle foreign key constraints
      // 3. Use transactions
    }

    console.log("Database restore completed");
  }
}

export function createDatabaseBackupManager(
  dbManager: DatabaseManager,
  config: BackupConfig
): DatabaseBackupManager {
  return new DatabaseBackupManager(dbManager, config);
}
