<?php
declare(strict_types=1);
require_once __DIR__ . '/../app/bootstrap.php';

use App\Core\Database;

$isCli = PHP_SAPI === 'cli';
if (!$isCli) {
    $token = (string)($_GET['token'] ?? '');
    if (CRON_TOKEN === '' || !hash_equals(CRON_TOKEN, $token)) {
        http_response_code(403);
        exit('Forbidden');
    }
    header('Content-Type: text/plain; charset=utf-8');
}

$job = 'backup';
$started = date('Y-m-d H:i:s');
$status = 'failed';
$message = '';
$filePath = null;
try {
    $pdo = Database::pdo();
    if (!$pdo) throw new RuntimeException('Database connection unavailable: ' . Database::lastError());
    $dir = ROOT_PATH . '/storage/backups';
    if (!is_dir($dir) && !mkdir($dir, 0750, true) && !is_dir($dir)) throw new RuntimeException('Could not create backup directory.');
    $filePath = $dir . '/database-' . date('Ymd-His') . '.sql';
    $fh = fopen($filePath, 'wb');
    if (!$fh) throw new RuntimeException('Could not create backup file.');
    fwrite($fh, "-- " . APP_NAME . " database backup\n-- Generated: " . date('c') . "\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS=0;\n\n");
    $tables = $pdo->query('SHOW FULL TABLES WHERE Table_type = "BASE TABLE"')->fetchAll(PDO::FETCH_NUM);
    foreach ($tables as $tableRow) {
        $table = (string)$tableRow[0];
        $quoted = '`' . str_replace('`', '``', $table) . '`';
        $create = $pdo->query('SHOW CREATE TABLE ' . $quoted)->fetch(PDO::FETCH_NUM);
        fwrite($fh, "DROP TABLE IF EXISTS {$quoted};\n" . ($create[1] ?? '') . ";\n\n");
        $stmt = $pdo->query('SELECT * FROM ' . $quoted);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $columns = array_map(static fn($c) => '`' . str_replace('`', '``', (string)$c) . '`', array_keys($row));
            $values = array_map(static function ($value) use ($pdo): string {
                if ($value === null) return 'NULL';
                return $pdo->quote((string)$value);
            }, array_values($row));
            fwrite($fh, 'INSERT INTO ' . $quoted . ' (' . implode(',', $columns) . ') VALUES (' . implode(',', $values) . ");\n");
        }
        fwrite($fh, "\n");
    }
    fwrite($fh, "SET FOREIGN_KEY_CHECKS=1;\n");
    fclose($fh);
    @chmod($filePath, 0640);
    foreach (glob($dir . '/database-*.sql') ?: [] as $old) {
        if (is_file($old) && filemtime($old) < time() - (BACKUP_RETENTION_DAYS * 86400)) @unlink($old);
    }
    if (Database::tableExists('backups')) Database::safeExecute('INSERT INTO backups (file_path,backup_type,created_by,created_at) VALUES (?,"database",NULL,NOW())', [str_replace(ROOT_PATH . '/', '', $filePath)]);
    $status = 'success';
    $message = 'Backup created: ' . basename($filePath);
} catch (Throwable $e) {
    $message = $e->getMessage();
    if ($filePath && is_file($filePath)) @unlink($filePath);
} finally {
    if (Database::tableExists('cron_runs')) Database::safeExecute('INSERT INTO cron_runs (job_name,status,message,started_at,finished_at) VALUES (?,?,?,?,NOW())', [$job,$status,substr($message,0,65000),$started]);
}
echo '[' . date('c') . '] ' . $job . ': ' . $message . PHP_EOL;
if ($status !== 'success') exit(1);
