{include file="$dir/templates/_task_log_modal.tpl"}

<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title pull-left"><i class="fa fa-tasks"></i> Task Queue</h3>
        <div class="pull-right">
            <button class="btn btn-success btn-sm" id="puq-bulk-del-success" title="Delete all tasks with status=success">
                <i class="fa fa-trash"></i> Delete success
            </button>
            <button class="btn btn-danger btn-sm" id="puq-bulk-del-failed" title="Delete tasks with status=error or cancelled">
                <i class="fa fa-trash"></i> Delete error/cancelled
            </button>
            <button class="btn btn-default btn-sm" id="puq-bulk-del-all" title="Delete all completed (success/error/cancelled)">
                <i class="fa fa-broom"></i> Clean all completed
            </button>
            <button class="btn btn-warning btn-sm" id="puq-bulk-force-fail" title="Force-fail all running + awaiting_remote tasks (also kills any orphan restore PIDs + cleans /tmp scratch dirs)">
                <i class="fa fa-exclamation-triangle"></i> Force-fail stuck
            </button>
            <select id="puq-filter-status" class="input-sm" style="margin-right:6px;margin-left:6px;">
                <option value="">All</option>
                <option value="queued">queued</option>
                <option value="running">running</option>
                <option value="awaiting_remote">awaiting_remote</option>
                <option value="success">success</option>
                <option value="error">error</option>
                <option value="cancelled">cancelled</option>
            </select>
            <button class="btn btn-default btn-sm" id="puq-refresh"><i class="fa fa-sync"></i></button>
        </div>
        <div class="clearfix"></div>
    </div>
    <div class="panel-body">
        <table class="table table-striped table-bordered table-condensed" id="puq-data-table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Service</th>
                    <th>Target</th>
                    <th>Action</th>
                    <th>Status</th>
                    <th>Attempts</th>
                    <th>Priority</th>
                    <th>Scheduled</th>
                    <th>Error</th>
                    <th style="width:100px;">Actions</th>
                </tr>
            </thead>
            <tbody><tr><td colspan="10" class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading…</td></tr></tbody>
        </table>
    </div>
</div>

