<?php

declare(strict_types=1);

require_once __DIR__ . '/../app/auth.php';
require_once __DIR__ . '/../app/layout.php';
require_once __DIR__ . '/../app/backup.php';

$user = sparrow_require_backyard_login();

if (($user['role'] ?? '') !== 'owner') {
    http_response_code(403);
    exit('Only the site owner can manage full backups and restores.');
}

$pdo = sparrow_db();
$csrf_token = sparrow_backup_csrf_token();
$notice = '';
$error = '';
$restore_filename = '';
$restore_manifest = null;

function sparrow_backup_post_file(): string
{
    return trim((string) ($_POST['backup_file'] ?? ''));
}

function sparrow_backup_upload_error(int $code): string
{
    return match ($code) {
        UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => 'The backup is larger than the server upload limit.',
        UPLOAD_ERR_PARTIAL => 'The backup upload did not finish.',
        UPLOAD_ERR_NO_FILE => 'Choose a Sparrow backup ZIP file first.',
        UPLOAD_ERR_NO_TMP_DIR => 'The server temporary upload folder is unavailable.',
        UPLOAD_ERR_CANT_WRITE => 'The server could not save the uploaded backup.',
        UPLOAD_ERR_EXTENSION => 'A server extension stopped the upload.',
        default => 'The backup upload failed.',
    };
}

function sparrow_backup_ini_bytes(string $value): int
{
    $value = trim($value);
    if ($value === '') {
        return 0;
    }

    $number = (float) $value;
    $unit = strtolower(substr($value, -1));

    return match ($unit) {
        'g' => (int) ($number * 1024 * 1024 * 1024),
        'm' => (int) ($number * 1024 * 1024),
        'k' => (int) ($number * 1024),
        default => (int) $number,
    };
}

if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['download'])) {
    if (!sparrow_backup_verify_csrf($_GET['token'] ?? null)) {
        http_response_code(403);
        exit('The download link is invalid or expired.');
    }

    $download_path = sparrow_backup_path((string) $_GET['download']);
    if ($download_path === null || !is_file($download_path)) {
        http_response_code(404);
        exit('Backup not found.');
    }

    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename="' . basename($download_path) . '"');
    header('Content-Length: ' . filesize($download_path));
    header('X-Content-Type-Options: nosniff');
    readfile($download_path);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!sparrow_backup_verify_csrf($_POST['csrf_token'] ?? null)) {
        $error = 'The form expired. Refresh the page and try again.';
    } else {
        $action = trim((string) ($_POST['action'] ?? ''));

        try {
            if ($action === 'create_backup') {
                $result = sparrow_backup_create($pdo, $user);
                $notice = 'Full backup created: ' . $result['filename']
                    . ' (' . sparrow_backup_format_bytes((int) $result['size']) . '). Download a copy and keep it somewhere outside the website.';
            } elseif ($action === 'upload_backup') {
                $upload = $_FILES['backup_upload'] ?? null;
                if (!is_array($upload)) {
                    throw new RuntimeException('Choose a Sparrow backup ZIP file first.');
                }

                $upload_error = (int) ($upload['error'] ?? UPLOAD_ERR_NO_FILE);
                if ($upload_error !== UPLOAD_ERR_OK) {
                    throw new RuntimeException(sparrow_backup_upload_error($upload_error));
                }

                $temporary_path = (string) ($upload['tmp_name'] ?? '');
                if ($temporary_path === '' || !is_uploaded_file($temporary_path)) {
                    throw new RuntimeException('The uploaded backup could not be verified as an HTTP upload.');
                }

                sparrow_backup_validate_archive($temporary_path);
                $filename = sparrow_backup_unique_filename('full');
                $destination = sparrow_backup_ensure_directory() . DIRECTORY_SEPARATOR . $filename;

                if (!move_uploaded_file($temporary_path, $destination)) {
                    throw new RuntimeException('The validated backup could not be placed in the backup folder.');
                }

                $notice = 'Backup uploaded and verified as ' . $filename . '.';
            } elseif ($action === 'verify_backup') {
                $filename = sparrow_backup_post_file();
                $path = sparrow_backup_path($filename);
                if ($path === null || !is_file($path)) {
                    throw new RuntimeException('The selected backup was not found.');
                }

                $manifest = sparrow_backup_validate_archive($path);
                $notice = 'Backup verified successfully. It contains '
                    . number_format((int) ($manifest['database']['tables'] ?? 0)) . ' database tables and '
                    . number_format((int) ($manifest['site']['files'] ?? 0)) . ' site files.';
            } elseif ($action === 'prepare_restore') {
                $restore_filename = sparrow_backup_post_file();
                $path = sparrow_backup_path($restore_filename);
                if ($path === null || !is_file($path)) {
                    throw new RuntimeException('The selected backup was not found.');
                }

                $restore_manifest = sparrow_backup_validate_archive($path);
            } elseif ($action === 'restore_backup') {
                $filename = sparrow_backup_post_file();
                $confirmation = strtoupper(trim((string) ($_POST['restore_confirmation'] ?? '')));
                if ($confirmation !== 'RESTORE') {
                    throw new RuntimeException('Type RESTORE in the confirmation box before continuing.');
                }

                $path = sparrow_backup_path($filename);
                if ($path === null || !is_file($path)) {
                    throw new RuntimeException('The selected backup was not found.');
                }

                $result = sparrow_backup_restore($pdo, $user, $path);
                $notice = 'Restore completed. '
                    . number_format((int) $result['restored_files']) . ' site files and the database were restored. '
                    . 'A safety backup of the previous state was created first: '
                    . $result['safety_backup']['filename'] . '.';
            } elseif ($action === 'delete_backup') {
                $filename = sparrow_backup_post_file();
                $confirmation = strtoupper(trim((string) ($_POST['delete_confirmation'] ?? '')));
                if ($confirmation !== 'DELETE') {
                    throw new RuntimeException('Type DELETE before removing a backup.');
                }

                $path = sparrow_backup_path($filename);
                if ($path === null || !is_file($path)) {
                    throw new RuntimeException('The selected backup was not found.');
                }

                if (!unlink($path)) {
                    throw new RuntimeException('The backup could not be deleted.');
                }

                $notice = 'Backup deleted: ' . $filename . '.';
            }
        } catch (Throwable $exception) {
            $error = $exception->getMessage();
        }
    }
}

