// ── UI Rendering and Configuration Loading ───────────────────────────
async function loadTableConfig(tableName) {
    // Persist any pending edits for the table we're leaving before switching.
    if (typeof flushPendingSaves === 'function') flushPendingSaves();

    currentTableName = tableName;
    document.getElementById('selectedTableLabel').textContent = tableName;

    // Prefer the freshest in-memory state (kept in sync with every save),
    // then the injected snapshot, then the server.
    let cfg = (allPagesStates && allPagesStates[tableName]) || (pagesConfig && pagesConfig[tableName]) || null;

    if (!cfg) {
        try {
            const res = await fetch(`${baseUrl}/project/${projectSlug}/pages/load/${tableName}`);
            const data = await res.json();
            cfg = (data.success && data.config) ? data.config : { ...defaultConfig };
        } catch (err) {
            cfg = { ...defaultConfig };
        }
    }

    currentConfig = cfg;
    currentKeyColumns = (cfg.keyColumns || []).slice();
    if (currentKeyColumns.length === 0) await autoDetectPrimaryKey(tableName);
    if (typeof syncCaches === 'function') syncCaches(tableName, currentConfig);
    renderConfig();
}

const pageTypeMeta = {
    list:   { label: 'List',   icon: 'list-ul',          color: 'blue',   description: 'Browse and manage records' },
    add:    { label: 'Add',    icon: 'plus-circle',      color: 'green',  description: 'Create new records' },
    edit:   { label: 'Edit',   icon: 'pencil-square',   color: 'violet', description: 'Update existing records' },
    view:   { label: 'View',   icon: 'eye',              color: 'cyan',   description: 'Read a complete record' },
    print:  { label: 'Print',  icon: 'printer',          color: 'slate',  description: 'Printer-ready layout' },
    export: { label: 'Export', icon: 'box-arrow-down',  color: 'amber',  description: 'Download record data' },
    import: { label: 'Import', icon: 'box-arrow-up',    color: 'orange', description: 'Upload record data' },
    pdf:    { label: 'PDF',    icon: 'file-earmark-pdf', color: 'red',    description: 'Generate PDF output' },
    cards:  { label: 'Cards',  icon: 'grid-3x3-gap',     color: 'pink',   description: 'Visual card-based results' }
    // NOTE: 'calendar' is intentionally NOT a per-table page-type. The Calendar is a
    // single dedicated app (the `calendar` Common page / calendar-app), like the Admin
    // Area — it is not generated per table. The build even deletes any stray per-table
    // generated/<table>/calendar.php (BuildWriter ~2281), and availablePageTypes() omits
    // it from $valid, so offering it here only produced an orphaned, build-less checkbox.
};

const functionalityMeta = {
    spreadsheet:    { label: 'Spreadsheet mode', icon: 'grid-3x3', description: 'Edit records in a spreadsheet-style grid' },
    updateSelected: { label: 'Update selected',  icon: 'check2-square', description: 'Apply changes to multiple selected records' },
    inlineEdit:     { label: 'Inline edit',      icon: 'pencil', description: 'Edit a record directly on its list row' },
    inlineAdd:      { label: 'Inline add',       icon: 'node-plus', description: 'Add a record without leaving the list' },
    deleteRecords:  { label: 'Delete records',  icon: 'trash3', description: 'Allow authorized users to remove records' },
    copyRecords:    { label: 'Copy records',     icon: 'copy', description: 'Duplicate an existing record as a starting point' }
};

function escapePageHtml(value) {
    return String(value ?? '').replace(/[&<>'"]/g, char => ({
        '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#039;', '"': '&quot;'
    })[char]);
}

/**
 * Enhance existing title attributes without changing data-bs-toggle. Several
 * page buttons already use Bootstrap data attributes for behaviour, so the
 * tooltip layer is intentionally initialized through JavaScript only.
 */
function initializePageTooltips(root = document) {
    if (!window.bootstrap?.Tooltip) return;
    root.querySelectorAll('[title]').forEach(element => {
        bootstrap.Tooltip.getInstance(element)?.dispose();
        new bootstrap.Tooltip(element, {
            container: document.body,
            trigger: 'hover focus',
            customClass: 'pages-tooltip',
            delay: { show: 260, hide: 60 }
        });
    });
}

function syncPageSelectionPresentation(container) {
    container.querySelectorAll('.page-type-option').forEach(option => {
        const input = option.querySelector('.page-type-check');
        option.classList.toggle('is-selected', Boolean(input?.checked));
    });
    container.querySelectorAll('.function-option').forEach(option => {
        const input = option.querySelector('.func-check');
        option.classList.toggle('is-selected', Boolean(input?.checked));
    });
    const count = container.querySelectorAll('.page-type-check:checked').length;
    const badge = container.querySelector('#selectedPageTypeCount');
    if (badge) badge.textContent = `${count} selected`;
}

