<?php
/**
 * Admin backup and restore UI.
 *
 * @package Maca_Menu_List
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Backup admin screen.
 */
class Maca_MenuList_Admin_Backup {

    /**
     * @var self|null
     */
    private static $instance = null;

    /**
     * @return self
     */
    public static function instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * Constructor.
     */
    private function __construct() {
        add_action('admin_menu', array($this, 'add_admin_menu'), 20);
        add_action('admin_init', array($this, 'handle_form_submission'));
        add_action('admin_post_maca_menulist_download_backup', array($this, 'download_backup_file'));
        add_action('admin_post_maca_menulist_export_download', array($this, 'export_and_download'));
        add_action('wp_ajax_maca_menulist_create_export_backup', array($this, 'ajax_create_export_backup'));
        add_action('wp_ajax_maca_menulist_download_backup', array($this, 'ajax_download_backup'));
        add_action('wp_ajax_maca_menulist_import_backup', array($this, 'ajax_import_backup'));
        add_action('wp_ajax_maca_menulist_import_backup_continue', array($this, 'ajax_import_backup_continue'));
        add_action('wp_ajax_maca_menulist_import_backup_progress', array($this, 'ajax_import_backup_progress'));
    }

    /**
     * Register submenu page.
     */
    public function add_admin_menu() {
        add_submenu_page(
            'maca-restu',
            __('Säkerhetskopiering och återställning', 'maca-restu-pro'),
            __('Säkerhetskopiering', 'maca-restu-pro'),
            maca_menulist_admin_required_cap(),
            'maca-restu-backup',
            'maca_menulist_admin_render_backup_page'
        );
    }

    /**
     * Handle backup settings, export, and import.
     */
    public function handle_form_submission() {
        if (!isset($_POST['maca_type']) || sanitize_text_field(wp_unslash($_POST['maca_type'])) !== 'backup') {
            return;
        }

        if (!isset($_POST['maca_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['maca_nonce'])), 'maca_save')) {
            return;
        }

        if (!maca_menulist_user_can_manage_secrets()) {
            return;
        }

        $action = isset($_POST['maca_action']) ? sanitize_text_field(wp_unslash($_POST['maca_action'])) : '';

        if ($action === 'save_backup_settings') {
            $this->save_backup_settings();
            return;
        }

        if ($action === 'export_backup') {
            maca_menulist_backup_raise_limits();
            $result = maca_menulist_backup_create_file('manual');
            if ($result['success'] && !empty($result['filename'])) {
                wp_safe_redirect(
                    wp_nonce_url(
                        admin_url('admin-post.php?action=maca_menulist_download_backup&file=' . rawurlencode($result['filename'])),
                        'maca_download_backup_' . $result['filename']
                    )
                );
                exit;
            }

            add_settings_error(
                'maca_backup',
                'export_failed',
                isset($result['message']) ? $result['message'] : __('Säkerhetskopiering misslyckades.', 'maca-restu-pro'),
                'error'
            );
            return;
        }

        if ($action === 'import_backup') {
            $this->import_backup_upload();
            return;
        }

        if ($action === 'delete_backup') {
            $this->delete_backup_file();
        }
    }

    /**
     * Save backup cron settings.
     */
    private function save_backup_settings() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing
        $daily_enabled = isset($_POST['maca_backup_daily_enabled']) ? '1' : '0';
        $retention_days = isset($_POST['maca_backup_retention_days']) ? intval($_POST['maca_backup_retention_days']) : 7;
        $daily_time = isset($_POST['maca_backup_daily_time']) ? sanitize_text_field(wp_unslash($_POST['maca_backup_daily_time'])) : '03:00';
        // phpcs:enable WordPress.Security.NonceVerification.Missing

        if ($retention_days < 1) {
            $retention_days = 7;
        }

        if (!preg_match('/^\d{2}:\d{2}$/', $daily_time)) {
            $daily_time = '03:00';
        }

        update_option('maca_menulist_backup_daily_enabled', $daily_enabled);
        update_option('maca_menulist_backup_retention_days', $retention_days);
        update_option('maca_menulist_backup_daily_time', $daily_time);

        maca_menulist_backup_schedule_cron();

        add_settings_error(
            'maca_backup',
            'settings_saved',
            __('Inställningar för säkerhetskopiering sparade.', 'maca-restu-pro'),
            'updated'
        );
    }

    /**
     * Import uploaded backup file.
     */
    private function import_backup_upload() {
        if (empty($_FILES['maca_backup_file']['tmp_name'])) {
            add_settings_error(
                'maca_backup',
                'import_missing',
                __('Välj en säkerhetskopieringsfil att importera.', 'maca-restu-pro'),
                'error'
            );
            return;
        }

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $file = $_FILES['maca_backup_file'];
        $name = isset($file['name']) ? sanitize_file_name($file['name']) : '';
        $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION));

