import { apiGet, apiPost, apiPut, apiDelete } from '../api.js';
import { canEdit, pageHeaderHTML, showToast, getRole } from '../app.js';
import { confirmAction } from '../confirm-modal.js';
import { navigate } from '../router.js';

export async function questionnairesPage() {
    const app = document.getElementById('app');
    app.innerHTML = `
        ${pageHeaderHTML('Questionnaires', '<span id="headerActions"></span>')}
        <div id="qGrid" class="q-dashboard-root"><div class="spinner"></div></div>
        <div id="scoringProfilesPanel"></div>
        <div id="categoryKeysPanel"></div>
    `;

    if (canEdit()) {
        document.getElementById('headerActions').innerHTML = `
            <input type="file" id="importBundleFile" accept=".json,application/json" hidden>
            <button type="button" class="btn" id="importBundleBtn">Import questionnaires</button>
            <a href="#/questionnaire/new" class="btn btn-primary">+ New Questionnaire</a>
        `;
        bindImportBundle();
    }

    try {
        const [data, profilesData] = await Promise.all([
            apiGet('questionnaires.php'),
            apiGet('scoring_profiles.php').catch(() => ({ profiles: [] })),
        ]);
        const categoryKeys = data.categoryKeys || [];
        renderGrid(data.questionnaires || [], categoryKeys);
        renderScoringProfilesSection(profilesData.profiles || [], data.questionnaires || []);
        renderCategoryKeysPanel(categoryKeys);
        bindCategoryLabelEditors();
    } catch (e) {
        showToast(e.message, 'error');
        document.getElementById('qGrid').innerHTML = `<p class="error-text">${e.message}</p>`;
    }
}

function renderCategoryKeysPanel(categoryKeys) {
    const panel = document.getElementById('categoryKeysPanel');
    if (!panel) return;

    if (!canEdit()) {
        panel.innerHTML = '';
        return;
    }

    if (!categoryKeys.length) {
        panel.innerHTML = `
            <div class="card category-keys-card" style="margin-top:16px">
                <h3 style="margin:0 0 8px;font-size:1rem">Category keys</h3>
                <p class="data-toolbar-hint" style="margin:0">
                    Set a category key on a questionnaire (editor → settings) to group it on the app opening screen.
                    German group titles can be edited below once a key is in use.
                </p>
            </div>`;
        return;
    }

    panel.innerHTML = `
        <div class="card category-keys-card" style="margin-top:16px">
            <h3 style="margin:0 0 8px;font-size:1rem">Category keys</h3>
            <p class="data-toolbar-hint" style="margin:0 0 12px">
                German labels for the app opening screen. Other languages: <a href="#/translations">Translations</a>.
                Delete removes the key from questionnaires, all translations, and catalog defaults.
            </p>
            <div class="table-wrapper" style="max-height:none">
                <table class="data-table category-keys-table">
                    <thead>
                        <tr>
                            <th>Category key</th>
                            <th>App string key</th>
                            <th>German label</th>
                            <th>Questionnaires</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        ${categoryKeys.map(row => `
                            <tr class="${row.orphaned ? 'row-orphan-category' : ''}">
                                <td><code>${esc(row.categoryKey)}</code></td>
                                <td><code class="data-toolbar-hint">${esc(row.stringKey)}</code></td>
                                <td class="category-label-cell">
                                    <input type="text" class="category-german-input"
                                        data-category-key="${esc(row.categoryKey)}"
                                        value="${esc(row.germanLabel || '')}"
                                        placeholder="German label"
                                        aria-label="German label for ${esc(row.categoryKey)}">
                                </td>
                                <td>${row.orphaned
                                    ? '<span class="data-toolbar-hint">unused</span>'
                                    : esc(String(row.questionnaireCount))}</td>
                                <td style="text-align:right;white-space:nowrap">
                                    <button type="button" class="btn btn-sm btn-danger delete-cat-key-btn"
                                        data-key="${esc(row.categoryKey)}"
                                        data-count="${row.questionnaireCount}">Delete</button>
                                </td>
                            </tr>
                        `).join('')}
                    </tbody>
                </table>
            </div>
        </div>`;

    panel.querySelectorAll('.delete-cat-key-btn').forEach(btn => {
        btn.addEventListener('click', async (e) => {
            e.stopPropagation();
            const key = btn.dataset.key;
            const count = parseInt(btn.dataset.count || '0', 10);
            let msg = `Delete category key "${key}"?\n\nThis removes all translations and catalog defaults for questionnaire_group_${key}.`;
            if (count > 0) {
                msg += `\n\n${count} questionnaire(s) will have their category key cleared.`;
            }
            if (!(await confirmAction({
                title: 'Delete category key',
                message: msg,
                confirmLabel: 'Delete',
                variant: 'danger',
            }))) return;
            btn.disabled = true;
            try {
                const result = await apiPost('questionnaires.php', { action: 'deleteCategoryKey', categoryKey: key });
                const cleared = result.questionnairesCleared ?? count;
                showToast(
                    cleared
                        ? `Deleted "${key}" and cleared ${cleared} questionnaire(s)`
                        : `Deleted "${key}"`,
                    'success'
                );
                await questionnairesPage();
            } catch (err) {
                showToast(err.message, 'error');
                btn.disabled = false;
            }
        });
    });
}

