<?php

namespace PortalPeople\NgaugeBackupSql\jobs;

use Yii;
use yii\base\BaseObject;
use PortalPeople\NgaugeBackupSql\components\BackupManager;

/**
 * Database Backup Queue Job
 * 
 * Executes database backups asynchronously via Yii2 queue system.
 * Supports backup of multiple tables and automatic cleanup of old backups.
 * 
 * Usage:
 * ```php
 * use PortalPeople\NgaugeBackupSql\jobs\DatabaseBackupJob;
 * 
 * // Backup specific tables
 * Yii::$app->queue->push(new DatabaseBackupJob([
 *     'tables' => ['users', 'pricing'],
 *     'compress' => true,
 * ]));
 * 
 * // Backup all tables
 * Yii::$app->queue->push(new DatabaseBackupJob([
 *     'tables' => ['*'],
 * ]));
 * ```
 */
class DatabaseBackupJob extends BaseObject implements \common\components\Queue\JobInterface
{
    /**
     * @var array List of table names to backup (use ['*'] for all tables)
     */
    public $tables = [];
    
    /**
     * @var bool Whether to compress backups
     */
    public $compress = true;
    
    /**
     * @var bool Whether to run cleanup after backup
     */
    public $runCleanup = true;
    
    /**
     * @var int|null Override retention days for cleanup (null = use module default)
     */
    public $retentionDays = null;
    
    /**
     * @var string|null Database component to backup (null = use module default)
     */
    public $dbComponent = null;

    /**
     * Execute the backup job
     * 
     * @param \common\components\Queue\Queue $queue Queue instance
     * @return bool Success status
     */
    public function execute($queue)
    {
        try {
            $manager = Yii::createObject(BackupManager::class);
            
            // Override db component if specified
            if ($this->dbComponent !== null) {
                $manager->module->dbComponent = $this->dbComponent;
            }
            
            // Determine tables to backup
            $tablesToBackup = $this->resolveTables($manager);
            
            if (empty($tablesToBackup)) {
                Yii::warning('No tables to backup', __METHOD__);
                return true;
            }
            
            Yii::info('Starting backup of ' . count($tablesToBackup) . ' table(s)', __METHOD__);
            
            $successCount = 0;
            $failedCount = 0;
            
            // Backup each table
            foreach ($tablesToBackup as $table) {
                try {
                    $backupFile = $manager->createBackup($table, null, $this->compress);
                    $successCount++;
                    
                    Yii::info("Backed up table '{$table}': " . basename($backupFile), __METHOD__);
                    
                } catch (\Exception $e) {
                    $failedCount++;
                    Yii::error("Failed to backup table '{$table}': " . $e->getMessage(), __METHOD__);
                }
            }
            
            Yii::info("Backup completed: {$successCount} successful, {$failedCount} failed", __METHOD__);
            
            // Run cleanup if enabled
            if ($this->runCleanup) {
                $this->runBackupCleanup($manager);
            }
            
            return true;
            
        } catch (\Exception $e) {
            Yii::error('Backup job failed: ' . $e->getMessage(), __METHOD__);
            return false;
        }
    }

    /**
     * Get time-to-reserve for this job (in seconds)
     * 
     * @return int TTR in seconds
     */
    public function getTtr()
    {
        // Allow 30 minutes for backup operations
        return 1800;
    }

    /**
     * Resolve which tables to backup
     * 
     * @param BackupManager $manager Backup manager instance
     * @return array List of table names
     */
    protected function resolveTables($manager)
    {
        // If wildcard specified, get all tables
        if (in_array('*', $this->tables)) {
            return $manager->listTables(true);
        }
        
        // Otherwise use specified tables
        return $this->tables;
    }

    /**
     * Run backup cleanup
     * 
     * @param BackupManager $manager Backup manager instance
     */
    protected function runBackupCleanup($manager)
    {
        try {
            $deleted = $manager->cleanupOldBackups($this->retentionDays);
            
            if ($deleted > 0) {
                Yii::info("Cleaned up {$deleted} old backup(s)", __METHOD__);
            }
            
        } catch (\Exception $e) {
            Yii::error('Backup cleanup failed: ' . $e->getMessage(), __METHOD__);
        }
    }
}
