<?php
declare(strict_types=1);

// Christo Lochenberg Developments | info@christodev.co.za | +27 61 523 9126
class AdminBackups extends Controller {
    
    public function __construct() {
        if (!isLoggedIn() || !isAdmin()) {
            header('Location: ' . URLROOT . '/users/login');
            exit;
        }
    }

    public function backups(): void {
        $backupDir = APPROOT . '/backups/';
        
        if (!is_dir($backupDir)) {
            mkdir($backupDir, 0755, true);
        }

        $files = scandir($backupDir);
        $backups = [];

        foreach ($files as $file) {
            if (pathinfo($file, PATHINFO_EXTENSION) === 'sql') {
                $filePath = $backupDir . $file;
                
                $dateStr = str_replace(['backup_', '.sql'], '', $file);
                $dateObj = DateTime::createFromFormat('Y-m-d_H-i-s', $dateStr);
                $formattedDate = $dateObj ? $dateObj->format('Y-m-d H:i:s') : 'Unknown';

                $bytes = filesize($filePath);
                $units = ['B', 'KB', 'MB', 'GB'];
                $bytes = max($bytes, 0);
                $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
                $pow = min($pow, count($units) - 1);
                $bytes /= (1 << (10 * $pow));
                $formattedSize = round($bytes, 2) . ' ' . $units[$pow];

                $backups[] = [
                    'filename' => $file,
                    'date' => $formattedDate,
                    'timestamp' => filemtime($filePath),
                    'size' => $formattedSize
                ];
            }
        }

        usort($backups, function($a, $b) {
            return $b['timestamp'] <=> $a['timestamp'];
        });

        $data = [
            'title' => 'Database Backups',
            'description' => 'Create and manage manual snapshots of your database.',
            'backups' => $backups,
            
            // Contextual Help
            'help_title' => 'Database Snapshots Guide',
            'help_content' => '
                <h4 class="font-bold text-gray-800 dark:text-gray-200 mt-0">Database Snapshots</h4>
                <p>The backup generator creates complete, native SQL dumps of your entire database schema and current data via a 100% native PHP script (no shell access required).</p>
                <ul class="list-disc pl-5 space-y-2 mt-2">
                    <li><strong>Generation:</strong> Clicking "Generate Backup" extracts all tables, turns off foreign key checks to prevent locking, and saves the file securely in the <code>/backups/</code> directory on your server.</li>
                    <li><strong>Management:</strong> You can download these .sql files directly to your local machine for safekeeping, or permanently delete old backups to free up server space.</li>
                    <li><strong>Best Practice:</strong> Always generate and download a fresh backup before installing an OTA update or making significant configuration changes.</li>
                </ul>
            '
        ];

        $this->view('admin/backups', $data);
    }

    public function createBackup(): void {
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            
            $backupDir = APPROOT . '/backups/';
            if (!is_dir($backupDir)) {
                mkdir($backupDir, 0755, true);
            }

            $filename = 'backup_' . date('Y-m-d_H-i-s') . '.sql';
            $filePath = $backupDir . $filename;

            try {
                $pdo = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4', DB_USER, DB_PASS);
                $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

                $tables = [];
                $query = $pdo->query('SHOW TABLES');
                while ($row = $query->fetch(PDO::FETCH_NUM)) {
                    $tables[] = $row[0];
                }

                $sql = "-- Database Backup for " . DB_NAME . "\n";
                $sql .= "-- Generated: " . date('Y-m-d H:i:s') . "\n\n";
                $sql .= "SET FOREIGN_KEY_CHECKS=0;\n\n";

                foreach ($tables as $table) {
                    $query = $pdo->query("SHOW CREATE TABLE `$table`");
                    $row = $query->fetch(PDO::FETCH_NUM);
                    $sql .= "DROP TABLE IF EXISTS `$table`;\n";
                    $sql .= $row[1] . ";\n\n";

                    $query = $pdo->query("SELECT * FROM `$table`");
                    $rowCount = $query->rowCount();
                    $numCols = $query->columnCount();

                    if ($rowCount > 0) {
                        $sql .= "INSERT INTO `$table` VALUES\n";
                        $rowIdx = 0;
                        while ($row = $query->fetch(PDO::FETCH_NUM)) {
                            $sql .= "(";
                            for ($i = 0; $i < $numCols; $i++) {
                                $val = $row[$i];
                                if (is_null($val)) {
                                    $sql .= "NULL";
                                } else {
                                    // ZERO-BREAKAGE: Explicitly cast to string to prevent PHP 8 TypeErrors
                                    $val = addslashes((string)$val);
                                    $val = str_replace("\n", "\\n", $val);
                                    $sql .= "'" . $val . "'";
                                }
                                if ($i < ($numCols - 1)) {
                                    $sql .= ",";
                                }
                            }
                            $sql .= ")";
                            
                            if ($rowIdx < ($rowCount - 1)) {
                                $sql .= ",\n";
                            } else {
                                $sql .= ";\n\n";
                            }
                            $rowIdx++;
                        }
                    }
                }
                
                $sql .= "SET FOREIGN_KEY_CHECKS=1;\n";

                if (file_put_contents($filePath, $sql) !== false && filesize($filePath) > 0) {
                    systemLog('BACKUP_CREATED', "A manual database backup was generated: {$filename}");
                    flash('system_msg', 'Backup created successfully!', 'success');
                } else {
                    throw new Exception("Failed to write to backup file. Check directory permissions.");
                }

            } catch (Exception $e) {
                if (file_exists($filePath)) {
                    @unlink($filePath);
                }
                error_log("Backup generation failed: " . $e->getMessage());
                flash('system_msg', 'Failed to generate backup. See error log for details.', 'error');
            }

            header('Location: ' . URLROOT . '/admin/backups');
            exit;
        }
    }

    public function downloadBackup(string $filename): void {
        $filename = basename($filename);
        $filePath = APPROOT . '/backups/' . $filename;

        if (file_exists($filePath) && pathinfo($filePath, PATHINFO_EXTENSION) === 'sql') {
            
            systemLog('BACKUP_DOWNLOADED', "Admin downloaded database backup: {$filename}");
            
            header('Content-Description: File Transfer');
            header('Content-Type: application/sql');
            header('Content-Disposition: attachment; filename="' . $filename . '"');
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Length: ' . filesize($filePath));
            readfile($filePath);
            exit;
        } else {
            flash('system_msg', 'Backup file not found.', 'error');
            header('Location: ' . URLROOT . '/admin/backups');
            exit;
        }
    }

    public function deleteBackup(string $filename): void {
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            $filename = basename($filename);
            $filePath = APPROOT . '/backups/' . $filename;

            if (file_exists($filePath) && pathinfo($filePath, PATHINFO_EXTENSION) === 'sql') {
                if (@unlink($filePath)) {
                    systemLog('BACKUP_DELETED', "Admin permanently deleted database backup: {$filename}");
                    flash('system_msg', 'Backup deleted successfully!', 'success');
                } else {
                    flash('system_msg', 'Failed to delete backup file. Check permissions.', 'error');
                }
            } else {
                flash('system_msg', 'Backup file not found.', 'error');
            }
            
            header('Location: ' . URLROOT . '/admin/backups');
            exit;
        }
    }
}