function renderConfig() {
    const container = document.getElementById('pageConfigContainer');
    const cfg = currentConfig || defaultConfig;
    const hasKey = currentKeyColumns.length > 0;

    // Key-dependent page types render unchecked while no key column is selected.
    const needsKeyTypes = ['edit', 'view', 'print', 'export', 'import'];
    const rawTypes = cfg.pageTypes || ['list'];
    const effectiveTypes = hasKey ? rawTypes.slice() : rawTypes.filter(t => !needsKeyTypes.includes(t));

    let html = '';

    // Pages to Build
    html += `<section class="section-card page-types-card" aria-labelledby="pageTypesHeading">
        <div class="section-heading">
            <span class="section-heading-icon is-blue"><i class="bi bi-window-stack"></i></span>
            <span class="section-heading-copy"><strong id="pageTypesHeading">Pages to build</strong><small>Choose the experiences generated for this table</small></span>
            <span class="section-count" id="selectedPageTypeCount">${effectiveTypes.length} selected</span>
        </div>`;
    if (!hasKey) html += `<div class="pages-key-notice" role="status"><i class="bi bi-key"></i><span><strong>Key column required.</strong> Select a key to unlock record-specific pages.</span><button type="button" class="page-settings-btn" id="keyColumnsNoticeBtn" title="Choose the columns that uniquely identify each record">Choose key</button></div>`;
    html += '<div class="page-type-grid">';
    Object.entries(pageTypeMeta).forEach(([type, meta]) => {
        const checked = effectiveTypes.includes(type) ? 'checked' : '';
        const needsKey = needsKeyTypes.includes(type);
        const disabled = needsKey && !hasKey ? 'disabled' : '';
        const inputId = `pageType_${type}`;
        html += `<div class="page-type-option page-color-${meta.color} ${disabled ? 'is-disabled' : ''}">
            <input class="page-type-check" id="${inputId}" type="checkbox" value="${type}" ${checked} ${disabled}>
            <label for="${inputId}" title="${escapePageHtml(meta.description)}">
                <span class="page-type-icon"><i class="bi bi-${meta.icon}"></i></span>
                <span class="page-type-copy"><strong>${meta.label}</strong><small>${meta.description}</small></span>
                <span class="page-type-state"><i class="bi bi-check-lg"></i></span>
            </label>`;
        if (['list', 'add', 'edit', 'view', 'pdf', 'cards', 'export', 'import'].includes(type)) {
            html += `<button type="button" class="page-settings-btn page-type-settings" data-page="${type}" title="Configure ${meta.label} page" aria-label="Configure ${meta.label} page" ${disabled}><i class="bi bi-sliders"></i></button>`;
        }
        html += `</div>`;
    });
    html += '</div></section>';

    // Key Columns
    const keySummary = currentKeyColumns.length
        ? currentKeyColumns.map(key => `<span class="key-column-chip"><i class="bi bi-key-fill"></i>${escapePageHtml(key)}</span>`).join('')
        : '<span class="key-column-empty">No key columns selected</span>';
    html += `<section class="section-card key-columns-card" aria-labelledby="keyColumnsHeading">
        <div class="section-heading compact">
            <span class="section-heading-icon is-amber"><i class="bi bi-key"></i></span>
            <span class="section-heading-copy"><strong id="keyColumnsHeading">Record identity</strong><small>Keys uniquely identify records for view, edit, and export operations</small></span>
            <button type="button" class="page-settings-btn section-action" id="keyColumnsBtn" title="Select key columns"><i class="bi bi-sliders"></i><span>Configure</span></button>
        </div>
        <div class="key-columns-summary">${keySummary}</div>
    </section>`;

    // Functionality
    html += `<section class="section-card functionality-card" aria-labelledby="functionalityHeading">
        <div class="section-heading">
            <span class="section-heading-icon is-violet"><i class="bi bi-lightning-charge"></i></span>
            <span class="section-heading-copy"><strong id="functionalityHeading">List-page capabilities</strong><small>Add efficient record workflows to the generated list page</small></span>
        </div><div class="functionality-grid">`;
    const func = cfg.functionality || defaultConfig.functionality;
    for (const [key, value] of Object.entries(func)) {
        // Ignore any legacy/removed capability key (e.g. the old `pdfView`) that
        // might still linger in an older saved config — only known ones render.
        const meta = functionalityMeta[key];
        if (!meta) continue;
        const checked = value ? 'checked' : '';
        const inputId = `functionality_${key}`;
        html += `<div class="function-option">
            <input class="func-check" id="${inputId}" type="checkbox" data-key="${escapePageHtml(key)}" ${checked}>
            <label for="${inputId}" title="${escapePageHtml(meta.description)}">
                <span class="function-icon"><i class="bi bi-${meta.icon}"></i></span>
                <span class="function-copy"><strong>${escapePageHtml(meta.label)}</strong><small>${escapePageHtml(meta.description)}</small></span>
                <span class="function-switch" aria-hidden="true"><span></span></span>
            </label>
        </div>`;
    }
    html += '</div></section>';

    // Dispose tooltips bound to the outgoing DOM so their body-appended tip nodes
    // and instances don't leak across repeated table switches.
    if (window.bootstrap?.Tooltip) {
        container.querySelectorAll('[data-bs-original-title], [title]').forEach(el => bootstrap.Tooltip.getInstance(el)?.dispose());
    }
    container.innerHTML = html;

    // Attach event listeners with auto‑save
    container.querySelectorAll('.page-type-check, .func-check').forEach(cb => {
        cb.addEventListener('change', () => {
            syncPageSelectionPresentation(container);
            autoSaveCurrentPageState();
        });
    });
    container.querySelectorAll('.page-settings-btn').forEach(btn => {
        if (btn.dataset.page) btn.addEventListener('click', () => openPageSettingsModal(btn.dataset.page));
    });
    document.getElementById('keyColumnsBtn')?.addEventListener('click', openKeyColumnsModal);
    document.getElementById('keyColumnsNoticeBtn')?.addEventListener('click', openKeyColumnsModal);
    syncPageSelectionPresentation(container);
    initializePageTooltips(container);

    // If key columns are missing, key-dependent types were rendered unchecked;
    // persist that correction once (no recursion, no stale DOM read).
    if (effectiveTypes.length !== rawTypes.length) {
        if (currentConfig) currentConfig.pageTypes = effectiveTypes;
        autoSaveCurrentPageState();
    }
}