function categoryGermanInputHTML(categoryKey, label) {
    if (!canEdit() || !categoryKey) {
        return esc(label);
    }
    return `<input type="text" class="category-german-input category-title-input"
        data-category-key="${esc(categoryKey)}"
        value="${esc(label)}"
        aria-label="German category title">`;
}

function bindCategoryLabelEditors() {
    if (!canEdit()) return;

    document.querySelectorAll('.category-german-input').forEach(input => {
        input.dataset.lastSaved = input.value.trim();

        input.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                input.blur();
            }
        });

        input.addEventListener('blur', () => saveCategoryGermanLabel(input));
    });
}

async function saveCategoryGermanLabel(input) {
    const categoryKey = input.dataset.categoryKey?.trim();
    const label = input.value.trim();
    if (!categoryKey) return;

    const prev = input.dataset.lastSaved ?? '';
    if (label === prev) return;

    if (!label) {
        showToast('German label cannot be empty', 'error');
        input.value = prev;
        return;
    }

    input.disabled = true;
    try {
        await apiPost('questionnaires.php', {
            action: 'updateCategoryLabel',
            categoryKey,
            germanLabel: label,
        });
        input.dataset.lastSaved = label;
        syncCategoryGermanInputs(categoryKey, label);
        showToast('Category label saved', 'success');
    } catch (err) {
        showToast(err.message, 'error');
        input.value = prev;
    } finally {
        input.disabled = false;
    }
}

function syncCategoryGermanInputs(categoryKey, label) {
    document.querySelectorAll('.category-german-input').forEach(el => {
        if (el.dataset.categoryKey === categoryKey) {
            el.value = label;
            el.dataset.lastSaved = label;
        }
    });
}

const UNCATEGORIZED = '__uncategorized__';

function groupQuestionnairesByCategory(questionnaires, categoryKeys) {
    const labelByKey = Object.fromEntries(
        (categoryKeys || [])
            .filter(r => !r.orphaned)
            .map(r => [r.categoryKey, r.germanLabel || r.categoryKey])
    );

    const sorted = [...questionnaires].sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0));
    const buckets = new Map();

    for (const q of sorted) {
        const key = (q.categoryKey || '').trim() || UNCATEGORIZED;
        if (!buckets.has(key)) buckets.set(key, []);
        buckets.get(key).push(q);
    }

    const sections = [...buckets.entries()].map(([key, items]) => ({
        categoryKey: key === UNCATEGORIZED ? '' : key,
        title: key === UNCATEGORIZED ? 'Uncategorized' : (labelByKey[key] || key),
        items,
        sortKey: Math.min(...items.map(q => q.orderIndex ?? 0)),
    }));

    sections.sort((a, b) => {
        const aUncat = a.categoryKey === '';
        const bUncat = b.categoryKey === '';
        if (aUncat !== bUncat) {
            return aUncat ? 1 : -1;
        }
        return a.sortKey - b.sortKey;
    });
    return sections;
}