$backups = sparrow_backup_list();
$zip_ready = class_exists('ZipArchive');
$mysql_ready = extension_loaded('pdo_mysql');
$upload_limit = min(
    array_filter([
        sparrow_backup_ini_bytes((string) ini_get('upload_max_filesize')),
        sparrow_backup_ini_bytes((string) ini_get('post_max_size')),
    ], static fn(int $value): bool => $value > 0) ?: [0]
);
$backup_directory = sparrow_backup_ensure_directory();
$free_space = disk_free_space($backup_directory);

sparrow_backyard_header('Backup & Restore');
?>

<style>
    .backup-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 18px;
        margin-bottom: 18px;
    }

    .backup-status-list {
        display: grid;
        gap: 8px;
        margin: 16px 0;
    }

    .backup-status-item {
        display: flex;
        justify-content: space-between;
        gap: 12px;
        padding: 10px 12px;
        border: 1px solid #ead8e3;
        border-radius: 10px;
        background: #fffafd;
    }

    .backup-ready {
        color: #247044;
        font-weight: 700;
    }

    .backup-not-ready {
        color: #a13b3b;
        font-weight: 700;
    }

    .backup-warning {
        border-left: 4px solid #bf7b28;
        background: #fff9ee;
        padding: 12px 14px;
        border-radius: 8px;
    }

    .backup-danger {
        border: 1px solid #d9a7a7;
        background: #fff7f7;
    }

    .backup-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        align-items: center;
    }

    .backup-actions form {
        margin: 0;
    }

    .backup-file-name {
        overflow-wrap: anywhere;
    }

    .backup-confirm-box {
        max-width: 560px;
        margin-bottom: 18px;
    }

    .backup-confirm-box input[type="text"] {
        max-width: 180px;
        text-transform: uppercase;
    }

    @media (max-width: 760px) {
        .backup-grid {
            grid-template-columns: 1fr;
        }
    }
</style>

<section class="card">
    <h1>Full Backup &amp; Restore</h1>

    <p class="muted">
        Create one protected ZIP package containing the current database, website files, uploaded approval images, gallery images, and documents. Download important backups to another device before hosting or making major changes.
    </p>

    <?php if ($notice !== ''): ?>
        <div class="notice notice-success"><?= sparrow_escape($notice) ?></div>
    <?php endif; ?>

    <?php if ($error !== ''): ?>
        <div class="notice notice-error"><?= sparrow_escape($error) ?></div>
    <?php endif; ?>

    <div class="backup-status-list">
        <div class="backup-status-item">
            <span>ZIP package support</span>
            <span class="<?= $zip_ready ? 'backup-ready' : 'backup-not-ready' ?>">
                <?= $zip_ready ? 'Ready' : 'Not enabled' ?>
            </span>
        </div>
        <div class="backup-status-item">
            <span>MySQL database support</span>
            <span class="<?= $mysql_ready ? 'backup-ready' : 'backup-not-ready' ?>">
                <?= $mysql_ready ? 'Ready' : 'Not enabled' ?>
            </span>
        </div>
        <div class="backup-status-item">
            <span>Free backup space</span>
            <strong><?= $free_space === false ? 'Could not check' : sparrow_escape(sparrow_backup_format_bytes((int) $free_space)) ?></strong>
        </div>
    </div>

    <form method="post">
        <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
        <input type="hidden" name="action" value="create_backup">
        <button type="submit" class="button" <?= (!$zip_ready || !$mysql_ready) ? 'disabled' : '' ?>>
            Create Full Backup
        </button>
    </form>
</section>

