{* Backups tab. Split-mode services render two columns (web/mail);
   unified-mode services collapse into one full-width "Account backups"
   table using role='all'. The JS at the bottom branches on the same
   deployment_mode signal exported as window.puqSvcDeploymentMode. *}
{if $service_row.deployment_mode eq 'unified'}
<div class="row">
    <div class="col-md-12">
        <h4><i class="fa fa-archive"></i> Account backups
            <small class="text-muted" id="puq-svc-bk-all-count"></small>
            <span class="label label-primary" style="margin-left:6px;font-size:11px;">unified</span>
        </h4>
        <div style="margin-bottom:6px;">
            <button type="button" class="btn btn-primary btn-xs puq-bk-create" data-role="all"><i class="fa fa-plus"></i> Backup account now</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-sync"   data-role="all"><i class="fa fa-sync"></i> Sync from server</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-reload" data-role="all"><i class="fa fa-redo"></i> Reload</button>
            <button type="button" class="btn btn-info btn-xs puq-bk-check-restore" data-role="web" title="SSH-probe Hestia restore queue (anchored on web)"><i class="fa fa-search"></i> Check restore now</button>
        </div>
        <table class="table table-striped table-condensed" id="puq-svc-bk-all-table" style="width:100%;">
            <thead><tr><th>ID</th><th>Filename</th><th>Size</th><th>Status</th><th>Created</th><th>Actions</th></tr></thead>
            <tbody></tbody>
        </table>
    </div>
</div>
{else}
<div class="row">
    {* Vanity: the mailbox is on the SHARED provider mail user — there is no
       per-customer mail backup, so only the web account is shown (full width). *}
    <div class="{if $service_row.deployment_mode eq 'vanity'}col-md-12{else}col-md-6{/if}">
        <h4><i class="fa fa-globe"></i> Web backups
            <small class="text-muted" id="puq-svc-bk-web-count"></small></h4>
        <div style="margin-bottom:6px;">
            <button type="button" class="btn btn-primary btn-xs puq-bk-create" data-role="web"><i class="fa fa-plus"></i> Backup web now</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-sync"   data-role="web"><i class="fa fa-sync"></i> Sync from server</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-reload" data-role="web"><i class="fa fa-redo"></i> Reload</button>
            <button type="button" class="btn btn-info btn-xs puq-bk-check-restore" data-role="web" title="SSH-probe Hestia restore queue for this user"><i class="fa fa-search"></i> Check restore now</button>
        </div>
        <table class="table table-striped table-condensed" id="puq-svc-bk-web-table" style="width:100%;">
            <thead><tr><th>ID</th><th>Filename</th><th>Size</th><th>Status</th><th>Created</th><th>Actions</th></tr></thead>
            <tbody></tbody>
        </table>
    </div>
    {if $service_row.deployment_mode ne 'vanity'}
    <div class="col-md-6">
        <h4><i class="fa fa-envelope"></i> Mail backups
            <small class="text-muted" id="puq-svc-bk-mail-count"></small></h4>
        <div style="margin-bottom:6px;">
            <button type="button" class="btn btn-primary btn-xs puq-bk-create" data-role="mail"><i class="fa fa-plus"></i> Backup mail now</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-sync"   data-role="mail"><i class="fa fa-sync"></i> Sync from server</button>
            <button type="button" class="btn btn-default btn-xs puq-bk-reload" data-role="mail"><i class="fa fa-redo"></i> Reload</button>
            <button type="button" class="btn btn-info btn-xs puq-bk-check-restore" data-role="mail" title="SSH-probe Hestia restore queue for this user"><i class="fa fa-search"></i> Check restore now</button>
        </div>
        <table class="table table-striped table-condensed" id="puq-svc-bk-mail-table" style="width:100%;">
            <thead><tr><th>ID</th><th>Filename</th><th>Size</th><th>Status</th><th>Created</th><th>Actions</th></tr></thead>
            <tbody></tbody>
        </table>
    </div>
    {/if}