function renderQuestionnaireCard(q) {
    const stateClass = `badge-${(q.state || 'draft').toLowerCase().replace(/\s+/g, '_')}`;
    return `
        <div class="q-card" data-id="${q.questionnaireID}" draggable="${canEdit()}">
            <div class="q-card-header">
                <div class="q-card-title">
                    ${canEdit() ? '<span class="drag-handle" title="Drag to reorder" aria-label="Drag to reorder">&#x2630;</span>' : ''}
                    ${esc(q.name)}
                </div>
                <span class="badge ${stateClass}">${esc(q.state || 'draft')}</span>
            </div>
            <div class="q-card-meta">
                <span>v${esc(q.version || '—')}</span>
                <span>${q.questionCount || 0} question${q.questionCount == 1 ? '' : 's'}</span>
                <span>#${q.orderIndex ?? '—'}</span>
            </div>
            <div class="q-card-actions">
                <a href="#/questionnaire/${q.questionnaireID}" class="btn btn-sm">Edit</a>
                <a href="#/questionnaire/${q.questionnaireID}/results" class="btn btn-sm">Results</a>
                ${getRole() === 'admin' ? `<button class="btn btn-sm btn-danger delete-q-btn" data-id="${q.questionnaireID}">Delete</button>` : ''}
            </div>
        </div>`;
}

function renderGrid(questionnaires, categoryKeys = []) {
    const grid = document.getElementById('qGrid');

    if (!questionnaires.length) {
        grid.innerHTML = `
            <div class="empty-state">
                <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9 12h6m-3-3v6m-7 4h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>
                <h3>No questionnaires yet</h3>
                <p>Create your first questionnaire to get started.</p>
            </div>
        `;
        return;
    }

    const sections = groupQuestionnairesByCategory(questionnaires, categoryKeys);

    grid.innerHTML = `
        <div class="q-dashboard-groups">
            ${sections.map(section => `
                <section class="q-category-group" data-category="${esc(section.categoryKey)}">
                    <h2 class="q-category-title">${categoryGermanInputHTML(section.categoryKey, section.title)}</h2>
                    <div class="q-category-grid">
                        ${section.items.map(q => renderQuestionnaireCard(q)).join('')}
                    </div>
                </section>
            `).join('')}
        </div>`;

    grid.querySelectorAll('.q-card').forEach(card => {
        card.addEventListener('click', (e) => {
            if (e.target.closest('.q-card-actions') || e.target.closest('.drag-handle')) return;
            navigate(`#/questionnaire/${card.dataset.id}`);
        });
    });

    grid.querySelectorAll('.delete-q-btn').forEach(btn => {
        btn.addEventListener('click', async (e) => {
            e.stopPropagation();
            if (!(await confirmAction({
                title: 'Delete questionnaire',
                message: 'Delete this questionnaire and all its data?',
                confirmLabel: 'Delete',
                variant: 'danger',
            }))) return;
            try {
                await apiDelete('questionnaires.php', { questionnaireID: btn.dataset.id });
                showToast('Questionnaire deleted', 'success');
                btn.closest('.q-card').remove();
            } catch (err) {
                showToast(err.message, 'error');
            }
        });
    });

    if (canEdit()) initGridDrag(questionnaires);
}

function collectDashboardCardOrder() {
    const ids = [];
    document.querySelectorAll('.q-category-group').forEach(section => {
        section.querySelectorAll('.q-category-grid .q-card').forEach(card => {
            ids.push(card.dataset.id);
        });
    });
    return ids;
}