{literal}
<script>
(function(){
    var baseUrl = '{/literal}{$meta.admin_module_url}&ajax={literal}';
    var badge = window.statusBadge;
    function load() {
        var status = $('#puq-filter-status').val();
        puqAjax({
            container: '#puq-data-table',
            loadingCaption: 'Loading tasks…',
            url: baseUrl + 'listTasks&status=' + encodeURIComponent(status),
            success: function(r) {
                var $tbody = $('#puq-data-table tbody').empty();
                if (r.status !== 'success' || !r.data.length) {
                    $tbody.append('<tr><td colspan="10" class="text-center text-muted">No tasks.</td></tr>');
                    return;
                }
                r.data.forEach(function(t) {
                    $tbody.append(
                        '<tr data-id="' + t.id + '">' +
                        '<td>' + t.id + '</td>' +
                        '<td>' + (t.service_id || '—') + '</td>' +
                        '<td>' + esc(t.target_type) + ' #' + (t.target_id || '—') + '</td>' +
                        '<td><code>' + esc(t.action) + '</code></td>' +
                        '<td>' + badge(t.status) + '</td>' +
                        '<td>' + t.attempts + ' / ' + t.max_attempts + '</td>' +
                        '<td>' + t.priority + '</td>' +
                        '<td class="small">' + esc(t.scheduled_at || '—') + '</td>' +
                        '<td class="small text-danger" style="max-width:220px;word-break:break-all;">' + esc((t.error_message || '').substring(0, 120)) + '</td>' +
                        '<td>' +
                          '<button class="btn btn-xs btn-default puq-log" title="View log"><i class="fa fa-list-alt"></i></button> ' +
                          (t.status === 'error' || t.status === 'cancelled'
                            ? '<button class="btn btn-xs btn-info puq-retry" title="Retry"><i class="fa fa-redo"></i></button> '
                            : '') +
                          (t.status === 'queued' || t.status === 'running' || t.status === 'awaiting_remote'
                            ? '<button class="btn btn-xs btn-warning puq-cancel" title="' +
                                  (t.status === 'running' ? 'Cancel hung running task'
                                 : t.status === 'awaiting_remote' ? 'Cancel awaiting_remote task (kills runaway process + cleans temp dir for backup restore)'
                                 : 'Cancel') +
                              '"><i class="fa fa-ban"></i></button>'
                            : '') +
                        '</td></tr>'
                    );
                });
            }
        });
    }

    $(document).ready(function(){
        load();

        $('#puq-filter-status').on('change', load);
        $('#puq-refresh').on('click', function() {
            var btn = this;
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'listTasks&status=' + encodeURIComponent($('#puq-filter-status').val()), dataType: 'json',
                success: function(r) { load(); },
                complete: function() { btnRestore(btn, 'sync', ''); }
            });
        });

        $('#puq-data-table').on('click', '.puq-retry', function() {
            var btn = this;
            var id = $(this).closest('tr').data('id');
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'retryTask', type: 'POST', data: { id: id }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') { showNotification('Task requeued.', 'success'); load(); }
                    else { showNotification(r.msg || 'Retry failed.', 'error'); }
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'redo', ''); }
            });
        });

        $('#puq-data-table').on('click', '.puq-log', function() {
            window.puqOpenTaskLog($(this).closest('tr').data('id'));
        });

        // Bulk-delete by category. Always confirms — destructive.
        // After success we hard-reload the page so any UI state (modals, polls,
        // cached row HTML) is reset cleanly — load() alone sometimes left stale
        // rows on screen if a poll fired in parallel.
        function bulkDelete(label, cats, btn) {
            puqConfirm({
                type: 'danger', icon: 'fa-trash',
                title: 'Delete tasks?',
                text: 'Delete all tasks with status: <code>' + esc(cats.join(', ')) + '</code>.<br><br>This is permanent.',
                ok: 'Delete', cancel: 'Cancel',
                onConfirm: function(){
                    return new Promise(function(resolve, reject){
                        $.ajax({
                            url: baseUrl + 'deleteTasksByCategory', type: 'POST',
                            traditional: false,
                            data: { categories: cats.join(',') },
                            dataType: 'json',
                            success: function(r) {
                                if (r.status === 'success') {
                                    showNotification(r.msg || ('Deleted ' + (r.data && r.data.deleted ? r.data.deleted : 0)), 'success');
                                    setTimeout(function(){ window.location.reload(); }, 600);
                                    resolve();
                                } else {
                                    reject(new Error(r.msg || 'Delete failed'));
                                }
                            },
                            error: function() { reject(new Error('Request failed')); }
                        });
                    });
                }
            });
        }

        $('#puq-bulk-del-success').on('click', function(){ bulkDelete('success', ['success'], this); });
        $('#puq-bulk-del-failed').on('click',  function(){ bulkDelete('failed',  ['error', 'cancelled'], this); });
        $('#puq-bulk-del-all').on('click',     function(){ bulkDelete('completed', ['success','error','cancelled'], this); });

        // Force-fail running + awaiting_remote — for stuck rows when cron
        // died mid-task or remote queue probe is misbehaving. For parked
        // backup-restore tasks this ALSO SSH-kills the runaway PID and
        // removes the /tmp/puq-restore-<token>/ scratch dir so the server
        // doesn't keep restoring against a user we've given up on.
        $('#puq-bulk-force-fail').on('click', function() {
            puqConfirm({
                type: 'warning', icon: 'fa-bolt',
                title: 'Force-fail stuck tasks?',
                text: 'Marks every currently <strong>running</strong> or <strong>awaiting_remote</strong> task as failed. '
                    + 'For parked backup-restore tasks we ALSO kill the runaway v-restore-user process + clean its /tmp scratch dir. '
                    + 'Use when cron died mid-execution and tasks are stuck.<br><br>You can retry the ones you want afterwards.',
                ok: 'Force-fail', cancel: 'Cancel',
                onConfirm: function(){
                    return new Promise(function(resolve, reject){
                        $.ajax({
                            url: baseUrl + 'forceFailRunningTasks', type: 'POST',
                            dataType: 'json',
                            success: function(r) {
                                if (r.status === 'success') {
                                    showNotification(r.msg || ('Force-failed ' + (r.data && r.data.count ? r.data.count : 0)), 'success');
                                    setTimeout(function(){ window.location.reload(); }, 600);
                                    resolve();
                                } else {
                                    reject(new Error(r.msg || 'Force-fail failed'));
                                }
                            },
                            error: function() { reject(new Error('Request failed')); }
                        });
                    });
                }
            });
        });

        $('#puq-data-table').on('click', '.puq-cancel', function() {
            var btn = this;
            var id = $(this).closest('tr').data('id');
            btnSpinner(btn);
            $.ajax({
                url: baseUrl + 'cancelTask', type: 'POST', data: { id: id }, dataType: 'json',
                success: function(r) {
                    if (r.status === 'success') { showNotification('Task cancelled.', 'success'); load(); }
                    else { showNotification(r.msg || 'Cancel failed.', 'error'); }
                },
                error: function() { showNotification('Request failed.', 'error'); },
                complete: function() { btnRestore(btn, 'ban', ''); }
            });
        });
    });
})();
</script>
{/literal}