</div>
{/if}
<script>window.puqSvcDeploymentMode = {if $service_row.deployment_mode eq 'unified'}'unified'{elseif $service_row.deployment_mode eq 'vanity'}'vanity'{else}'split'{/if};</script>
{literal}
<script>
(window.puqSvc = window.puqSvc || {}).init_backups = function(ctx){
    var esc = ctx.esc, baseUrl = ctx.baseUrl, puqId = ctx.puqId, whmcsId = ctx.whmcsId, fmtDate = ctx.fmtDate;
    // Unified-mode services render one 'all' table; split renders two
    // (web/mail). PAGE_ROLES drives which load()/reload calls fire.
    var PAGE_ROLES = (window.puqSvcDeploymentMode === 'unified') ? ['all']
                   : (window.puqSvcDeploymentMode === 'vanity') ? ['web']
                   : ['web', 'mail'];
    var dt = {};
    PAGE_ROLES.forEach(function(r){ dt[r] = null; });

    function fmtSize(n){
        if (n == null || n === '') return '—';
        n = parseInt(n, 10);
        if (n < 1024) return n + ' B';
        var u = ['KB','MB','GB','TB']; var i = -1;
        do { n /= 1024; i++; } while (n >= 1024 && i < u.length-1);
        return n.toFixed(n < 10 ? 2 : 1) + ' ' + u[i];
    }

    function load(role) {
        puqAjax({ container: '#puq-svc-bk-' + role + '-table', loadingCaption: 'Loading ' + role + ' backups…',
            url: baseUrl + 'listServiceBackups&service_id=' + whmcsId + '&role=' + role, dataType: 'json',
            success: function(r){
                var rows = (r.status === 'success' && r.data && r.data.backups) ? r.data.backups : [];
                $('#puq-svc-bk-' + role + '-count').text('(' + rows.length + ')');
                if (dt[role]) { dt[role].destroy(); $('#puq-svc-bk-' + role + '-table tbody').empty(); }
                rows.forEach(function(b){
                    var cls = ({queued:'default',creating:'info',active:'success',error:'danger',restoring:'info',deleting:'warning'})[b.deploy_status] || 'default';
                    var rowActions = '';
                    if (b.deploy_status === 'active') {
                        rowActions =
                            '<button class="btn btn-xs btn-warning puq-bk-restore" data-id="' + esc(b.id) + '" title="Restore (DESTRUCTIVE)"><i class="fa fa-undo"></i></button> ' +
                            '<button class="btn btn-xs btn-danger puq-bk-delete" data-id="' + esc(b.id) + '" title="Delete"><i class="fa fa-trash"></i></button>';
                    } else if (b.deploy_status === 'error') {
                        rowActions =
                            '<button class="btn btn-xs btn-danger puq-bk-delete" data-id="' + esc(b.id) + '" title="Delete local row"><i class="fa fa-trash"></i></button>';
                    }
                    $('#puq-svc-bk-' + role + '-table tbody').append('<tr>' +
                        '<td>' + esc(b.id) + '</td>' +
                        '<td><code style="font-size:11px;">' + esc(b.filename || '—') + '</code></td>' +
                        '<td>' + fmtSize(b.size_bytes) + '</td>' +
                        '<td><span class="label label-' + cls + '">' + esc(b.deploy_status) + '</span>' +
                          (b.deploy_error ? ' <i class="fa fa-exclamation-triangle text-danger" title="' + esc(b.deploy_error) + '"></i>' : '') + '</td>' +
                        '<td>' + fmtDate(b.created_at) + '</td>' +
                        '<td>' + rowActions + '</td>' +
                        '</tr>');
                });
                dt[role] = $('#puq-svc-bk-' + role + '-table').DataTable({ order: [[0, 'desc']], pageLength: 10, autoWidth: false });
            }
        });
    }

    $('#tab-backups').on('click', '.puq-bk-create', function(){
        var role = $(this).data('role'); var btn = this; btnSpinner(btn);
        $.ajax({ url: baseUrl + 'triggerServiceBackup', type: 'POST',
            data: { service_id: whmcsId, role: role }, dataType: 'json',
            success: function(r){ showNotification(r.msg || 'Queued', r.status === 'success' ? 'success' : 'error'); load(role); },
            error: function(){ showNotification('Request failed.', 'error'); },
            complete: function(){ btnRestore(btn, 'plus', 'Backup ' + role + ' now'); }
        });
    });

    $('#tab-backups').on('click', '.puq-bk-sync', function(){
        var role = $(this).data('role'); var btn = this; btnSpinner(btn);
        $.ajax({ url: baseUrl + 'syncServiceBackups', type: 'POST',
            data: { service_id: whmcsId, role: role }, dataType: 'json',
            success: function(r){ showNotification(r.msg || 'Queued', r.status === 'success' ? 'success' : 'error'); load(role); },
            complete: function(){ btnRestore(btn, 'sync', 'Sync from server'); }
        });
    });

    $('#tab-backups').on('click', '.puq-bk-reload', function(){ load($(this).data('role')); });

    $('#tab-backups').on('click', '.puq-bk-restore', function(){
        var id = $(this).data('id');
        puqConfirm({
            type: 'danger', icon: 'fa-undo',
            title: 'Restore backup?',
            text: '<strong>Destructive.</strong> The service will be overwritten with the state captured in this backup. Anything created since then will be lost.',
            ok: 'Restore', cancel: 'Cancel',
            onConfirm: function(){
                return new Promise(function(resolve, reject){
                    $.ajax({ url: baseUrl + 'restoreServiceBackup', type: 'POST', data: { backup_id: id }, dataType: 'json',
                        success: function(r){
                            if (r.status === 'success') { showNotification(r.msg || 'Restore queued', 'success'); PAGE_ROLES.forEach(load); resolve(); }
                            else reject(new Error(r.msg || 'Restore failed'));
                        },
                        error: function(){ reject(new Error('Request failed')); }
                    });
                });
            }
        });
    });
    $('#tab-backups').on('click', '.puq-bk-delete', function(){
        var id = $(this).data('id');
        puqConfirm({
            type: 'danger', icon: 'fa-trash',
            title: 'Delete backup?',
            text: 'Backup <code>#' + id + '</code> will be removed from the server. This cannot be undone.',
            ok: 'Delete', cancel: 'Cancel',
            onConfirm: function(){
                return new Promise(function(resolve, reject){
                    $.ajax({ url: baseUrl + 'deleteServiceBackup', type: 'POST', data: { backup_id: id }, dataType: 'json',
                        success: function(r){
                            if (r.status === 'success') { showNotification(r.msg || 'Delete queued', 'success'); PAGE_ROLES.forEach(load); resolve(); }
                            else reject(new Error(r.msg || 'Delete failed'));
                        },
                        error: function(){ reject(new Error('Request failed')); }
                    });
                });
            }
        });
    });

    // ---- Check restore now ----
    // Synchronously SSH-probes Hestia's restore queue for this user and
    // shows the result in a modal. If Hestia says idle BUT we still have a
    // parked task / restore_lock, exposes a "Finalize" button that runs
    // the resync + lock-clear inline (catches the case where cron is
    // misbehaving or the admin doesn't want to wait for the next tick).
    function buildCheckRestoreBody(role, d){
        var status = d.active
            ? '<span class="label label-warning">ACTIVE</span> Hestia is currently restoring this user.'
            : '<span class="label label-success">IDLE</span> Hestia has finished or never had this user in the queue.';
        var rows = ''
            + '<tr><th style="width:140px;">Role</th><td>' + esc(role) + '</td></tr>'
            + '<tr><th>User</th><td><code>' + esc(d.username) + '</code> @ ' + esc(d.server_name) + '</td></tr>'
            + '<tr><th>Hestia queue</th><td>' + status + '</td></tr>';
        if (d.lock) {
            var lockLine = d.lock.locked
                ? '<span class="label label-warning">LOCKED</span>' + (d.lock.started_at ? ' since ' + esc(d.lock.started_at) : '')
                : '<span class="label label-success">UNLOCKED</span>';
            rows += '<tr><th>Service lock</th><td>' + lockLine + '</td></tr>';
        }
        if (d.parked_task) {
            rows += '<tr><th>Parked task</th><td>#' + esc(d.parked_task.id)
                  + ' <span class="label label-info">' + esc(d.parked_task.status) + '</span>'
                  + ' (probes: ' + esc(d.parked_task.probe_count || 0) + ', started ' + esc(d.parked_task.started_at || d.parked_task.created_at || '—') + ')</td></tr>';
        } else {
            rows += '<tr><th>Parked task</th><td><span class="text-muted">none</span></td></tr>';
        }
        rows += '<tr><th>Probed at</th><td>' + esc(d.probed_at) + '</td></tr>';

        var html = '<table class="table table-condensed" style="margin:0 0 8px;">' + rows + '</table>';
        if (d.log_tail) {
            html += '<div style="margin-top:6px;"><strong>Hestia log tail:</strong></div>'
                  + '<pre style="background:#1e1e1e;color:#dcdcdc;padding:8px;font-size:11px;max-height:200px;overflow:auto;margin:4px 0 0;">'
                  + esc(d.log_tail) + '</pre>';
        }
        if (d.can_finalize) {
            html += '<div style="margin-top:10px;padding:8px;background:#fff3cd;border:1px solid #ffe69c;border-radius:3px;font-size:12px;color:#856404;">'
                  + '<i class="fa fa-info-circle"></i> Hestia is idle but the local lock is still set. '
                  + 'You can finalise now (runs resync + clears the lock) instead of waiting for the next probe cron.'
                  + '</div>'
                  + '<div style="margin-top:8px;text-align:right;">'
                  + '  <button type="button" class="btn btn-primary btn-sm puq-bk-finalize-restore" data-role="' + esc(role) + '">'
                  + '    <i class="fa fa-check"></i> Finalise restore now'
                  + '  </button>'
                  + '</div>';
        }
        // Cancel — only meaningful while a parked task exists. If Hestia is
        // already running v-restore-user, the backend will refuse with 409
        // (we can't safely abort mid-restore). For "queued but not yet
        // running" the backend removes the line from restore-users.log and
        // Hestia never picks it up.
        if (d.parked_task) {
            html += '<div style="margin-top:14px;padding-top:10px;border-top:1px solid #eee;">'
                  + '<div style="display:flex;align-items:center;gap:8px;">'
                  + '  <small style="color:#777;flex:1;">'
                  + (d.active
                      ? '<i class="fa fa-exclamation-triangle text-warning"></i> Hestia is actively restoring — cancel will be refused. Wait for it to finish.'
                      : 'Restore is parked in Hestia\'s queue but hasn\'t started yet. Cancelling removes the queue line so Hestia never picks it up.')
                  + '  </small>'
                  + '  <button type="button" class="btn btn-danger btn-sm puq-bk-cancel-restore" data-role="' + esc(role) + '">'
                  + '    <i class="fa fa-times"></i> Cancel restore'
                  + '  </button>'
                  + '</div>'
                  + '</div>';
        }
        return html;
    }

    function showCheckRestoreModal(role) {
        // Open modal immediately with a loading message; replace body once
        // the probe round-trip returns. Probe is ~200-500 ms but feels
        // snappier with progressive content.
        var modal = puqModal({
            type: 'info', icon: 'fa-search',
            title: 'Check restore — ' + role,
            body: '<div class="text-center" style="padding:30px;"><i class="fa fa-spinner fa-spin fa-2x text-info"></i><div style="margin-top:10px;color:#666;">SSH-probing Hestia restore queue…</div></div>',
            cancel: 'Close', ok: ' ',  // hide OK by giving it whitespace label (we render our own)
        });
        // The "OK" button is harmless here — just close. Hide it visually.
        setTimeout(function(){ jQuery(modal.box).find('.puq-confirm-btn-ok').hide(); }, 0);

        $.ajax({
            url: baseUrl + 'checkRestoreNow', type: 'POST',
            data: { service_id: whmcsId, role: role }, dataType: 'json',
            success: function(r) {
                var $box = jQuery(modal.box);
                if (r.status !== 'success' || !r.data) {
                    $box.find('.puq-confirm-text').html(
                        '<div class="alert alert-danger" style="margin:0;text-align:left;">'
                      + '<i class="fa fa-exclamation-triangle"></i> ' + esc(r.msg || 'Probe failed')
                      + '</div>'
                    );
                    return;
                }
                $box.find('.puq-confirm-text').html(buildCheckRestoreBody(role, r.data));
            },
            error: function() {
                jQuery(modal.box).find('.puq-confirm-text').html(
                    '<div class="alert alert-danger" style="margin:0;text-align:left;">Request failed.</div>'
                );
            }
        });
    }

    $('#tab-backups').on('click', '.puq-bk-check-restore', function(){
        var role = $(this).data('role');
        showCheckRestoreModal(role);
    });

    $('#tab-backups').on('click', '.puq-bk-finalize-restore', function(){
        var role = $(this).data('role');
        var btn  = this;
        btnSpinner(btn, 'Finalising…');
        $.ajax({
            url: baseUrl + 'finalizeRestoreNow', type: 'POST',
            data: { service_id: whmcsId, role: role }, dataType: 'json',
            success: function(r) {
                btnRestore(btn, 'check', 'Finalise restore now');
                if (r.status === 'success') {
                    showNotification(r.msg || 'Restore finalised.', 'success');
                    // Close any open modal and reload the row tables.
                    jQuery('.puq-confirm-overlay').remove();
                    PAGE_ROLES.forEach(load);
                } else {
                    showNotification(r.msg || 'Finalise failed.', 'error');
                }
            },
            error: function() {
                btnRestore(btn, 'check', 'Finalise restore now');
                showNotification('Request failed.', 'error');
            }
        });
    });

    // Cancel a parked awaiting_remote restore task. Confirms first (destructive
    // operations always need a second click) then hits cancelRestoreNow. The
    // backend may refuse with 409 if Hestia is mid-restore — we surface that
    // as a clear error toast rather than a generic "failed".
    $('#tab-backups').on('click', '.puq-bk-cancel-restore', function(){
        var role = $(this).data('role');
        puqConfirm({
            type: 'danger', icon: 'fa-times',
            title: 'Cancel scheduled restore?',
            text: 'Removes the <code>' + role + '</code> restore from Hestia\'s queue (only works if it hasn\'t started yet). '
                + 'The backup file itself is untouched — you can restore it again later.',
            ok: 'Cancel restore', cancel: 'Keep it',
            onConfirm: function(){
                return new Promise(function(resolve, reject){
                    $.ajax({
                        url: baseUrl + 'cancelRestoreNow', type: 'POST',
                        data: { service_id: whmcsId, role: role }, dataType: 'json',
                        success: function(r) {
                            if (r.status === 'success') {
                                showNotification(r.msg || 'Restore cancelled.', 'success');
                                jQuery('.puq-confirm-overlay').remove();
                                PAGE_ROLES.forEach(load);
                                resolve();
                            } else {
                                // 409 (Hestia mid-restore) gets a more visible toast.
                                reject(new Error(r.msg || 'Cancel failed'));
                            }
                        },
                        error: function(){ reject(new Error('Request failed')); }
                    });
                });
            }
        });
    });

    PAGE_ROLES.forEach(load);
};
</script>
{/literal}