function initGridDrag(questionnaires) {
    const root = document.getElementById('qGrid');
    if (!root) return;
    let dragItem = null;
    let dragRow = null;

    root.addEventListener('dragstart', (e) => {
        const card = e.target.closest('.q-card');
        if (!card || !e.target.closest('.drag-handle')) { e.preventDefault(); return; }
        dragItem = card;
        dragRow = card.closest('.q-category-grid');
        card.style.opacity = '0.5';
        e.dataTransfer.effectAllowed = 'move';
    });

    root.addEventListener('dragover', (e) => {
        e.preventDefault();
        if (!dragItem || !dragRow) return;

        const row = e.target.closest('.q-category-grid');
        if (!row || row !== dragRow) return;

        const cards = [...row.querySelectorAll('.q-card')].filter(c => c !== dragItem);
        let insertBefore = null;
        for (const child of cards) {
            const box = child.getBoundingClientRect();
            if (e.clientX < box.left + box.width / 2) {
                insertBefore = child;
                break;
            }
        }
        if (insertBefore) row.insertBefore(dragItem, insertBefore);
        else row.appendChild(dragItem);
    });

    root.addEventListener('dragend', async () => {
        if (!dragItem) return;
        dragItem.style.opacity = '';
        const newOrder = collectDashboardCardOrder();
        dragItem = null;
        dragRow = null;

        for (let i = 0; i < newOrder.length; i++) {
            const id = newOrder[i];
            const q = questionnaires.find(x => x.questionnaireID === id);
            if (q && parseInt(q.orderIndex, 10) !== i) {
                try {
                    await apiPut('questionnaires.php', { questionnaireID: id, orderIndex: i });
                    q.orderIndex = i;
                } catch (err) {
                    showToast(err.message, 'error');
                    return;
                }
            }
        }
        showToast('Order saved', 'success');
    });
}

function normalizeProfileBands(profile) {
    const greenMax = profile?.greenMax ?? 12;
    const yellowMax = profile?.yellowMax ?? 36;
    return {
        greenMin: profile?.greenMin ?? 0,
        greenMax,
        yellowMin: profile?.yellowMin ?? (greenMax + 1),
        yellowMax,
        redMin: profile?.redMin ?? (yellowMax + 1),
    };
}

function bandSummary(profile) {
    const b = normalizeProfileBands(profile || {});
    return `Green ${b.greenMin}–${b.greenMax} · Yellow ${b.yellowMin}–${b.yellowMax} · Red ${b.redMin}+`;
}

function readBandsFromModal(overlay) {
    return {
        greenMin: parseInt(overlay.querySelector('#spGreenMin')?.value || '0', 10),
        greenMax: parseInt(overlay.querySelector('#spGreenMax')?.value || '0', 10),
        yellowMin: parseInt(overlay.querySelector('#spYellowMin')?.value || '0', 10),
        yellowMax: parseInt(overlay.querySelector('#spYellowMax')?.value || '0', 10),
        redMin: parseInt(overlay.querySelector('#spRedMin')?.value || '0', 10),
    };
}

function validateBands(b) {
    if (b.greenMin > b.greenMax) return 'Green min must not exceed green max';
    if (b.yellowMin > b.yellowMax) return 'Yellow min must not exceed yellow max';
    if (b.greenMax >= b.yellowMin) return 'Green range must end before yellow range starts';
    if (b.yellowMax >= b.redMin) return 'Yellow range must end before red range starts';
    return null;
}

function bandPreviewHTML(b) {
    return `
        <div class="scoring-band-strips">
            <span class="band-badge band-green">Green: ${b.greenMin} – ${b.greenMax}</span>
            <span class="band-badge band-yellow">Yellow: ${b.yellowMin} – ${b.yellowMax}</span>
            <span class="band-badge band-red">Red: ${b.redMin}+</span>
        </div>`;
}

function bandRangesEditorHTML(bands) {
    const b = normalizeProfileBands(bands);
    return `
        <h4 class="scoring-modal-section-title">Score bands</h4>
        <p class="data-toolbar-hint" style="margin:0 0 10px">Set inclusive min/max for each band. Ranges must not overlap.</p>
        <div class="scoring-band-ranges-table">
            <div class="scoring-band-range-row scoring-band-range-header">
                <span>Band</span><span>Min</span><span>Max</span>
            </div>
            <div class="scoring-band-range-row">
                <span class="band-badge band-green">Green</span>
                <input type="number" id="spGreenMin" min="0" value="${b.greenMin}">
                <input type="number" id="spGreenMax" min="0" value="${b.greenMax}">
            </div>
            <div class="scoring-band-range-row">
                <span class="band-badge band-yellow">Yellow</span>
                <input type="number" id="spYellowMin" min="0" value="${b.yellowMin}">
                <input type="number" id="spYellowMax" min="0" value="${b.yellowMax}">
            </div>
            <div class="scoring-band-range-row">
                <span class="band-badge band-red">Red</span>
                <input type="number" id="spRedMin" min="0" value="${b.redMin}">
                <span class="scoring-band-max-placeholder">∞</span>
            </div>
        </div>
        <div id="spBandPreview" class="scoring-band-labels"></div>`;
}