<?php if (is_array($restore_manifest) && $restore_filename !== ''): ?>
    <section class="card backup-danger backup-confirm-box">
        <h2>Confirm Full Restore</h2>
        <p>
            You are about to restore <strong class="backup-file-name"><?= sparrow_escape($restore_filename) ?></strong>, created
            <strong><?= sparrow_escape((string) ($restore_manifest['created_at'] ?? 'date unavailable')) ?></strong>.
        </p>
        <p>
            This will replace the current database and overwrite matching website files. A new safety backup of the current site will be created automatically before anything is restored.
        </p>
        <p><strong>Type RESTORE to continue:</strong></p>

        <form method="post">
            <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
            <input type="hidden" name="action" value="restore_backup">
            <input type="hidden" name="backup_file" value="<?= sparrow_escape($restore_filename) ?>">
            <p>
                <input type="text" name="restore_confirmation" autocomplete="off" required>
            </p>
            <div class="backup-actions">
                <button type="submit" class="button">Restore This Backup</button>
                <a class="button button-secondary" href="<?= sparrow_escape(sparrow_url('/backyard/backups.php')) ?>">Cancel</a>
            </div>
        </form>
    </section>
<?php endif; ?>

<div class="backup-grid">
    <section class="card">
        <h2>Bring In a Backup</h2>
        <p class="muted">
            Upload a backup created by this page. The package is fully checked before it is added to the restore list.
        </p>

        <form method="post" enctype="multipart/form-data">
            <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
            <input type="hidden" name="action" value="upload_backup">
            <p>
                <input type="file" name="backup_upload" accept=".zip,application/zip" required>
            </p>
            <button type="submit" class="button button-secondary">Upload &amp; Verify Backup</button>
        </form>

        <p class="muted" style="margin-top: 14px;">
            Browser upload limit: <?= $upload_limit > 0 ? sparrow_escape(sparrow_backup_format_bytes($upload_limit)) : 'server default' ?>.
            For a larger migration package, place it directly in <code>storage/backups</code> using your host file manager, then refresh this page.
        </p>
    </section>

    <section class="card">
        <h2>Safe Restore Rules</h2>
        <div class="backup-warning">
            <strong>A restore never starts immediately.</strong>
            The package must pass its integrity check, you must type RESTORE, and the site creates a pre-restore safety backup first.
        </div>
        <p class="muted" style="margin-top: 14px;">
            Matching files are restored and overwritten. Unrelated files added after the backup are left in place so the restore does not unexpectedly delete server files.
            The destination server's <code>app/config.php</code> database connection is preserved during migration.
        </p>
    </section>
</div>

<section class="card">
    <h2>Saved Backups</h2>

    <?php if (!$backups): ?>
        <p class="muted">No full backups have been created yet.</p>
    <?php else: ?>
        <div class="table-wrap">
            <table>
                <thead>
                    <tr>
                        <th>Backup</th>
                        <th>Type</th>
                        <th>Created</th>
                        <th>Size</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($backups as $backup): ?>
                        <tr>
                            <td class="backup-file-name"><strong><?= sparrow_escape($backup['filename']) ?></strong></td>
                            <td><?= sparrow_escape($backup['type']) ?></td>
                            <td><?= sparrow_escape(date('F j, Y g:i A', (int) $backup['created_at'])) ?></td>
                            <td><?= sparrow_escape(sparrow_backup_format_bytes((int) $backup['size'])) ?></td>
                            <td>
                                <div class="backup-actions">
                                    <a
                                        class="button button-small"
                                        href="<?= sparrow_escape(sparrow_url('/backyard/backups.php')) ?>?download=<?= rawurlencode($backup['filename']) ?>&amp;token=<?= rawurlencode($csrf_token) ?>"
                                    >Download</a>

                                    <form method="post">
                                        <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
                                        <input type="hidden" name="action" value="verify_backup">
                                        <input type="hidden" name="backup_file" value="<?= sparrow_escape($backup['filename']) ?>">
                                        <button type="submit" class="button button-small button-secondary">Verify</button>
                                    </form>

                                    <form method="post">
                                        <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
                                        <input type="hidden" name="action" value="prepare_restore">
                                        <input type="hidden" name="backup_file" value="<?= sparrow_escape($backup['filename']) ?>">
                                        <button type="submit" class="button button-small button-secondary">Restore</button>
                                    </form>

                                    <details>
                                        <summary class="button button-small button-secondary">Delete</summary>
                                        <form method="post" style="margin-top: 8px;">
                                            <input type="hidden" name="csrf_token" value="<?= sparrow_escape($csrf_token) ?>">
                                            <input type="hidden" name="action" value="delete_backup">
                                            <input type="hidden" name="backup_file" value="<?= sparrow_escape($backup['filename']) ?>">
                                            <input type="text" name="delete_confirmation" placeholder="Type DELETE" autocomplete="off" required>
                                            <button type="submit" class="button button-small">Delete Backup</button>
                                        </form>
                                    </details>
                                </div>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    <?php endif; ?>
</section>

<?php sparrow_backyard_footer(); ?>
