{% include "generic/exam_candidate_headers.html" %}
<div class="card mb-2 bg-dark text-light border-0">
    <div class="card-body py-2">
        <div class="d-flex justify-content-between align-items-start mb-2">
            <div>
                <h5 class="card-title mb-0">Users</h5>
                {% if groups %}
                    <div class="small text-muted mt-1">Users from the following groups are available:
                        {% for group in groups %}
                            <a href='{{group.get_absolute_url}}' class="badge bg-light text-dark border ms-1">{{group}}</a>
                        {% endfor %}
                    </div>
                {% else %}
                    <div class="small text-muted mt-1">This exam is not associated with any user groups. <a href="{% url app_name|add:':exam_groups_edit' exam.pk %}">Edit and add a group</a> to enable user management.</div>
                {% endif %}
            </div>
            <div class="btn-group">
                {% if current_user_users or available_user_users %}
                    <button class="btn btn-sm btn-outline-light toggle-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Toggle all</button>
                {% endif %}
                <button class="btn btn-sm btn-outline-success add-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Add all</button>
                <button class="btn btn-sm btn-outline-danger remove-all-btn" data-bulk-url="{% url app_name|add:':exam_user_bulk_edit' exam.pk %}">Remove all</button>
            </div>
        </div>



        <div class="d-flex align-items-center mb-2">
            <div class="me-auto small text-muted">Sort by:</div>
            <div class="btn-group btn-group-sm user-sort-group" role="group" aria-label="Sort">
                <button type="button" class="btn btn-sm btn-outline-light sort-btn" data-key="cid">Username <span class="sort-caret"></span></button>
                <button type="button" class="btn btn-sm btn-outline-light sort-btn" data-key="name">Name <span class="sort-caret"></span></button>
                <button type="button" class="btn btn-sm btn-outline-light sort-btn" data-key="email">Email <span class="sort-caret"></span></button>
            </div>
        </div>

        {% include 'generic/partials/user_user_list.html' with exam=exam current_user_users=current_user_users available_user_users=available_user_users %}
    </div>
</div>

        <!-- Collapsible panel for adding arbitrary users (collapsed by default) -->
<div class="mt-3">
    <p>
        <a class="btn btn-sm btn-link" data-bs-toggle="collapse" href="#add-arbitrary-users-collapse" role="button" aria-expanded="false" aria-controls="add-arbitrary-users-collapse">Add arbitrary users</a>
    </p>
    <div class="collapse" id="add-arbitrary-users-collapse">
        <div class="card card-body">
            <label class="form-label small mb-1">Add arbitrary users</label>
            {{ user_search_widget|default:''|safe }}
            <div class="mt-2">
                <button type="button" id="add-selected-users-btn" class="btn btn-sm btn-outline-success">Add selected users</button>
            </div>
        </div>
    </div>
</div>