const SCORING_BAND_OPTIONS = [
    { value: 'green', label: 'Green' },
    { value: 'yellow', label: 'Yellow' },
    { value: 'red', label: 'Red' },
];

function processCompleteBandsSummaryHTML(profile) {
    const bands = (profile?.processCompleteBands || [])
        .map(b => String(b).toLowerCase())
        .filter(Boolean);
    if (!bands.length) return '';
    const chips = bands.map(b => {
        const label = SCORING_BAND_OPTIONS.find(o => o.value === b)?.label || b;
        return `<span class="band-badge band-${esc(b)}">${esc(label)}</span>`;
    }).join('');
    return `
        <div class="scoring-profile-complete-bands">
            <span class="scoring-profile-complete-label">Process complete when coach sets</span>
            <span class="scoring-profile-complete-chips">${chips}</span>
        </div>`;
}

function processCompleteBandsEditorHTML(selected, editable) {
    const dis = editable ? '' : ' disabled';
    const sel = new Set((selected || []).map(b => String(b).toLowerCase()));
    return `
        <div class="scoring-process-complete-panel">
            <h4 class="scoring-modal-section-title">Process complete</h4>
            <p class="scoring-process-complete-hint">
                When the coach sets one of these categories during score review, the app shows the process-complete dialog for that client.
            </p>
            <div class="scoring-band-picker" id="spProcessCompleteBands">
                ${SCORING_BAND_OPTIONS.map(b => {
                    const checked = sel.has(b.value) ? ' checked' : '';
                    return `<label class="scoring-band-picker-item">
                        <input type="checkbox" value="${b.value}"${checked}${dis}>
                        <span class="band-badge band-${b.value}">${esc(b.label)}</span>
                    </label>`;
                }).join('')}
            </div>
        </div>`;
}

function readProcessCompleteBandsFromModal(overlay) {
    return [...(overlay.querySelectorAll('#spProcessCompleteBands input[type=checkbox]:checked') || [])]
        .map(cb => cb.value);
}

function renderScoringProfilesSection(profiles, questionnaires) {
    const panel = document.getElementById('scoringProfilesPanel');
    if (!panel) return;

    panel.innerHTML = `
        <div class="scoring-profiles-section">
            <div class="card scoring-profiles-card">
                <div class="scoring-profile-header">
                    <div>
                        <h3 class="scoring-section-title">Scoring profiles</h3>
                        <p class="scoring-section-desc">
                            Weighted multi-questionnaire scores with Green / Yellow / Red bands for insights.
                        </p>
                    </div>
                    ${canEdit() ? '<button type="button" class="btn btn-primary btn-sm" id="newScoringProfileBtn">+ New profile</button>' : ''}
                </div>
                <div id="scoringProfilesList" class="scoring-profiles-list"></div>
            </div>
        </div>`;

    const list = panel.querySelector('#scoringProfilesList');
    if (!profiles.length) {
        list.innerHTML = '<p class="scoring-empty-hint">No scoring profiles yet. Create one to combine questionnaire scores for insights.</p>';
    } else {
        list.innerHTML = profiles.map(p => scoringProfileCardHTML(p, questionnaires)).join('');
    }

    if (canEdit()) {
        panel.querySelector('#newScoringProfileBtn')?.addEventListener('click', () => {
            openScoringProfileModal(null, questionnaires, profiles);
        });
        list.querySelectorAll('.edit-profile-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const profile = profiles.find(x => x.profileID === btn.dataset.id);
                openScoringProfileModal(profile, questionnaires, profiles);
            });
        });
        list.querySelectorAll('.delete-profile-btn').forEach(btn => {
            btn.addEventListener('click', async () => {
                if (!(await confirmAction({
                    title: 'Delete scoring profile',
                    message: `Delete scoring profile "${btn.dataset.name}"?`,
                    confirmLabel: 'Delete',
                    variant: 'danger',
                }))) return;
                try {
                    await apiDelete('scoring_profiles.php', { profileID: btn.dataset.id });
                    showToast('Profile deleted', 'success');
                    await questionnairesPage();
                } catch (err) {
                    showToast(err.message, 'error');
                }
            });
        });
    }
}