function fillKeyColumnsBody(columns) {
    const body = document.getElementById('keyColumnsBody');
    let html = '';
    columns.forEach(col => {
        const checked = currentKeyColumns.includes(col.COLUMN_NAME) ? 'checked' : '';
        const name = escapePageHtml(col.COLUMN_NAME);
        const ctype = escapePageHtml(col.COLUMN_TYPE);
        html += `<div class="form-check small">
            <input class="form-check-input key-col-check" type="checkbox" value="${name}" id="kc_${name}" ${checked}>
            <label class="form-check-label" for="kc_${name}">${name} <span class="text-muted">(${ctype})</span></label>
        </div>`;
    });
    body.innerHTML = html;
}

function renderClickActionsTable() {
    const container = document.getElementById('clickActionsTableContainer');
    if (!container) return;
    if (clickActions.length === 0) {
        container.innerHTML = '<div class="text-muted small py-2">No click actions defined.</div>';
        return;
    }
    const typeLabels = { openPage: 'Open Page', openUrl: 'Open URL', selectRecord: 'Select', expandDetails: 'Expand', executeCode: 'Run Code' };
    let html = '<table class="table table-sm table-bordered small mb-0"><thead><tr><th>Field</th><th>Action</th><th>Trigger</th><th>Detail</th><th></th></tr></thead><tbody>';
    clickActions.forEach((ca, idx) => {
        // Detail column: the target page, the URL template, or a — placeholder.
        let detail = '—';
        if (ca.actionType === 'openPage') detail = escapePageHtml(ca.target || 'view');
        else if (ca.actionType === 'openUrl') detail = '<code>' + escapePageHtml((ca.url || '').slice(0, 40)) + '</code>';
        else if (ca.actionType === 'executeCode') detail = ca.server ? 'client + server' : 'client only';
        // Little chips for the cross-cutting modifiers.
        let chips = '';
        if (ca.confirm) chips += ' <span class="badge bg-warning-subtle text-warning-emphasis" title="Confirms: ' + escapePageHtml(ca.confirm) + '"><i class="bi bi-shield-exclamation"></i></span>';
        if (ca.onlyWhen) chips += ' <span class="badge bg-info-subtle text-info-emphasis" title="Only when: ' + escapePageHtml(ca.onlyWhen) + '"><i class="bi bi-funnel"></i></span>';
        const trig = (ca.on === 'double') ? '<i class="bi bi-mouse2" title="Double click"></i> ×2' : '<i class="bi bi-mouse" title="Single click"></i>';
        html += `<tr>
            <td>${escapePageHtml(ca.field)}</td>
            <td>${escapePageHtml(typeLabels[ca.actionType] || ca.actionType)}${chips}</td>
            <td>${trig}</td>
            <td>${detail}</td>
            <td>
                <button class="btn btn-sm btn-outline-secondary edit-click-btn" data-index="${idx}" title="Edit this click action"><i class="bi bi-pencil"></i></button>
                <button class="btn btn-sm btn-outline-danger delete-click-btn" data-index="${idx}" title="Delete this click action"><i class="bi bi-trash"></i></button>
            </td>
        </tr>`;
    });
    html += '</tbody></table>';
    container.innerHTML = html;

    container.querySelectorAll('.edit-click-btn').forEach(btn => {
        btn.addEventListener('click', () => openClickActionModal(parseInt(btn.dataset.index)));
    });
    container.querySelectorAll('.delete-click-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            const idx = parseInt(btn.dataset.index);
            clickActions.splice(idx, 1);
            renderClickActionsTable();
            autoSaveCurrentPageState();  // auto‑save after deletion
        });
    });
    initializePageTooltips(container);
}

window.loadTableConfig = loadTableConfig;
window.renderConfig = renderConfig;
window.fillKeyColumnsBody = fillKeyColumnsBody;
window.renderClickActionsTable = renderClickActionsTable;
window.initializePageTooltips = initializePageTooltips;