<script>
    // Mirror the HTMX-enabled behavior used for CID users.
    document.addEventListener('DOMContentLoaded', function(){
        // Bulk form for users
        const bulkForm = document.createElement('form');
        bulkForm.id = 'bulk-user-form';
        bulkForm.className = 'd-none';
        bulkForm.setAttribute('hx-target', '#user-users-wrap');
        bulkForm.setAttribute('hx-swap', 'outerHTML');
        const bulkInput = document.createElement('input'); bulkInput.type='hidden'; bulkInput.name='bulk_pks'; bulkInput.id='bulk_pks_input_user'; bulkForm.appendChild(bulkInput);
        const bulkAddInput = document.createElement('input'); bulkAddInput.type='hidden'; bulkAddInput.name='add'; bulkAddInput.id='bulk_add_input_user'; bulkForm.appendChild(bulkAddInput);
        const csrfTokenInput = document.createElement('input'); csrfTokenInput.type='hidden'; csrfTokenInput.name='csrfmiddlewaretoken'; csrfTokenInput.value='{{ csrf_token }}'; bulkForm.appendChild(csrfTokenInput);
        document.body.appendChild(bulkForm);

        function setLoading(btn, loading){ if(!btn) return; try{ if(loading){ btn.dataset._origDisabled = btn.disabled ? '1':'0'; btn.disabled = true; const spinner = document.createElement('span'); spinner.className='btn-spinner spinner-border spinner-border-sm ms-2'; spinner.setAttribute('role','status'); spinner.setAttribute('aria-hidden','true'); btn.appendChild(spinner);} else { if(typeof btn.dataset._origDisabled !== 'undefined'){ btn.disabled = btn.dataset._origDisabled === '1'; delete btn.dataset._origDisabled;} else { btn.disabled = false;} const s = btn.querySelector('.btn-spinner'); if(s) s.remove(); } }catch(e){} }

        function submitBulk(url, pks, add, triggeringButton){
            if (window.htmx && typeof htmx.submit === 'function'){
                if(triggeringButton) setLoading(triggeringButton, true);
                bulkForm.setAttribute('hx-post', url);
                bulkInput.value = JSON.stringify(pks);
                if (add === null) bulkAddInput.disabled = true; else { bulkAddInput.disabled = false; bulkAddInput.value = add ? 'true' : 'false'; }
                htmx.submit(bulkForm); return;
            }
            if(triggeringButton) setLoading(triggeringButton, true);
            const fd = new FormData(); fd.append('bulk_pks', JSON.stringify(pks)); if (add !== null) fd.append('add', add ? 'true' : 'false'); const csrf = document.querySelector('input[name="csrfmiddlewaretoken"]').value; const headers = { 'X-CSRFToken': csrf };
            fetch(url, { method: 'POST', body: fd, headers: headers, credentials: 'same-origin' })
                .then(resp => resp.text().then(text => ({ resp, text })))
                .then(({ resp, text }) => { try{ const parser = new DOMParser(); const doc = parser.parseFromString(text, 'text/html'); const newWrap = doc.querySelector('#user-users-wrap'); if (newWrap){ const oldWrap = document.querySelector('#user-users-wrap'); if (oldWrap) oldWrap.replaceWith(newWrap); } else { const newList = doc.querySelector('#user-users-list'); if (newList){ const old = document.querySelector('#user-users-list'); if (old) old.replaceWith(newList); } } }catch(e){ console.error('bulk swap failed', e);} const trigger = resp.headers.get('HX-Trigger'); if (trigger){ try{ const detail = JSON.parse(trigger); for(const k in detail){ document.body.dispatchEvent(new CustomEvent(k, { detail: detail[k] })); } }catch(e){} } })
                .catch(err => console.error('bulk request failed', err))
                .finally(()=>{ if(triggeringButton) setLoading(triggeringButton, false); });
        }

        const defaultBulkUrl = "{% url app_name|add:':exam_user_bulk_edit' exam.pk %}";
        document.querySelectorAll('.add-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ const url = btn.dataset.bulkUrl || defaultBulkUrl; const items = document.querySelectorAll('#user-users-list li:not(.current)'); const pks = Array.from(items).map(i => i.dataset.pk).filter(Boolean).map(Number); if (!pks.length) return; submitBulk(url, pks, true, btn); }); });
        document.querySelectorAll('.remove-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ if(!confirm('Remove all selected users from the exam?')) return; const url = btn.dataset.bulkUrl || defaultBulkUrl; const items = document.querySelectorAll('#user-users-list li.current'); const pks = Array.from(items).map(i => i.dataset.pk).filter(Boolean).map(Number); if (!pks.length) return; submitBulk(url, pks, false, btn); }); });

        document.querySelectorAll('.toggle-all-btn').forEach(function(btn){ btn.addEventListener('click', function(){ const url = btn.dataset.bulkUrl || document.querySelector('.add-all-btn')?.dataset.bulkUrl || defaultBulkUrl; const items = Array.from(document.querySelectorAll('#user-users-list li')).map(function(li){ return { pk: Number(li.dataset.pk), add: !li.classList.contains('current') }; }); if (!items.length) return; submitBulk(url, items, null, btn); }); });

        // Handler for adding arbitrary selected users from the search widget
        const addSelectedBtn = document.getElementById('add-selected-users-btn');
        if (addSelectedBtn){
            addSelectedBtn.addEventListener('click', function(){
                const sel = document.getElementById('id_add_users');
                if(!sel) return;
                const pks = Array.from(sel.options).map(o => o.value).filter(Boolean).map(Number);
                if(!pks.length) return;
                submitBulk(defaultBulkUrl, pks, true, addSelectedBtn);
            });
        }

        // Listen for single-item toggle events to update counts and show toasts
        document.body.addEventListener('user_toggled', function(evt){ try { const detail = evt.detail || {}; const added = detail.added; if (window.toastr) { if (added) toastr.info('User added to exam'); else toastr.info('User removed from exam'); } const addedEl = document.getElementById('user-count-added'); const availEl = document.getElementById('user-count-available'); if (addedEl && availEl){ let addedCount = parseInt(addedEl.textContent || '0') || 0; let availCount = parseInt(availEl.textContent || '0') || 0; if (added){ addedCount += 1; availCount = Math.max(0, availCount - 1); } else { addedCount = Math.max(0, addedCount - 1); availCount += 1; } addedEl.textContent = String(addedCount); availEl.textContent = String(availCount); } } catch(e){} });

        // Delegated click handler for per-item toggle buttons (HTMX preferred)
        document.body.addEventListener('click', function(e){ const btn = e.target.closest && e.target.closest('.toggle-btn'); if(!btn) return; const form = btn.closest('form'); if(!form) return; e.preventDefault(); setLoading(btn, true); if(window.htmx && typeof htmx.submit === 'function'){ htmx.submit(form); return; } (async function(){ try{ const url = form.action || form.getAttribute('hx-post'); const fd = new FormData(form); const csrf = document.querySelector('input[name="csrfmiddlewaretoken"]')?.value; const headers = { 'HX-Request': 'true' }; if(csrf) headers['X-CSRFToken'] = csrf; const resp = await fetch(url, { method: 'POST', body: fd, headers: headers, credentials: 'same-origin' }); const text = await resp.text(); try{ const parser = new DOMParser(); const doc = parser.parseFromString(text, 'text/html'); const newLi = doc.querySelector('li'); const oldLi = form.closest('li'); if(newLi && oldLi){ oldLi.replaceWith(newLi); } const trigger = resp.headers.get('HX-Trigger'); if (trigger){ try{ const detail = JSON.parse(trigger); for(const k in detail){ document.body.dispatchEvent(new CustomEvent(k, { detail: detail[k] })); } }catch(e){} } }catch(err){ console.error('toggle parse/swap failed', err); } }catch(err){ console.error('toggle request failed', err); } finally{ setLoading(btn, false); } })(); });

        // Sorting for user list (scoped to this card)
        (function(){
            const sortGroup = document.querySelector('.user-sort-group');
            if(!sortGroup) return;
            let userSort = { key: 'cid', dir: 'asc' };
            function updateUserCarets(){
                const buttons = sortGroup.querySelectorAll('.sort-btn');
                buttons.forEach(function(b){ const key = b.dataset.key; const caret = b.querySelector('.sort-caret'); if(caret) caret.textContent = (userSort.key === key) ? (userSort.dir === 'asc' ? ' ▲' : ' ▼') : ''; });
            }
            function getUserValue(li, key){
                if(!li) return '';
                if(key === 'cid') return (li.dataset.username || '').toString().toLowerCase();
                return (li.dataset[key] || '').toString().toLowerCase();
            }
            function sortUserList(key){
                const ul = document.getElementById('user-users-list'); if(!ul) return;
                const items = Array.from(ul.children);
                const dir = (userSort.key === key && userSort.dir === 'asc') ? 'desc' : 'asc';
                items.sort(function(a,b){ const va = getUserValue(a,key); const vb = getUserValue(b,key); if(va < vb) return dir === 'asc' ? -1 : 1; if(va > vb) return dir === 'asc' ? 1 : -1; return 0; });
                items.forEach(function(it){ ul.appendChild(it); });
                userSort = { key: key, dir: dir };
                updateUserCarets();
            }
            sortGroup.querySelectorAll('.sort-btn').forEach(function(b){ b.addEventListener('click', function(){ sortUserList(b.dataset.key); }); });
            updateUserCarets();
        })();

    });
</script>
<style>
    .current {
        color: lightgray;
    }
    /* removed decorative pseudo-element that showed [ADDED TO EXAM] */

    button {
        padding: 0;
    }
</style>