function scoringProfileCardHTML(profile, questionnaires) {
    const qnById = Object.fromEntries((questionnaires || []).map(q => [q.questionnaireID, q]));
    const members = profile.questionnaires || [];
    const activeBadge = profile.isActive
        ? '<span class="badge badge-active">Active</span>'
        : '<span class="badge badge-draft">Inactive</span>';
    const memberRows = members.map(m => {
        const q = qnById[m.questionnaireID];
        const name = q?.name || m.questionnaireID;
        return `<div class="scoring-profile-q-row"><span class="scoring-profile-q-name">${esc(name)}</span><span class="scoring-profile-q-weight">× ${m.weight}</span></div>`;
    }).join('');

    return `
        <div class="scoring-profile-card">
            <div class="scoring-profile-card-top">
                <div class="scoring-profile-card-main">
                    <div class="scoring-profile-name-row">
                        <strong>${esc(profile.name)}</strong>
                        ${activeBadge}
                    </div>
                    ${profile.description ? `<p class="scoring-profile-desc">${esc(profile.description)}</p>` : ''}
                    <p class="scoring-profile-bands">${bandSummary(profile)}</p>
                    ${processCompleteBandsSummaryHTML(profile)}
                </div>
                ${canEdit() ? `
                    <div class="scoring-profile-card-actions">
                        <button type="button" class="btn btn-sm edit-profile-btn" data-id="${esc(profile.profileID)}">Edit</button>
                        <button type="button" class="btn btn-sm btn-danger delete-profile-btn"
                            data-id="${esc(profile.profileID)}" data-name="${esc(profile.name)}">Delete</button>
                    </div>` : ''}
            </div>
            <p class="scoring-profile-member-count">${members.length} questionnaire(s)</p>
            <div class="scoring-profile-members">${memberRows || '<p class="scoring-empty-hint">No questionnaires linked</p>'}</div>
        </div>`;
}