        if (!in_array($extension, array('json', 'zip'), true)) {
            add_settings_error(
                'maca_backup',
                'import_type',
                __('Ladda upp en .json- eller .zip-säkerhetskopieringsfil.', 'maca-restu-pro'),
                'error'
            );
            return;
        }

        if (!empty($file['error'])) {
            add_settings_error(
                'maca_backup',
                'import_upload',
                __('Uppladdningen misslyckades.', 'maca-restu-pro'),
                'error'
            );
            return;
        }

        $result = maca_menulist_backup_restore_from_file($file['tmp_name'], $name);
        add_settings_error(
            'maca_backup',
            $result['success'] ? 'import_success' : 'import_failed',
            $result['message'],
            $result['success'] ? 'updated' : 'error'
        );
    }

    /**
     * Delete a stored backup file from disk.
     */
    private function delete_backup_file() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing
        $filename = isset($_POST['maca_backup_filename']) ? sanitize_file_name(wp_unslash($_POST['maca_backup_filename'])) : '';
        // phpcs:enable WordPress.Security.NonceVerification.Missing

        $result = maca_menulist_backup_delete_file($filename);

        add_settings_error(
            'maca_backup',
            $result['success'] ? 'delete_success' : 'delete_failed',
            $result['message'],
            $result['success'] ? 'updated' : 'error'
        );
    }

    /**
     * AJAX: create backup file and return download URL.
     */
    public function ajax_create_export_backup() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_send_json_error(
                array('message' => __('Du har inte behörighet att ladda ner säkerhetskopior.', 'maca-restu-pro')),
                403
            );
        }

        check_ajax_referer('maca_export_download', 'nonce');

        maca_menulist_backup_raise_limits();

        $result = maca_menulist_backup_create_file('manual');
        if (!$result['success'] || empty($result['filename'])) {
            wp_send_json_error(
                array(
                    'message' => isset($result['message'])
                        ? $result['message']
                        : __('Säkerhetskopiering misslyckades. Kontrollera att uploads-mappen är skrivbar och att servern har tillräckligt med minne och tid.', 'maca-restu-pro'),
                )
            );
        }

        wp_send_json_success(
            array(
                'filename' => $result['filename'],
            )
        );
    }

    /**
     * AJAX: stream an existing backup file (POST filename — avoids blocked ?file= URLs).
     */
    public function ajax_download_backup() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_die(esc_html__('Du har inte behörighet att ladda ner säkerhetskopior.', 'maca-restu-pro'), '', array('response' => 403));
        }

        check_ajax_referer('maca_export_download', 'nonce');

        $filename = maca_menulist_backup_normalize_filename(
            isset($_POST['filename']) ? wp_unslash($_POST['filename']) : ''
        );

        if ($filename === '') {
            wp_die(esc_html__('Ogiltig säkerhetskopieringsfil.', 'maca-restu-pro'), '', array('response' => 400));
        }

        $this->stream_backup_file($filename);
    }

    /**
     * AJAX: poll import progress (%).
     */
    public function ajax_import_backup_progress() {
        if (!maca_menulist_user_can_manage_secrets()) {
            wp_send_json_error(array('message' => __('Forbidden', 'maca-restu-pro')), 403);
        }

        check_ajax_referer('maca_backup_import', 'nonce');

        $job_id = isset($_GET['job_id']) ? sanitize_key(wp_unslash($_GET['job_id'])) : '';
        $progress = maca_menulist_backup_get_import_progress($job_id);

        if (!$progress) {
            wp_send_json_success(
                array(
                    'percent' => 0,
                    'stage'   => '',
                )
            );
        }

        wp_send_json_success($progress);
    }

    /**
     * AJAX: import uploaded backup with progress updates.
     */
    public function ajax_import_backup() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_send_json_error(array('message' => __('Du har inte behörighet att importera säkerhetskopior.', 'maca-restu-pro')), 403);
        }

        check_ajax_referer('maca_backup_import', 'nonce');

        $job_id = isset($_POST['job_id']) ? sanitize_key(wp_unslash($_POST['job_id'])) : '';
        if ($job_id === '') {
            wp_send_json_error(array('message' => __('Ogiltigt importjobb.', 'maca-restu-pro')));
        }

        if (empty($_FILES['maca_backup_file']['tmp_name'])) {
            wp_send_json_error(array('message' => __('Välj en säkerhetskopieringsfil att importera.', 'maca-restu-pro')));
        }

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $file = $_FILES['maca_backup_file'];
        $name = isset($file['name']) ? sanitize_file_name($file['name']) : '';
        $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION));

        if (!in_array($extension, array('json', 'zip'), true)) {
            wp_send_json_error(array('message' => __('Ladda upp en .json- eller .zip-säkerhetskopieringsfil.', 'maca-restu-pro')));
        }

        if (!empty($file['error'])) {
            wp_send_json_error(array('message' => __('Uppladdningen misslyckades.', 'maca-restu-pro')));
        }

        maca_menulist_backup_raise_limits();

        if (function_exists('session_status') && session_status() === PHP_SESSION_ACTIVE) {
            // phpcs:ignore WordPress.PHP.NoSilencedFunctions.Discouraged
            @session_write_close();
        }

        if (!maca_menulist_backup_import_init_job($job_id, $file['tmp_name'], $name)) {
            wp_send_json_error(array('message' => __('Kunde inte förbereda importen.', 'maca-restu-pro')));
        }

        maca_menulist_backup_set_import_progress(
            $job_id,
            (int) MACA_MENULIST_BACKUP_IMPORT_UPLOAD_PERCENT,
            __('Fil uppladdad, startar import…', 'maca-restu-pro')
        );

        wp_send_json_success(
            array(
                'job_id'  => $job_id,
                'percent' => (int) MACA_MENULIST_BACKUP_IMPORT_UPLOAD_PERCENT,
                'stage'   => __('Fil uppladdad, startar import…', 'maca-restu-pro'),
            )
        );
    }

    /**
     * AJAX: run the next short import step (keeps progress bar moving).
     */
    public function ajax_import_backup_continue() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_send_json_error(array('message' => __('Du har inte behörighet att importera säkerhetskopior.', 'maca-restu-pro')), 403);
        }

        check_ajax_referer('maca_backup_import', 'nonce');

        $job_id = isset($_POST['job_id']) ? sanitize_key(wp_unslash($_POST['job_id'])) : '';
        if ($job_id === '') {
            wp_send_json_error(array('message' => __('Ogiltigt importjobb.', 'maca-restu-pro')));
        }

        if (function_exists('session_status') && session_status() === PHP_SESSION_ACTIVE) {
            // phpcs:ignore WordPress.PHP.NoSilencedFunctions.Discouraged
            @session_write_close();
        }

        $result = maca_menulist_backup_import_run_step($job_id);

        if ($result['done'] && $result['success']) {
            wp_send_json_success(
                array(
                    'done'    => true,
                    'percent' => $result['percent'],
                    'stage'   => $result['stage'],
                    'message' => $result['message'],
                )
            );
        }

        if ($result['done'] && !$result['success']) {
            maca_menulist_backup_clear_import_progress($job_id);
            wp_send_json_error(array('message' => $result['message']));
        }

        wp_send_json_success(
            array(
                'done'    => false,
                'percent' => $result['percent'],
                'stage'   => $result['stage'],
            )
        );
    }

    /**
     * Create a backup and send it to the browser immediately.
     */
    public function export_and_download() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_die(esc_html__('Du har inte behörighet att ladda ner säkerhetskopior.', 'maca-restu-pro'));
        }

        check_admin_referer('maca_export_download');
        maca_menulist_backup_raise_limits();

        register_shutdown_function(
            static function () {
                if (!function_exists('maca_menulist_debug_log')) {
                    return;
                }

                $error = error_get_last();
                if (
                    is_array($error)
                    && isset($error['type'], $error['message'])
                    && in_array((int) $error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR), true)
                ) {
                    maca_menulist_debug_log(
                        'backup_export_fatal: ' . $error['message']
                        . (isset($error['file'], $error['line']) ? ' in ' . $error['file'] . ':' . $error['line'] : '')
                    );
                }
            }
        );

        $result = maca_menulist_backup_create_file('manual');
        if (!$result['success'] || empty($result['filename'])) {
            wp_die(
                esc_html(isset($result['message']) ? $result['message'] : __('Säkerhetskopiering misslyckades.', 'maca-restu-pro'))
            );
        }

        $this->stream_backup_file($result['filename']);
    }

    /**
     * Stream a backup file to the browser.
     *
     * @param string $filename Backup filename.
     */
    private function stream_backup_file($filename) {
        maca_menulist_backup_discard_buffered_output();

        $path = trailingslashit(maca_menulist_backup_get_directory()) . $filename;
        if (!is_readable($path)) {
            wp_die(esc_html__('Säkerhetskopieringsfilen hittades inte.', 'maca-restu-pro'));
        }

        $mime = (substr($filename, -4) === '.zip') ? 'application/zip' : 'application/json';

        maca_menulist_backup_discard_buffered_output();

        nocache_headers();
        status_header(200);
        header('Content-Type: ' . $mime);
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($path));

        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
        readfile($path);
        exit;
    }

    /**
     * Download a stored backup file.
     */
    public function download_backup_file() {
        maca_menulist_backup_discard_buffered_output();

        if (!maca_menulist_user_can_manage_secrets()) {
            wp_die(esc_html__('Du har inte behörighet att ladda ner säkerhetskopior.', 'maca-restu-pro'));
        }

        $filename = maca_menulist_backup_normalize_filename(
            isset($_POST['file'])
                ? wp_unslash($_POST['file'])
                : (isset($_GET['file']) ? wp_unslash($_GET['file']) : '')
        );

        if ($filename === '') {
            wp_die(esc_html__('Ogiltig säkerhetskopieringsfil.', 'maca-restu-pro'));
        }

        $nonce_action = 'maca_download_backup_' . $filename;
        if (isset($_POST['maca_backup_download_nonce'])) {
            check_admin_referer($nonce_action, 'maca_backup_download_nonce');
        } else {
            check_admin_referer($nonce_action);
        }

        $this->stream_backup_file($filename);
    }

    /**
     * Render backup admin page.
     */
    public function render_backup_page() {
        if (!maca_menulist_user_can_manage_secrets()) {
            wp_die(esc_html__('Du har inte behörighet att öppna den här sidan.', 'maca-restu-pro'));
        }

        $daily_enabled = get_option('maca_menulist_backup_daily_enabled', '0') === '1';
        $retention_days = (int) get_option('maca_menulist_backup_retention_days', 7);
        $daily_time = get_option('maca_menulist_backup_daily_time', '03:00');
        $last_run = (int) get_option('maca_menulist_backup_last_run', 0);
        $last_file = get_option('maca_menulist_backup_last_file', '');
        $files = maca_menulist_backup_list_files();
        $next_cron = defined('MACA_MENULIST_BACKUP_CRON_HOOK')
            ? wp_next_scheduled(MACA_MENULIST_BACKUP_CRON_HOOK)
            : false;
        // Do not run DB migrations on page view — that can timeout and leave a blank admin content area.
        $discovered_tables = maca_menulist_backup_discover_tables(false);
        $skipped_table_keys = function_exists('maca_menulist_backup_get_skipped_table_keys')
            ? maca_menulist_backup_get_skipped_table_keys()
            : array();

        ?>
        <div class="wrap">
            <h1><?php esc_html_e('Säkerhetskopiering och återställning', 'maca-restu-pro'); ?></h1>
            <p><?php esc_html_e('Exporterar pluginets databastabeller (maca_*), inställningar (maca_menulist_*) och refererade mediafiler (meny-PDF/bilder, rättbilder, QR-logotyp) i en ZIP-fil.', 'maca-restu-pro'); ?></p>

            <?php settings_errors('maca_backup'); ?>

            <p class="description">
                <?php
                printf(
                    /* translators: %d: number of database tables */
                    esc_html__('Säkerhetskopierar för närvarande %d plugintabeller.', 'maca-restu-pro'),
                    count($discovered_tables)
                );
                ?>
                <?php if (!empty($discovered_tables)) : ?>
                    <code><?php echo esc_html(implode(', ', array_keys($discovered_tables))); ?></code>
                <?php endif; ?>
            </p>
            <?php if (!empty($skipped_table_keys)) : ?>
                <p class="description">
                    <?php
                    esc_html_e(
                        'Klickstatistik och bokningslogg hoppas över vid export för snabbare säkerhetskopior (befintlig data på sajten lämnas oförändrad vid återställning).',
                        'maca-restu-pro'
                    );
                    ?>
                    <code><?php echo esc_html(implode(', ', $skipped_table_keys)); ?></code>
                </p>
            <?php endif; ?>

            <h2><?php esc_html_e('Automatisk daglig säkerhetskopiering', 'maca-restu-pro'); ?></h2>
            <form method="post" action="">
                <?php wp_nonce_field('maca_save', 'maca_nonce'); ?>
                <input type="hidden" name="maca_action" value="save_backup_settings">
                <input type="hidden" name="maca_type" value="backup">
                <table class="form-table">
                    <tr>
                        <th scope="row"><?php esc_html_e('Daglig säkerhetskopiering', 'maca-restu-pro'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="maca_backup_daily_enabled" value="1" <?php checked($daily_enabled); ?>>
                                <?php esc_html_e('Kör säkerhetskopiering en gång per dag (sparas i uploads/maca-menulist-backups/)', 'maca-restu-pro'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><label for="maca_backup_daily_time"><?php esc_html_e('Tid', 'maca-restu-pro'); ?></label></th>
                        <td>
                            <input type="time" id="maca_backup_daily_time" name="maca_backup_daily_time" value="<?php echo esc_attr($daily_time); ?>">
                            <p class="description"><?php esc_html_e('Sajtens tidszon.', 'maca-restu-pro'); ?></p>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><label for="maca_backup_retention_days"><?php esc_html_e('Behåll säkerhetskopior', 'maca-restu-pro'); ?></label></th>
                        <td>
                            <input type="number" id="maca_backup_retention_days" name="maca_backup_retention_days" min="1" max="90" value="<?php echo esc_attr($retention_days); ?>" class="small-text">
                            <?php esc_html_e('dagar', 'maca-restu-pro'); ?>
                        </td>
                    </tr>
                </table>
                <?php submit_button(__('Spara inställningar', 'maca-restu-pro')); ?>
            </form>

            <?php if ($next_cron) : ?>
                <p class="description">
                    <?php
                    printf(
                        /* translators: %s: formatted date/time */
                        esc_html__('Nästa schemalagda säkerhetskopiering: %s', 'maca-restu-pro'),
                        esc_html(wp_date(get_option('date_format') . ' ' . get_option('time_format'), $next_cron))
                    );
                    ?>
                </p>
            <?php endif; ?>

            <?php if ($last_run > 0) : ?>
                <p class="description">
                    <?php
                    printf(
                        /* translators: 1: date/time, 2: filename */
                        esc_html__('Senaste säkerhetskopiering: %1$s (%2$s)', 'maca-restu-pro'),
                        esc_html(wp_date(get_option('date_format') . ' ' . get_option('time_format'), $last_run)),
                        esc_html($last_file)
                    );
                    ?>
                </p>
            <?php endif; ?>

            <h2><?php esc_html_e('Ladda ner säkerhetskopia', 'maca-restu-pro'); ?></h2>
            <p class="description"><?php esc_html_e('Spara en komplett ZIP på din dator eller i molnet. Den innehåller data.json plus en media/-mapp med alla pluginmedia. Första säkerhetskopieringen kan ta upp till en minut — vänta tills nedladdningen startar.', 'maca-restu-pro'); ?></p>
            <p>
                <button
                    type="button"
                    class="button button-primary"
                    id="maca-backup-export-download"
                    data-ajax-url="<?php echo esc_url(admin_url('admin-ajax.php')); ?>"
                    data-nonce="<?php echo esc_attr(wp_create_nonce('maca_export_download')); ?>"
                    data-creating="<?php echo esc_attr(__('Skapar säkerhetskopia…', 'maca-restu-pro')); ?>"
                    data-downloading="<?php echo esc_attr(__('Startar nedladdning…', 'maca-restu-pro')); ?>"
                    data-done="<?php echo esc_attr(__('Säkerhetskopia nedladdad.', 'maca-restu-pro')); ?>"
                    data-error="<?php echo esc_attr(__('Säkerhetskopiering misslyckades. Kontrollera att uploads-mappen är skrivbar och att servern har tillräckligt med minne och tid.', 'maca-restu-pro')); ?>"
                >
                    <?php esc_html_e('Skapa och ladda ner säkerhetskopia', 'maca-restu-pro'); ?>
                </button>
                <span class="maca-backup-export-status description" id="maca-backup-export-status" style="display:none;margin-left:8px;"></span>
            </p>
            <script>
            (function () {
                var button = document.getElementById('maca-backup-export-download');
                var status = document.getElementById('maca-backup-export-status');
                if (!button || !status) {
                    return;
                }

                var creatingText = button.getAttribute('data-creating') || '';
                var downloadingText = button.getAttribute('data-downloading') || '';
                var doneText = button.getAttribute('data-done') || '';
                var defaultError = button.getAttribute('data-error') || '';

                function resetExportUi() {
                    button.disabled = false;
                    button.removeAttribute('aria-busy');
                    status.style.display = 'none';
                    status.textContent = '';
                    status.style.color = '';
                }

                function setStatus(message, color) {
                    status.textContent = message;
                    status.style.display = 'inline';
                    status.style.color = color || '';
                }

                function showError(message) {
                    setStatus(message || defaultError, '#b32d2e');
                    button.disabled = false;
                    button.removeAttribute('aria-busy');
                }

                function parseJsonResponse(response) {
                    return response.text().then(function (text) {
                        var data = null;
                        try {
                            data = JSON.parse(text);
                        } catch (error) {
                            throw new Error(defaultError);
                        }

                        if (!response.ok || !data || !data.success) {
                            var message = data && data.data && data.data.message ? data.data.message : defaultError;
                            throw new Error(message);
                        }

                        return data;
                    });
                }

                function downloadBackupFile(filename) {
                    var formData = new FormData();
                    formData.append('action', 'maca_menulist_download_backup');
                    formData.append('nonce', button.getAttribute('data-nonce') || '');
                    formData.append('filename', filename);

                    return fetch(button.getAttribute('data-ajax-url') || '', {
                        method: 'POST',
                        credentials: 'same-origin',
                        body: formData
                    }).then(function (response) {
                        if (!response.ok) {
                            throw new Error(defaultError);
                        }

                        var disposition = response.headers.get('Content-Disposition') || '';
                        var match = /filename=\"([^\"]+)\"/i.exec(disposition);
                        if (match && match[1]) {
                            filename = match[1];
                        }

                        return response.blob().then(function (blob) {
                            var objectUrl = URL.createObjectURL(blob);
                            var anchor = document.createElement('a');
                            anchor.href = objectUrl;
                            anchor.download = filename || 'maca-restu-backup.zip';
                            anchor.style.display = 'none';
                            document.body.appendChild(anchor);
                            anchor.click();
                            setTimeout(function () {
                                URL.revokeObjectURL(objectUrl);
                                anchor.remove();
                            }, 1000);
                        });
                    });
                }

                window.addEventListener('pageshow', function (event) {
                    if (event.persisted) {
                        resetExportUi();
                    }
                });

                button.addEventListener('click', function () {
                    if (button.disabled) {
                        return;
                    }

                    button.disabled = true;
                    button.setAttribute('aria-busy', 'true');
                    setStatus(creatingText, '');

                    var formData = new FormData();
                    formData.append('action', 'maca_menulist_create_export_backup');
                    formData.append('nonce', button.getAttribute('data-nonce') || '');

                    fetch(button.getAttribute('data-ajax-url') || '', {
                        method: 'POST',
                        credentials: 'same-origin',
                        body: formData
                    })
                        .then(parseJsonResponse)
                        .then(function (data) {
                            var filename = data.data && data.data.filename ? data.data.filename : '';

                            if (!filename) {
                                throw new Error(defaultError);
                            }

                            setStatus(downloadingText, '');

                            return downloadBackupFile(filename).then(function () {
                                setStatus(doneText, '#00a32a');
                                button.disabled = false;
                                button.removeAttribute('aria-busy');
                                setTimeout(resetExportUi, 5000);
                            });
                        })
                        .catch(function (error) {
                            showError(error && error.message ? error.message : defaultError);
                        });
                });
            })();
            </script>

            <hr>

            <h2><?php esc_html_e('Importera säkerhetskopia', 'maca-restu-pro'); ?></h2>
            <p class="description"><?php esc_html_e('Ladda upp en .zip-säkerhetskopia för att återställa databas, inställningar och mediafiler. Äldre .json-säkerhetskopior återställer bara data (ingen media).', 'maca-restu-pro'); ?></p>
            <form id="maca-backup-import-form" enctype="multipart/form-data">
                <p>
                    <input type="file" id="maca-backup-import-file" name="maca_backup_file" accept=".json,.zip,application/json,application/zip" required>
                </p>
                <p>
                    <button
                        type="submit"
                        class="button button-primary"
                        id="maca-backup-import-submit"
                        data-ajax-url="<?php echo esc_url(admin_url('admin-ajax.php')); ?>"
                        data-nonce="<?php echo esc_attr(wp_create_nonce('maca_backup_import')); ?>"
                        data-uploading="<?php echo esc_attr(__('Laddar upp fil…', 'maca-restu-pro')); ?>"
                        data-importing="<?php echo esc_attr(__('Importerar…', 'maca-restu-pro')); ?>"
                        data-done="<?php echo esc_attr(__('Import klar.', 'maca-restu-pro')); ?>"
                        data-error="<?php echo esc_attr(__('Importen misslyckades.', 'maca-restu-pro')); ?>"
                        data-slow-hint="<?php echo esc_attr(__('Detta kan ta flera minuter — vänta utan att ladda om sidan.', 'maca-restu-pro')); ?>"
                    >
                        <?php esc_html_e('Importera säkerhetskopia', 'maca-restu-pro'); ?>
                    </button>
                </p>
                <div id="maca-backup-import-progress" class="maca-backup-import-progress" hidden>
                    <div class="maca-backup-import-progress__track" aria-hidden="true">
                        <div class="maca-backup-import-progress__bar" id="maca-backup-import-bar" style="width:0%;"></div>
                    </div>
                    <p class="maca-backup-import-progress__meta">
                        <strong id="maca-backup-import-percent">0%</strong>
                        <span id="maca-backup-import-stage"></span>
                    </p>
                </div>
                <p class="description" id="maca-backup-import-status" style="display:none;" aria-live="polite"></p>
            </form>
            <style>
                .maca-backup-import-progress { max-width: 520px; margin: 12px 0 0; }
                .maca-backup-import-progress__track {
                    height: 10px;
                    border-radius: 999px;
                    background: #dcdcde;
                    overflow: hidden;
                }
                .maca-backup-import-progress__bar {
                    height: 100%;
                    width: 0;
                    background: linear-gradient(90deg, #2271b1, #135e96);
                    transition: width 0.25s ease;
                }
                .maca-backup-import-progress__meta {
                    display: flex;
                    flex-wrap: wrap;
                    gap: 8px 12px;
                    margin: 8px 0 0;
                    color: #50575e;
                    font-size: 13px;
                }
            </style>
            <script>
            (function () {
                var form = document.getElementById('maca-backup-import-form');
                var fileInput = document.getElementById('maca-backup-import-file');
                var submitBtn = document.getElementById('maca-backup-import-submit');
                var progressWrap = document.getElementById('maca-backup-import-progress');
                var progressBar = document.getElementById('maca-backup-import-bar');
                var progressPercent = document.getElementById('maca-backup-import-percent');
                var progressStage = document.getElementById('maca-backup-import-stage');
                var statusEl = document.getElementById('maca-backup-import-status');

                if (!form || !fileInput || !submitBtn) {
                    return;
                }

                var importProgressFloor = 0;
                var uploadFinished = false;

                function setProgress(percent, stage, allowDecrease) {
                    var safe = Math.max(0, Math.min(100, parseInt(percent, 10) || 0));
                    if (!allowDecrease && safe < importProgressFloor) {
                        safe = importProgressFloor;
                    } else if (safe > importProgressFloor) {
                        importProgressFloor = safe;
                    }
                    if (progressWrap) {
                        progressWrap.hidden = false;
                    }
                    if (progressBar) {
                        progressBar.style.width = safe + '%';
                    }
                    if (progressPercent) {
                        progressPercent.textContent = safe + '%';
                    }
                    if (progressStage) {
                        progressStage.textContent = stage || '';
                    }
                }

                function setStatus(message, color) {
                    if (!statusEl) {
                        return;
                    }
                    statusEl.style.display = message ? 'block' : 'none';
                    statusEl.textContent = message || '';
                    statusEl.style.color = color || '';
                }

                var pollTimer = null;

                function stopPolling() {
                    if (pollTimer) {
                        window.clearInterval(pollTimer);
                        pollTimer = null;
                    }
                }

                function startPolling(jobId) {
                    stopPolling();
                    var ajaxUrl = submitBtn.getAttribute('data-ajax-url') || '';
                    var nonce = submitBtn.getAttribute('data-nonce') || '';

                    pollTimer = window.setInterval(function () {
                        var url = ajaxUrl
                            + '?action=maca_menulist_import_backup_progress'
                            + '&nonce=' + encodeURIComponent(nonce)
                            + '&job_id=' + encodeURIComponent(jobId);

                        fetch(url, { credentials: 'same-origin' })
                            .then(function (response) { return response.json(); })
                            .then(function (json) {
                                if (!json || !json.success || !json.data) {
                                    return;
                                }
                                setProgress(json.data.percent, json.data.stage);
                            })
                            .catch(function () {});
                    }, 500);
                }

                function runImportStep(jobId) {
                    var ajaxUrl = submitBtn.getAttribute('data-ajax-url') || '';
                    var nonce = submitBtn.getAttribute('data-nonce') || '';
                    var formData = new FormData();

                    formData.append('action', 'maca_menulist_import_backup_continue');
                    formData.append('nonce', nonce);
                    formData.append('job_id', jobId);

                    return fetch(ajaxUrl, {
                        method: 'POST',
                        body: formData,
                        credentials: 'same-origin'
                    })
                        .then(function (response) {
                            return response.text().then(function (text) {
                                var json;
                                try {
                                    json = JSON.parse(text);
                                } catch (error) {
                                    throw new Error(submitBtn.getAttribute('data-error') || 'Import failed');
                                }

                                if (!response.ok || !json.success) {
                                    throw new Error(
                                        (json.data && json.data.message)
                                            ? json.data.message
                                            : (submitBtn.getAttribute('data-error') || 'Import failed')
                                    );
                                }

                                return json;
                            });
                        })
                        .then(function (json) {
                            var data = json.data || {};
                            setProgress(data.percent, data.stage);

                            if (data.done) {
                                stopPolling();
                                setProgress(100, submitBtn.getAttribute('data-done') || '');
                                setStatus(data.message || (submitBtn.getAttribute('data-done') || ''), '#00a32a');
                                submitBtn.disabled = false;
                                fileInput.disabled = false;
                                window.setTimeout(function () {
                                    window.location.reload();
                                }, 1200);
                                return;
                            }

                            return new Promise(function (resolve) {
                                window.setTimeout(function () {
                                    resolve(runImportStep(jobId));
                                }, 80);
                            });
                        });
                }

                form.addEventListener('submit', function (event) {
                    event.preventDefault();

                    if (!fileInput.files || !fileInput.files[0]) {
                        setStatus(submitBtn.getAttribute('data-error') || '', '#b32d2e');
                        return;
                    }

                    var jobId = 'import_' + Date.now().toString(36);
                    var formData = new FormData();
                    formData.append('action', 'maca_menulist_import_backup');
                    formData.append('nonce', submitBtn.getAttribute('data-nonce') || '');
                    formData.append('job_id', jobId);
                    formData.append('maca_backup_file', fileInput.files[0]);

                    submitBtn.disabled = true;
                    fileInput.disabled = true;
                    setStatus('', '');
                    importProgressFloor = 0;
                    uploadFinished = false;
                    setProgress(0, submitBtn.getAttribute('data-uploading') || '', true);

                    var xhr = new XMLHttpRequest();
                    xhr.open('POST', submitBtn.getAttribute('data-ajax-url') || '', true);
                    xhr.withCredentials = true;

                    xhr.upload.addEventListener('progress', function (uploadEvent) {
                        if (uploadFinished || !uploadEvent.lengthComputable) {
                            return;
                        }
                        var uploadPercent = Math.min(24, Math.round((uploadEvent.loaded / uploadEvent.total) * 24));
                        setProgress(uploadPercent, submitBtn.getAttribute('data-uploading') || '', true);
                    });

                    xhr.addEventListener('load', function () {
                        try {
                            var json = JSON.parse(xhr.responseText);
                            if (!json.success) {
                                throw new Error(
                                    (json.data && json.data.message) ? json.data.message : (submitBtn.getAttribute('data-error') || '')
                                );
                            }

                            uploadFinished = true;
                            startPolling(jobId);
                            setProgress(
                                (json.data && json.data.percent) ? json.data.percent : 25,
                                (json.data && json.data.stage) ? json.data.stage : (submitBtn.getAttribute('data-importing') || '')
                            );

                            runImportStep(jobId).catch(function (error) {
                                stopPolling();
                                setProgress(0, '');
                                setStatus(error && error.message ? error.message : (submitBtn.getAttribute('data-error') || ''), '#b32d2e');
                                submitBtn.disabled = false;
                                fileInput.disabled = false;
                            });
                        } catch (error) {
                            stopPolling();
                            setStatus(error && error.message ? error.message : (submitBtn.getAttribute('data-error') || ''), '#b32d2e');
                            submitBtn.disabled = false;
                            fileInput.disabled = false;
                        }
                    });

                    xhr.addEventListener('error', function () {
                        stopPolling();
                        setStatus(submitBtn.getAttribute('data-error') || '', '#b32d2e');
                        submitBtn.disabled = false;
                        fileInput.disabled = false;
                    });

                    xhr.send(formData);
                });
            })();
            </script>

            <hr>

            <h2><?php esc_html_e('Sparade säkerhetskopior', 'maca-restu-pro'); ?></h2>
            <p class="description"><?php esc_html_e('Ladda ner sparade säkerhetskopior för att förvara dem utanför webbplatsen (USB, e-post, molnlagring m.m.). Du kan radera gamla kopior här för att frigöra diskutrymme — en bekräftelse visas innan något tas bort.', 'maca-restu-pro'); ?></p>
            <?php if (empty($files)) : ?>
                <p><?php esc_html_e('Inga säkerhetskopior ännu.', 'maca-restu-pro'); ?></p>
            <?php else : ?>
                <table class="widefat striped">
                    <thead>
                        <tr>
                            <th><?php esc_html_e('Fil', 'maca-restu-pro'); ?></th>
                            <th><?php esc_html_e('Datum', 'maca-restu-pro'); ?></th>
                            <th><?php esc_html_e('Storlek', 'maca-restu-pro'); ?></th>
                            <th><?php esc_html_e('Åtgärder', 'maca-restu-pro'); ?></th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php foreach ($files as $file) : ?>
                            <tr>
                                <td><code><?php echo esc_html($file['filename']); ?></code></td>
                                <td><?php echo esc_html(wp_date(get_option('date_format') . ' ' . get_option('time_format'), $file['modified'])); ?></td>
                                <td><?php echo esc_html(size_format((int) $file['size'])); ?></td>
                                <td>
                                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="display:inline;">
                                        <input type="hidden" name="action" value="maca_menulist_download_backup">
                                        <input type="hidden" name="file" value="<?php echo esc_attr($file['filename']); ?>">
                                        <?php wp_nonce_field('maca_download_backup_' . $file['filename'], 'maca_backup_download_nonce'); ?>
                                        <button type="submit" class="button-link"><?php esc_html_e('Ladda ner', 'maca-restu-pro'); ?></button>
                                    </form>
                                    <span aria-hidden="true"> | </span>
                                    <form method="post" action="" style="display:inline;" onsubmit="return confirm('<?php echo esc_js(__('Radera den här säkerhetskopian permanent? Det går inte att ångra. Ladda ner en kopia först om du kan behöva den senare.', 'maca-restu-pro')); ?>');">
                                        <?php wp_nonce_field('maca_save', 'maca_nonce'); ?>
                                        <input type="hidden" name="maca_action" value="delete_backup">
                                        <input type="hidden" name="maca_type" value="backup">
                                        <input type="hidden" name="maca_backup_filename" value="<?php echo esc_attr($file['filename']); ?>">
                                        <button type="submit" class="button-link delete"><?php esc_html_e('Radera', 'maca-restu-pro'); ?></button>
                                    </form>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    </tbody>
                </table>
            <?php endif; ?>

        </div>
        <?php
    }
}

/**
 * Render the backup admin page (stable global callback for add_submenu_page).
 *
 * @return void
 */
function maca_menulist_admin_render_backup_page() {
    Maca_MenuList_Admin_Backup::instance()->render_backup_page();
}

/**
 * Ensure backup AJAX handlers are registered for admin-ajax.php.
 */
add_action(
    'plugins_loaded',
    static function () {
        if (!defined('DOING_AJAX') || !DOING_AJAX) {
            return;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $action = isset($_REQUEST['action']) ? sanitize_key(wp_unslash($_REQUEST['action'])) : '';
        if (!in_array(
            $action,
            array(
                'maca_menulist_create_export_backup',
                'maca_menulist_download_backup',
                'maca_menulist_import_backup',
                'maca_menulist_import_backup_continue',
                'maca_menulist_import_backup_progress',
            ),
            true
        )) {
            return;
        }

        require_once MACA_MENULIST_PLUGIN_DIR . 'includes/backup.php';
        Maca_MenuList_Admin_Backup::instance();
    },
    0
);
