<?php
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/db.php';
require_login();
header('Content-Type: application/json');

$action = $_GET['action'] ?? $_POST['action'] ?? 'list';
$baseDir = realpath(__DIR__ . '/..');
$backupDir = $baseDir . DIRECTORY_SEPARATOR . 'backups';
if (!is_dir($backupDir)) {
    @mkdir($backupDir, 0775, true);
}

function ensure_admin_backup() { if (!has_role(['admin','super_admin'])) json_response(['message'=>'Forbidden'], 403); }

function list_backups($backupDir) {
    $out = [];
    if (is_dir($backupDir)) {
        $files = scandir($backupDir);
        foreach ($files as $f) {
            if ($f === '.' || $f === '..') continue;
            $full = $backupDir . DIRECTORY_SEPARATOR . $f;
            if (is_file($full)) {
                $out[] = [
                    'name' => $f,
                    'size' => filesize($full),
                    'mtime' => date('Y-m-d H:i:s', filemtime($full)),
                    'url' => url_for('backups/' . rawurlencode($f))
                ];
            }
        }
        // sort desc by mtime
        usort($out, function($a,$b){ return strcmp($b['mtime'],$a['mtime']); });
    }
    return $out;
}

switch ($action) {
    case 'list':
        json_response(['data' => list_backups($backupDir)]);
        break;

    case 'db_backup':
        ensure_admin_backup();
        if (!validate_csrf($_POST['csrf'] ?? '')) json_response(['message' => 'Invalid CSRF'], 400);
        // Build filename
        $fname = 'db_' . DB_NAME . '_' . date('Ymd_His') . '.sql';
        $fpath = $backupDir . DIRECTORY_SEPARATOR . $fname;

        // Try to locate mysqldump on Windows XAMPP or PATH
        $candidates = [
            'mysqldump',
            'C:\\xampp\\mysql\\bin\\mysqldump.exe',
            'C:\\Program Files\\MySQL\\MySQL Server 8.0\\bin\\mysqldump.exe',
        ];
        $mysqldump = null; $detectInfo = [];
        $isWin = (stripos(PHP_OS, 'WIN') === 0);
        foreach ($candidates as $cand) {
            if ($isWin) {
                if (stripos($cand, ':\\') !== false || strpos($cand, '\\') !== false) {
                    if (is_file($cand)) { $mysqldump = $cand; $detectInfo[] = 'found file: '.$cand; break; }
                } else {
                    // bare command name; use 'where' without quotes
                    $res = @shell_exec('where '.$cand.' 2> NUL');
                    if ($res) { $mysqldump = trim(explode("\n", str_replace("\r", '', $res))[0]); $detectInfo[]='where result: '.$mysqldump; break; }
                }
            } else {
                $res = @shell_exec('command -v ' . escapeshellarg($cand) . ' 2>/dev/null');
                if ($res) { $mysqldump = trim(explode("\n", $res)[0]); $detectInfo[]='command -v result: '.$mysqldump; break; }
                if (is_file($cand)) { $mysqldump = $cand; $detectInfo[] = 'found file: '.$cand; break; }
            }
        }
        if (!$mysqldump) {
            // fallback assume command available
            $mysqldump = 'mysqldump'; $detectInfo[]='fallback to mysqldump';
        }

        // Construct command with proper escaping (no shell redirection here)
        $host = DB_HOST; $user = DB_USER; $pass = DB_PASS; $db = DB_NAME;
        $cmd = '"' . $mysqldump . '" --single-transaction --quick --lock-tables=false --column-statistics=0 '
             . '-h ' . escapeshellarg($host) . ' -u ' . escapeshellarg($user) . ' '
             . escapeshellarg($db);

        $exitCode = null;
        if (function_exists('proc_open')) {
            $descriptorspec = [
                0 => ['pipe', 'r'],
                1 => ['file', $fpath, 'w'], // write mysqldump stdout directly to file
                2 => ['pipe', 'w']
            ];
            // Set MYSQL_PWD to avoid quoting issues with -p on Windows/cmd
            $env = $_ENV;
            if ($pass !== '') { $env['MYSQL_PWD'] = $pass; }
            $proc = proc_open($cmd, $descriptorspec, $pipes, $baseDir, $env);
            if (is_resource($proc)) {
                fclose($pipes[0]);
                $stderr = stream_get_contents($pipes[2]); fclose($pipes[2]);
                $exitCode = proc_close($proc);
                if ($exitCode !== 0 || !file_exists($fpath) || filesize($fpath) === 0) {
                    if (file_exists($fpath) && filesize($fpath) === 0) @unlink($fpath);
                    json_response(['message' => 'mysqldump failed', 'error' => trim($stderr), 'tool' => $mysqldump, 'detect' => $detectInfo], 500);
                }
            } else {
                json_response(['message' => 'Failed to start mysqldump process'], 500);
            }
        } else {
            // Fallback to shell_exec using shell redirection; include password as long option
            $cmdShell = '"' . $mysqldump . '" --single-transaction --quick --lock-tables=false --column-statistics=0 '
                      . '-h ' . escapeshellarg($host) . ' -u ' . escapeshellarg($user)
                      . ($pass !== '' ? ' --password=' . escapeshellarg($pass) : '') . ' '
                      . escapeshellarg($db) . ' > ' . escapeshellarg($fpath) . ' 2>&1';
            $out = @shell_exec($cmdShell);
            if (!file_exists($fpath) || filesize($fpath) === 0) {
                json_response(['message' => 'mysqldump failed', 'error' => trim((string)$out), 'tool' => $mysqldump, 'detect' => $detectInfo], 500);
            }
        }

        json_response(['message' => 'DB backup created', 'url' => url_for('backups/' . rawurlencode($fname))]);
        break;

    case 'system_backup':
        ensure_admin_backup();
        if (!validate_csrf($_POST['csrf'] ?? '')) json_response(['message' => 'Invalid CSRF'], 400);
        if (!class_exists('ZipArchive')) {
            json_response(['message' => 'ZipArchive not available in PHP'], 500);
        }
        $fname = 'system_' . date('Ymd_His') . '.zip';
        $fpath = $backupDir . DIRECTORY_SEPARATOR . $fname;
        $zip = new ZipArchive();
        if ($zip->open($fpath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            json_response(['message' => 'Failed to create ZIP archive'], 500);
        }
        $root = $baseDir; // application root
        $exclude = [realpath($backupDir)];
        $it = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );
        foreach ($it as $file) {
            $full = $file->getPathname();
            // Exclude backups directory
            foreach ($exclude as $ex) {
                if ($ex && strpos(realpath($full), $ex) === 0) { continue 2; }
            }
            $localName = ltrim(str_replace($root, '', $full), DIRECTORY_SEPARATOR);
            if ($file->isDir()) {
                $zip->addEmptyDir($localName);
            } else {
                $zip->addFile($full, $localName);
            }
        }
        $zip->close();
        json_response(['message' => 'System backup created', 'url' => url_for('backups/' . rawurlencode($fname))]);
        break;

    default:
        json_response(['message' => 'Invalid action'], 400);
}