function openScoringProfileModal(profile, questionnaires, allProfiles) {
    const isEdit = !!profile;
    const members = profile?.questionnaires?.length
        ? [...profile.questionnaires]
        : [];
    const selectedIds = new Set(members.map(m => m.questionnaireID));
    const initialBands = normalizeProfileBands(profile || {});

    const overlay = document.createElement('div');
    overlay.className = 'modal-overlay';
    overlay.innerHTML = `
        <div class="modal-dialog modal-dialog-wide">
            <h2>${isEdit ? 'Edit scoring profile' : 'New scoring profile'}</h2>
            <p class="modal-subtitle">Combine questionnaire totals with weights, then map the sum to Green / Yellow / Red bands.</p>
            <div class="form-group">
                <label for="spName">Name</label>
                <input type="text" id="spName" value="${esc(profile?.name || '')}" placeholder="e.g. RHS Index">
            </div>
            <div class="form-group">
                <label for="spDesc">Description</label>
                <textarea id="spDesc" rows="2" placeholder="Optional note for Counselors and admins">${esc(profile?.description || '')}</textarea>
            </div>
            <div class="form-group scoring-profile-active-row">
                <label class="checkbox-inline">
                    <input type="checkbox" id="spActive" ${profile?.isActive !== 0 ? 'checked' : ''}>
                    Active (shown in insights)
                </label>
            </div>
            ${bandRangesEditorHTML(initialBands)}
            ${processCompleteBandsEditorHTML(profile?.processCompleteBands || [], canEdit())}
            <h4 class="scoring-modal-section-title">Questionnaires</h4>
            <p class="data-toolbar-hint" style="margin:0 0 10px">Add questionnaires and set weight. List order is the display order.</p>
            <div id="spQnPicker" class="scoring-profile-picker"></div>
            <div class="modal-actions">
                <button type="button" class="btn btn-sm" id="spCancel">Cancel</button>
                <button type="button" class="btn btn-primary btn-sm" id="spSave">${isEdit ? 'Save' : 'Create'}</button>
            </div>
        </div>`;
    document.body.appendChild(overlay);
    document.body.classList.add('modal-open');

    const picker = overlay.querySelector('#spQnPicker');
    const sortedQn = [...(questionnaires || [])].sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0));

    function renderPicker() {
        const ordered = members.length
            ? members.map(m => ({ ...m, q: sortedQn.find(q => q.questionnaireID === m.questionnaireID) }))
            : [];
        const available = sortedQn.filter(q => !selectedIds.has(q.questionnaireID));

        picker.innerHTML = `
            ${ordered.map((m, idx) => `
                <div class="scoring-profile-q-row" data-qn="${esc(m.questionnaireID)}">
                    <span class="scoring-profile-q-name">${esc(m.q?.name || m.questionnaireID)}</span>
                    <span class="scoring-profile-q-actions">
                        <label class="sp-weight-wrap">Weight
                            <input type="number" class="sp-weight" step="0.1" min="0.1"
                                value="${m.weight ?? 1}">
                        </label>
                        <button type="button" class="btn btn-sm sp-move-up" ${idx === 0 ? 'disabled' : ''} title="Move up">↑</button>
                        <button type="button" class="btn btn-sm sp-move-down" ${idx === ordered.length - 1 ? 'disabled' : ''} title="Move down">↓</button>
                        <button type="button" class="btn btn-sm btn-danger sp-remove" title="Remove">Remove</button>
                    </span>
                </div>
            `).join('')}
            ${available.length ? `
                <div class="scoring-profile-add-row">
                    <select id="spAddSelect">
                        <option value="">Add questionnaire…</option>
                        ${available.map(q => `<option value="${esc(q.questionnaireID)}">${esc(q.name)}</option>`).join('')}
                    </select>
                    <button type="button" class="btn btn-sm" id="spAddBtn">Add</button>
                </div>` : ''}`;

        picker.querySelectorAll('.sp-weight').forEach((input, idx) => {
            input.addEventListener('change', () => {
                members[idx].weight = parseFloat(input.value) || 1;
            });
        });
        picker.querySelectorAll('.sp-remove').forEach(btn => {
            btn.addEventListener('click', () => {
                const row = btn.closest('.scoring-profile-q-row');
                const id = row?.dataset.qn;
                if (!id) return;
                selectedIds.delete(id);
                const i = members.findIndex(m => m.questionnaireID === id);
                if (i >= 0) members.splice(i, 1);
                renderPicker();
            });
        });
        picker.querySelectorAll('.sp-move-up').forEach(btn => {
            btn.addEventListener('click', () => {
                const row = btn.closest('.scoring-profile-q-row');
                const id = row?.dataset.qn;
                const i = members.findIndex(m => m.questionnaireID === id);
                if (i > 0) {
                    [members[i - 1], members[i]] = [members[i], members[i - 1]];
                    renderPicker();
                }
            });
        });
        picker.querySelectorAll('.sp-move-down').forEach(btn => {
            btn.addEventListener('click', () => {
                const row = btn.closest('.scoring-profile-q-row');
                const id = row?.dataset.qn;
                const i = members.findIndex(m => m.questionnaireID === id);
                if (i >= 0 && i < members.length - 1) {
                    [members[i], members[i + 1]] = [members[i + 1], members[i]];
                    renderPicker();
                }
            });
        });
        overlay.querySelector('#spAddBtn')?.addEventListener('click', () => {
            const sel = overlay.querySelector('#spAddSelect');
            const id = sel?.value;
            if (!id || selectedIds.has(id)) return;
            selectedIds.add(id);
            members.push({ questionnaireID: id, weight: 1, orderIndex: members.length });
            renderPicker();
        });
    }

    function updateBandPreview() {
        const el = overlay.querySelector('#spBandPreview');
        if (!el) return;
        const b = readBandsFromModal(overlay);
        const err = validateBands(b);
        if (err) {
            el.innerHTML = `<p class="error-text" style="margin:0">${esc(err)}</p>`;
            return;
        }
        el.innerHTML = bandPreviewHTML(b);
    }

    renderPicker();
    updateBandPreview();
    ['#spGreenMin', '#spGreenMax', '#spYellowMin', '#spYellowMax', '#spRedMin'].forEach(sel => {
        overlay.querySelector(sel)?.addEventListener('input', updateBandPreview);
    });

    const close = () => {
        overlay.remove();
        document.body.classList.remove('modal-open');
    };
    overlay.querySelector('#spCancel')?.addEventListener('click', close);
    overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); });

    overlay.querySelector('#spSave')?.addEventListener('click', async () => {
        const name = overlay.querySelector('#spName')?.value.trim();
        const description = overlay.querySelector('#spDesc')?.value.trim() || '';
        const isActive = overlay.querySelector('#spActive')?.checked;
        const bands = readBandsFromModal(overlay);
        const bandErr = validateBands(bands);
        if (!name) {
            showToast('Profile name is required', 'error');
            return;
        }
        if (bandErr) {
            showToast(bandErr, 'error');
            return;
        }
        if (!members.length) {
            showToast('Add at least one questionnaire', 'error');
            return;
        }
        const payload = {
            name,
            description,
            isActive,
            ...bands,
            processCompleteBands: readProcessCompleteBandsFromModal(overlay),
            questionnaires: members.map((m, idx) => ({
                questionnaireID: m.questionnaireID,
                weight: parseFloat(picker.querySelector(`[data-qn="${m.questionnaireID}"] .sp-weight`)?.value) || m.weight || 1,
                orderIndex: idx,
            })),
        };
        if (isEdit) payload.profileID = profile.profileID;

        const saveBtn = overlay.querySelector('#spSave');
        saveBtn.disabled = true;
        try {
            if (isEdit) {
                await apiPut('scoring_profiles.php', payload);
            } else {
                await apiPost('scoring_profiles.php', payload);
            }
            showToast(isEdit ? 'Profile saved' : 'Profile created', 'success');
            close();
            await questionnairesPage();
        } catch (err) {
            showToast(err.message, 'error');
            saveBtn.disabled = false;
        }
    });
}

function bindImportBundle() {
    const fileInput = document.getElementById('importBundleFile');
    const btn = document.getElementById('importBundleBtn');
    if (!fileInput || !btn) return;

    btn.addEventListener('click', () => fileInput.click());

    fileInput.addEventListener('change', async () => {
        const file = fileInput.files?.[0];
        fileInput.value = '';
        if (!file) return;

        let bundle;
        try {
            const text = await file.text();
            bundle = JSON.parse(text);
        } catch {
            showToast('Invalid JSON file', 'error');
            return;
        }

        if (!bundle?.questionnaires || !Array.isArray(bundle.questionnaires)) {
            showToast('Not a questionnaire bundle (missing questionnaires array)', 'error');
            return;
        }

        const count = bundle.questionnaires.length;
        if (!(await confirmAction({
            title: 'Import questionnaires',
            message: `Import ${count} questionnaire(s) from this file?`,
            confirmLabel: 'Import',
        }))) return;

        const mode = await confirmAction({
            title: 'Existing questionnaire IDs',
            message: 'If a questionnaire ID from the file already exists, how should it be handled?',
            choices: [
                {
                    value: 'replace',
                    label: 'Replace existing',
                    description: 'Overwrite the questionnaire with that ID.',
                },
                {
                    value: 'copy',
                    label: 'Import as new copy',
                    description: 'Keep the existing questionnaire and import with a new ID.',
                },
            ],
            confirmLabel: 'Continue',
            cancelLabel: 'Cancel import',
        });
        if (!mode) return;
        const replace = mode === 'replace';

        btn.disabled = true;
        const prev = btn.textContent;
        btn.textContent = 'Importing…';
        try {
            const result = await apiPost('questionnaires.php', {
                action: 'importBundle',
                bundle,
                replaceIfExists: replace,
            });
            const n = result.imported ?? count;
            showToast(`Imported ${n} questionnaire(s)`, 'success');
            await questionnairesPage();
        } catch (e) {
            showToast(e.message, 'error');
        } finally {
            btn.disabled = false;
            btn.textContent = prev;
        }
    });
}

function esc(s) {
    const d = document.createElement('div');
    d.textContent = s ?? '';
    return d.innerHTML;
}
