{% extends "base.html" %}
{% block head %}
<style>
#builder-layout{display:grid;grid-template-columns:220px 1fr 300px;gap:12px;height:calc(100vh - 200px);min-height:500px}
#builder-toolbox{overflow-y:auto;padding:8px}
#builder-canvas{overflow-y:auto;padding:16px;background:#f4f5f7;border-radius:8px;border:2px dashed #bbb;position:relative}
#builder-props{overflow-y:auto;padding:8px}
.toolbox-item{padding:8px 10px;margin-bottom:4px;border:1px solid #ddd;border-radius:6px;cursor:grab;background:#fff;font-size:0.9rem;transition:all 0.15s}
.toolbox-item:hover{border-color:#2F5496;background:#eef3fb}
.toolbox-item:active{cursor:grabbing}
.canvas-placeholder{color:#aaa;text-align:center;padding:40px 20px;pointer-events:none}

/* ── Form Preview (WYSIWYG Canvas) ── */
#form-preview{max-width:900px;margin:0 auto;min-height:200px}
#form-preview .group-box{position:relative;border:2px solid #e8f0fe;transition:border-color 0.2s}
#form-preview .group-box.selected{border-color:#2F5496;box-shadow:0 0 0 2px rgba(47,84,150,0.12)}
#form-preview .group-box .group-edit-overlay{position:absolute;top:2px;right:2px;display:none;gap:3px;z-index:10}
#form-preview .group-box:hover .group-edit-overlay{display:flex}
#form-preview .group-box .group-edit-overlay button{background:#fff;border:1px solid #ccc;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:11px;height:22px;transition:all 0.1s}
#form-preview .group-box .group-edit-overlay button:hover{background:#f0f0f0;border-color:#2F5496}

/* Field wrappers in the form */
#form-preview .field-col{position:relative;transition:all 0.2s;border-radius:4px;padding:6px}
#form-preview .field-col::before{content:'';position:absolute;inset:2px;border:2px solid transparent;border-radius:4px;pointer-events:none;transition:border-color 0.15s}
#form-preview .field-col.selected::before{border-color:#2F5496;box-shadow:0 0 0 2px rgba(47,84,150,0.1)}
#form-preview .field-col:hover::before{border-color:#d0d0d0}
#form-preview .field-col.selected:hover::before{border-color:#2F5496}
#form-preview .field-col .field{pointer-events:none;margin-bottom:0}
#form-preview .field-col .field .control{pointer-events:auto}
#form-preview .field-col .field input,#form-preview .field-col .field select,#form-preview .field-col .field textarea{pointer-events:auto}

/* Edit overlay on each field */
.field-edit-overlay{position:absolute;top:0;right:0;display:none;gap:2px;z-index:20;background:rgba(255,255,255,0.95);border:1px solid #ddd;border-radius:0 4px 0 4px;padding:1px 3px;box-shadow:0 1px 4px rgba(0,0,0,0.08)}
#form-preview .field-col:hover .field-edit-overlay,.field-col.selected .field-edit-overlay{display:flex}
.field-edit-overlay .field-name-tag{font-size:9px;color:#999;padding:2px 4px;font-family:monospace;line-height:18px}
.field-edit-overlay .btn-edit{background:transparent;border:none;cursor:pointer;padding:1px 4px;font-size:12px;line-height:18px;border-radius:3px;opacity:0.6;transition:all 0.1s}
.field-edit-overlay .btn-edit:hover{background:#eef3fb;opacity:1}
.field-edit-overlay .btn-edit.danger:hover{background:#fdecea;color:#c0392b}

/* Drag handle on fields */
.field-drag-handle{position:absolute;top:50%;left:-2px;transform:translateY(-50%);width:10px;height:30px;cursor:grab;z-index:15;opacity:0;display:flex;align-items:center;justify-content:center;transition:opacity 0.15s;border-radius:0 3px 3px 0}
.field-drag-handle::after{content:'⠿';font-size:12px;color:#bbb;line-height:1}
#form-preview .field-col:hover .field-drag-handle,.field-col.selected .field-drag-handle{opacity:1}
.field-drag-handle:hover::after{color:#2F5496}

/* Resize handle on columns */
.form-resize-handle{position:absolute;top:8px;bottom:8px;right:-3px;width:8px;cursor:col-resize;z-index:15;opacity:0;transition:opacity 0.15s;border-radius:0 4px 4px 0}
.form-resize-handle::before{content:'⋮';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:13px;color:#bbb;line-height:1}
#form-preview .field-col:hover .form-resize-handle{opacity:1}
.form-resize-handle:hover::before,.form-resize-handle.active::before{color:#2F5496}
.form-resize-handle:hover{background:rgba(47,84,150,0.06)}
.form-resize-handle.active{opacity:1;background:rgba(47,84,150,0.1)}

/* Column badges */
.form-col-badge{position:absolute;bottom:2px;right:8px;font-size:9px;color:#bbb;background:#f5f5f5;border-radius:3px;padding:0 6px;line-height:16px;letter-spacing:0.3px;z-index:3;opacity:0;transition:opacity 0.15s}
#form-preview .field-col:hover .form-col-badge,.field-col.selected .form-col-badge{opacity:1}
.form-col-badge:hover{color:#2F5496;background:#eef3fb}

/* Snap line during resize */
.resize-snap-line{position:fixed;top:0;bottom:0;width:2px;background:rgba(47,84,150,0.5);z-index:1000;pointer-events:none;display:none}
.resize-snap-line.show{display:block}

/* Structural elements (separator, label, group) */
#form-preview .structural-placeholder{position:relative;padding:4px 8px;margin:2px 0;border:2px dashed transparent;border-radius:4px;transition:all 0.15s;cursor:pointer}
#form-preview .structural-placeholder:hover{border-color:#d0d0d0;background:#fafafa}
#form-preview .structural-placeholder.selected{border-color:#2F5496;background:#f0f4ff}
#form-preview .structural-placeholder .struct-tools{position:absolute;top:2px;right:2px;display:none;gap:2px}
#form-preview .structural-placeholder:hover .struct-tools{display:flex}
#form-preview .structural-placeholder .struct-tools button{background:#fff;border:1px solid #ccc;border-radius:3px;cursor:pointer;padding:1px 5px;font-size:10px}
#form-preview .structural-placeholder .struct-tools button:hover{background:#f0f0f0}

/* Props panel */
.prop-group{margin-bottom:12px}
.prop-group label{display:block;font-size:0.8rem;font-weight:600;color:#555;margin-bottom:2px}
.prop-group input,.prop-group select,.prop-group textarea{width:100%;padding:5px 8px;border:1px solid #ddd;border-radius:4px;font-size:0.85rem}
.prop-group textarea{resize:vertical;min-height:50px}
#na-save-status{font-size:0.85rem;margin-left:12px}

/* Drop indicator */
.drop-indicator{height:3px;background:#2F5496;border-radius:2px;margin:2px 0;transition:all 0.1s;position:relative}
.drop-indicator::after{content:'';position:absolute;left:50%;top:-4px;width:8px;height:8px;background:#2F5496;border-radius:50%;transform:translateX(-50%)}

/* Inline editing */
.inline-edit-input{font-size:inherit;font-family:inherit;padding:2px 6px;border:2px solid #2F5496;border-radius:4px;background:#fff;min-width:120px;outline:none;box-shadow:0 2px 8px rgba(47,84,150,0.15)}
.inline-edit-input:focus{box-shadow:0 2px 12px rgba(47,84,150,0.25)}

/* Quick action toolbar on hover */
.field-quick-actions{position:absolute;bottom:-28px;left:50%;transform:translateX(-50%);display:none;gap:2px;z-index:30;background:rgba(255,255,255,0.98);border:1px solid #ddd;border-radius:6px;padding:2px 4px;box-shadow:0 2px 8px rgba(0,0,0,0.1);white-space:nowrap}
.field-col:hover .field-quick-actions,.field-col.selected .field-quick-actions{display:flex}
.field-quick-actions button{background:transparent;border:none;cursor:pointer;padding:3px 6px;font-size:11px;border-radius:4px;transition:all 0.1s;color:#555}
.field-quick-actions button:hover{background:#eef3fb;color:#2F5496}
.field-quick-actions button.danger:hover{background:#fdecea;color:#c0392b}

/* Label on canvas is clickable for inline edit */
#form-preview .field-col .field .label{pointer-events:auto;cursor:text;transition:background 0.1s;border-radius:3px;padding:1px 3px;margin:-1px}
#form-preview .field-col .field .label:hover{background:#f0f4ff}
#form-preview .field-col .field .label.editing{background:#fff;padding:0}

/* Rule Builder (unchanged) */
#rule-layout{display:grid;grid-template-columns:280px 1fr;gap:12px;height:calc(100vh - 200px);min-height:500px}
#rule-list{overflow-y:auto;padding:8px}
#rule-editor{overflow-y:auto;padding:12px}
.rule-card{padding:10px 12px;margin-bottom:6px;border:1px solid #ddd;border-radius:6px;cursor:pointer;background:#fff;transition:all 0.15s;position:relative}
.rule-card:hover{border-color:#2F5496}
.rule-card.selected{border-color:#2F5496;background:#eef3fb}
.rule-card .rule-name{font-weight:600;font-size:0.9rem}
.rule-card .rule-summary{font-size:0.8rem;color:#888;margin-top:2px}
.rule-card .rule-tools{position:absolute;top:6px;right:6px;display:none;gap:3px}
.rule-card:hover .rule-tools{display:flex}
.rule-card .rule-tools button{background:#fff;border:1px solid #ddd;border-radius:3px;cursor:pointer;padding:1px 5px;font-size:11px}
.rule-card .rule-tools button:hover{background:#f0f0f0}
.cond-row{display:flex;gap:6px;margin-bottom:6px;align-items:center;flex-wrap:wrap}
.cond-row select,.cond-row input{padding:4px 6px;border:1px solid #ddd;border-radius:4px;font-size:0.85rem}
.cond-row .cond-op{font-weight:600;font-size:0.8rem;color:#555;min-width:40px;text-align:center}
.act-card{border:1px solid #ddd;border-radius:6px;padding:10px;margin-bottom:8px;background:#fff;position:relative}
.act-card .act-tools{position:absolute;top:6px;right:6px;display:flex;gap:3px}
.act-card .act-tools button{background:#fff;border:1px solid #ddd;border-radius:3px;cursor:pointer;padding:1px 5px;font-size:11px}
.col-override-row{display:flex;gap:6px;margin-bottom:4px;align-items:center;flex-wrap:wrap}
.col-override-row select,.col-override-row input{padding:4px 6px;border:1px solid #ddd;border-radius:4px;font-size:0.85rem}
.col-override-row .col-val{flex:1;min-width:120px}
</style>
{% endblock %}

{% block content %}
<div class="container is-fluid mt-4">
    <nav class="breadcrumb" aria-label="breadcrumbs">
        <ul>
            <li><a href="{{ url_for('custom_modules.index') }}">Modul-Builder</a></li>
            <li><a href="{{ url_for('custom_modules.edit', module_id=module.id) }}">{{ module.name }}</a></li>
            <li class="is-active"><a href="#">Builder</a></li>
        </ul>
    </nav>

    <div class="level mb-2">
        <div class="level-left">
            <h2 class="title is-5">{{ module.icon }} {{ module.name }}</h2>
            <span id="na-save-status"></span>
        </div>
        <div class="level-right">
            <button class="button is-success is-small" onclick="saveAll()">💾 Alles speichern</button>
            <a href="{{ url_for('custom_modules.edit', module_id=module.id) }}" class="button is-light is-small">Zurück</a>
        </div>
    </div>

    <div class="tabs is-boxed is-medium mb-3">
        <ul>
            <li id="tab-form" class="is-active"><a onclick="switchTab('form')">📋 Formular</a></li>
            <li id="tab-rules"><a onclick="switchTab('rules')">📐 Regeln</a></li>
            <li id="tab-preview"><a onclick="switchTab('preview')">🧪 Test</a></li>
        </ul>
    </div>

    <!-- ════ Formular-Tab ════ -->
    <div id="view-form">
    <div id="builder-layout">
        <div id="builder-toolbox" class="box">
            <h3 class="title is-6 mb-2">🧰 Elemente</h3>
            <div class="toolbox-item" draggable="true" data-type="text" ondragstart="onToolboxDrag(event)">📝 Text</div>
            <div class="toolbox-item" draggable="true" data-type="number" ondragstart="onToolboxDrag(event)">🔢 Zahl</div>
            <div class="toolbox-item" draggable="true" data-type="checkbox" ondragstart="onToolboxDrag(event)">✅ Checkbox</div>
            <div class="toolbox-item" draggable="true" data-type="dropdown" ondragstart="onToolboxDrag(event)">📑 Dropdown</div>
            <div class="toolbox-item" draggable="true" data-type="radio" ondragstart="onToolboxDrag(event)">🔘 Radio</div>
            <div class="toolbox-item" draggable="true" data-type="separator" ondragstart="onToolboxDrag(event)">➖ Trenner</div>
            <div class="toolbox-item" draggable="true" data-type="label" ondragstart="onToolboxDrag(event)">🏷️ Label</div>
            <div class="toolbox-item" draggable="true" data-type="group_start" ondragstart="onToolboxDrag(event)">📦 Gruppen-Anfang</div>
            <div class="toolbox-item" draggable="true" data-type="group_end" ondragstart="onToolboxDrag(event)">📦 Gruppen-Ende</div>
        </div>
        <div id="builder-canvas" ondragover="onCanvasDragOver(event)" ondrop="onCanvasDrop(event)" ondragleave="onCanvasDragLeave(event)">
            <div id="js-canvas-list" style="min-height:200px">
                <div class="canvas-placeholder">⬇ Elemente hierher ziehen</div>
            </div>
        </div>
        <div id="builder-props" class="box">
            <h3 class="title is-6 mb-2">⚙️ Eigenschaften</h3>
            <div id="js-props-content">
                <p class="has-text-grey" style="font-size:0.85rem">Klicke ein Element an</p>
            </div>
        </div>
    </div>
    </div>

    <!-- ════ Regeln-Tab ════ -->
    <div id="view-rules" style="display:none">
    <div id="rule-layout">
        <div id="rule-list" class="box">
            <div class="level mb-2">
                <div class="level-left"><h3 class="title is-6">📐 Regeln</h3></div>
                <div class="level-right"><button class="button is-small is-primary" onclick="addRule()">+ Regel</button></div>
            </div>
            <div id="js-rule-list">
                <p class="has-text-grey" style="font-size:0.85rem">Keine Regeln definiert.</p>
            </div>
        </div>
        <div id="rule-editor" class="box">
            <div id="js-rule-editor-content">
                <p class="has-text-grey" style="font-size:0.9rem">Wähle links eine Regel aus oder erstelle eine neue.</p>
            </div>
        </div>
    </div>
    </div>

    <!-- ════ Vorschau-Tab ════ -->
    <div id="view-preview" style="display:none">
    <div id="preview-layout">
        <div class="preview-container box" id="js-preview-content" style="max-width:900px;margin:0 auto">
            <p class="has-text-grey" style="font-size:0.9rem">Lade Vorschau…</p>
        </div>
    </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
<script>
// ═══════════════════════════════════════════════════════════════════
//  SHARED STATE
// ═══════════════════════════════════════════════════════════════════
let formFields = [];
let rules = [];
let selectedFieldId = null;
let selectedRuleId = null;
let nextId = { fld: 1, rule: 1, act: 1 };
const MODULE_ID = {{ module.id }};

function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }

// ═══════════════════════════════════════════════════════════════════
//  TAB SWITCHING
// ═══════════════════════════════════════════════════════════════════
function switchTab(name) {
    document.getElementById('view-form').style.display = (name === 'form') ? 'block' : 'none';
    document.getElementById('view-rules').style.display = (name === 'rules') ? 'block' : 'none';
    document.getElementById('view-preview').style.display = (name === 'preview') ? 'block' : 'none';
    document.getElementById('tab-form').className = (name === 'form') ? 'is-active' : '';
    document.getElementById('tab-rules').className = (name === 'rules') ? 'is-active' : '';
    document.getElementById('tab-preview').className = (name === 'preview') ? 'is-active' : '';
    if (name === 'rules' && rules.length > 0 && !selectedRuleId) {
        selectedRuleId = rules[0].id;
        renderRuleList();
        renderRuleEditor();
    }
    if (name === 'preview') loadPreview();
}

// ═══════════════════════════════════════════════════════════════════
//  SAVE / LOAD
// ═══════════════════════════════════════════════════════════════════
function updateSaveStatus(msg) {
    document.getElementById('na-save-status').textContent = msg;
}

function saveAll() {
    updateSaveStatus('💾 Speichere …');
    Promise.all([
        fetch('/custom-modules/' + MODULE_ID + '/api/form-json', {
            method: 'PUT', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(formFields)
        }),
        fetch('/custom-modules/' + MODULE_ID + '/api/rules-json', {
            method: 'PUT', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(rules)
        })
    ]).then(([r1, r2]) => Promise.all([r1.json(), r2.json()]))
    .then(([d1, d2]) => {
        if (d1.ok && d2.ok) {
            updateSaveStatus('✅ Alles gespeichert ' + new Date().toLocaleTimeString());
        } else {
            updateSaveStatus('❌ Fehler beim Speichern');
        }
    }).catch(() => updateSaveStatus('❌ Netzwerkfehler'));
}

function loadAll() {
    Promise.all([
        fetch('/custom-modules/' + MODULE_ID + '/api/form-json').then(r => r.json()),
        fetch('/custom-modules/' + MODULE_ID + '/api/rules-json').then(r => r.json())
    ]).then(([formData, rulesData]) => {
        if (Array.isArray(formData) && formData.length > 0) {
            formFields = formData.map(f => {
                if (!f.id) { f.id = 'fld_' + (nextId.fld++); }
                return f;
            });
            nextId.fld = formFields.reduce((m, f) => Math.max(m, parseInt(String(f.id).replace('fld_','')) || 0), 0) + 1;
        }
        if (Array.isArray(rulesData) && rulesData.length > 0) {
            rules = rulesData.map(r => {
                if (!r.id) { r.id = 'rule_' + (nextId.rule++); }
                return r;
            });
            nextId.rule = rules.reduce((m, r) => Math.max(m, parseInt(String(r.id).replace('rule_','')) || 0), 0) + 1;
            rules.forEach(r => {
                if (r.actions) {
                    r.actions.forEach(a => {
                        if (!a.id) { a.id = 'act_' + (nextId.act++); }
                        const n = parseInt(String(a.id).replace('act_','')) || 0;
                        if (n >= nextId.act) nextId.act = n + 1;
                    });
                }
            });
        }
        if (formFields.length > 0) selectField(formFields[0].id);
        renderCanvas();
        renderProperties();
        renderRuleList();
        if (rules.length > 0) { selectedRuleId = rules[0].id; renderRuleEditor(); }
        updateSaveStatus('✅ Geladen');
    }).catch(() => {
        renderCanvas();
        renderProperties();
        renderRuleList();
    });
}

// ═══════════════════════════════════════════════════════════════════
//  FIELD TYPE TEMPLATES
// ═══════════════════════════════════════════════════════════════════
const FIELD_TEMPLATES = {
    text:       { name:'', label:'Textfeld', placeholder:'', default:'', required:false, inputmode:'', columns:'12' },
    number:     { name:'', label:'Zahl', placeholder:'', default:'', required:false, min:'', max:'', step:'any', columns:'12' },
    checkbox:   { name:'', label:'Checkbox', default:false, columns:'12' },
    dropdown:   { name:'', label:'Dropdown', options:[{value:'',label:''}], default:'', columns:'12' },
    radio:      { name:'', label:'Radio', options:[{value:'',label:''}], default:'', columns:'12' },
    separator:  {},
    label:      { text:'Label-Text', columns:'12' },
    group_start:{ title:'Gruppe', collapsible:false },
    group_end:  {},
};

function createField(type, insertAt) {
    const id = 'fld_' + (nextId.fld++);
    const field = { id, type, ...JSON.parse(JSON.stringify(FIELD_TEMPLATES[type] || {})) };
    if (field.name === '') field.name = id;
    if (insertAt !== undefined && insertAt >= 0 && insertAt < formFields.length) {
        formFields.splice(insertAt, 0, field);
    } else {
        formFields.push(field);
    }
    selectField(id);
    renderCanvas();
    renderProperties();
    return field;
}

// ═══════════════════════════════════════════════════════════════════
//  FORM BUILDER — CANVAS (LIVE FORM PREVIEW)
// ═══════════════════════════════════════════════════════════════════
function renderCanvas() {
    const list = document.getElementById('js-canvas-list');
    if (formFields.length === 0) {
        list.innerHTML = '<div class="canvas-placeholder">⬇ Elemente aus der Toolbox hierher ziehen</div>';
        return;
    }

    let html = '<div id="form-preview">';
    let inGroup = false;

    formFields.forEach((f) => {
        const sel = f.id === selectedFieldId ? ' selected' : '';
        const cond = f.conditional_show;
        const condAttr = (cond && cond.field && cond.value) ? ` data-cond-field="${esc(cond.field)}" data-cond-value="${esc(cond.value)}" style="display:none"` : '';

        const editBtns = `
            <button class="btn-edit" onclick="event.stopPropagation();selectField('${f.id}')" title="Bearbeiten">✎</button>
            <button class="btn-edit" onclick="event.stopPropagation();duplicateField('${f.id}')" title="Duplizieren">📋</button>
            <button class="btn-edit danger" onclick="event.stopPropagation();deleteField('${f.id}')" title="Löschen">✕</button>`;

        if (f.type === 'group_start') {
            if (inGroup) { html += '</div></div>'; }
            html += `<div class="box group-box${sel}"${condAttr} onclick="selectField('${f.id}')">
                <div class="group-edit-overlay">${editBtns}</div>
                <h5 class="title is-6 mb-2">📦 ${esc(f.title||'Gruppe')}</h5>
                <div class="columns is-multiline mb-0">`;
            inGroup = true;
            return;
        }

        if (f.type === 'group_end') {
            if (inGroup) { html += '</div></div>'; }
            inGroup = false;
            return;
        }

        if (f.type === 'separator') {
            html += `<div class="structural-placeholder${sel}"${condAttr} onclick="selectField('${f.id}')">
                <div class="struct-tools">${editBtns}</div>
                <hr style="margin:2px 0">
            </div>`;
            return;
        }

        if (f.type === 'label') {
            html += `<div class="structural-placeholder${sel}"${condAttr} onclick="selectField('${f.id}')">
                <div class="struct-tools">${editBtns}</div>
                <p style="margin:2px 0">${esc(f.text||'')}</p>
            </div>`;
            return;
        }

        // Regular field
        const colSize = f.columns || '12';
        const label = f.label || '';
        const required = f.required ? ' <span class="has-text-danger">*</span>' : '';
        const fieldHtml = renderFieldPreview(f);

        const inner = `
            <div class="field-edit-overlay">
                <span class="field-name-tag" title="Feldname: doppelklick zum Editieren">${esc(f.name||f.id)}</span>
                ${editBtns}
            </div>
            <div class="field-drag-handle" title="Zum Verschieben ziehen"></div>
            <div class="field">
                <label class="label builder-label" data-fid="${f.id}" data-field="label" style="font-size:0.85rem" title="Doppelklick zum Editieren">${esc(label)}${required}</label>
                <div class="control">${fieldHtml}</div>
            </div>
            <div class="field-quick-actions">
                <button onclick="event.stopPropagation();duplicateField('${f.id}')" title="Duplizieren">📋 Kopie</button>
                <button onclick="event.stopPropagation();deleteField('${f.id}')" class="danger" title="Löschen">✕ Löschen</button>
                <button onclick="event.stopPropagation();selectField('${f.id}')" title="Eigenschaften">⚙️ Props</button>
            </div>
            <span class="form-col-badge">${colSize}/12</span>
            <div class="form-resize-handle" data-id="${f.id}"></div>`;

        if (inGroup) {
            html += `<div class="column is-${colSize} field-col${sel}" data-fid="${f.id}"${condAttr} onclick="selectField('${f.id}')">${inner}</div>`;
        } else {
            html += `<div class="field-col${sel}" data-fid="${f.id}"${condAttr} onclick="selectField('${f.id}')">${inner}</div>`;
        }
    });

    if (inGroup) { html += '</div></div>'; }
    html += '</div>';
    list.innerHTML = html;

    // Setup SortableJS
    setupFormSortable();

    // Setup resize handles
    setupResizeHandles();

    // Setup inline editing
    initInlineEditing();
}

let _sortingGuard = false;

function setupFormSortable() {
    const preview = document.getElementById('form-preview');
    if (!preview) return;

    // Destroy existing instances
    if (preview._sortable) preview._sortable.destroy();
    preview.querySelectorAll('.group-box .columns.is-multiline').forEach(gc => {
        if (gc._sortable) gc._sortable.destroy();
    });

    function applyNewOrder() {
        if (_sortingGuard) return;
        _sortingGuard = true;
        // Read top-level field-cols in DOM order
        const topFields = [];
        preview.querySelectorAll(':scope > .field-col').forEach(el => {
            const fid = el.dataset.fid;
            if (fid) { const f = formFields.find(x => x.id === fid); if (f) topFields.push(f); }
        });
        const topFids = new Set(topFields.map(f => f.id));

        // Read inner group field-cols in DOM order
        const groupFields = {};
        preview.querySelectorAll('.group-box .columns.is-multiline').forEach(i => {
            const inner = [];
            i.querySelectorAll(':scope > .field-col').forEach(el => {
                const fid = el.dataset.fid;
                if (fid) { const f = formFields.find(x => x.id === fid); if (f) inner.push(f); }
            });
            if (inner.length) {
                // Find the group_start index
                const gi = formFields.findIndex(x => x.id === inner[0].id);
                if (gi >= 0) {
                    let gs = gi; while (gs > 0 && formFields[gs].type !== 'group_start') gs--;
                    let ge = gi; while (ge < formFields.length && formFields[ge].type !== 'group_end') ge++;
                    if (gs >= 0 && ge < formFields.length) groupFields[formFields[gs].id] = { gs, ge, inner };
                }
            }
        });

        // Rebuild formFields preserving structure
        const result = [];
        let topIdx = 0;
        const topList = [...topFields];
        let i = 0;
        while (i < formFields.length) {
            const f = formFields[i];
            if (f.type === 'group_start') {
                const g = groupFields[f.id];
                if (g) {
                    result.push(f); // group_start
                    result.push(...g.inner); // fields in group
                    result.push(formFields[g.ge]); // group_end
                    i = g.ge + 1;
                    continue;
                }
            }
            if (topFids.has(f.id)) {
                result.push(topList[topIdx++]);
            } else if (!Object.values(groupFields).some(g => g.inner.includes(f))) {
                result.push(f);
            }
            i++;
        }
        if (result.length === formFields.length) { formFields = result; }
        renderCanvas();
        if (selectedFieldId) selectField(selectedFieldId);
        markDirty();
        _sortingGuard = false;
    }

    // Top level: reorder field-cols outside groups
    preview._sortable = new Sortable(preview, {
        animation: 150,
        handle: '.field-drag-handle',
        filter: '.group-box, .structural-placeholder',
        onEnd: applyNewOrder
    });

    // Inner sortable for each group
    preview.querySelectorAll('.group-box .columns.is-multiline').forEach(groupCols => {
        groupCols._sortable = new Sortable(groupCols, {
            animation: 150,
            handle: '.field-drag-handle',
            onEnd: applyNewOrder
        });
    });
}

function renderFieldPreview(f) {
    const fid = f.id;
    switch (f.type) {
        case 'text':
            return `<input class="input" type="text" placeholder="${esc(f.placeholder||'Text eingeben…')}" data-fid="${fid}" readonly onfocus="this.removeAttribute('readonly')" style="font-size:0.85rem;pointer-events:auto">`;
        case 'number':
            return `<input class="input" type="text" inputmode="decimal" placeholder="${esc(f.placeholder||'0')}" data-fid="${fid}" readonly onfocus="this.removeAttribute('readonly')" style="font-size:0.85rem;pointer-events:auto">`;
        case 'checkbox':
            return `<label class="checkbox" style="font-size:0.85rem;pointer-events:auto"><input type="checkbox" data-fid="${fid}" ${f.default?'checked':''}> ${esc(f.label||'')}</label>`;
        case 'dropdown':
            const opts = f.options||[];
            return `<div class="select is-fullwidth" style="font-size:0.85rem;pointer-events:auto"><select data-fid="${fid}">${opts.map(o => '<option>'+esc(o.label||o.value)+'</option>').join('')}</select></div>`;
        case 'radio':
            const radOpts = f.options||[];
            return radOpts.map(o => `<label class="radio" style="font-size:0.85rem;pointer-events:auto"><input type="radio" data-fid="${fid}" name="builder_${fid}"> ${esc(o.label||o.value)}</label>`).join('');
        default:
            return '';
    }
}
function getFieldIcon(type) { return { text:'📝', number:'🔢', checkbox:'✅', dropdown:'📑', radio:'🔘', separator:'➖', label:'🏷️', group_start:'📦', group_end:'📦' }[type]||'📄'; }

// ═══════════════════════════════════════════════════════════════════
//  RESIZE HANDLES
// ═══════════════════════════════════════════════════════════════════
let resizeState = null;

function setupResizeHandles() {
    document.querySelectorAll('.form-resize-handle').forEach(h => {
        h.addEventListener('mousedown', startResize);
    });
}

function startResize(e) {
    e.preventDefault();
    e.stopPropagation();
    const handle = e.currentTarget;
    const fieldId = handle.dataset.id;
    const colEl = handle.closest('.field-col');
    const grid = document.getElementById('form-preview');
    if (!grid || !colEl) return;
    const gridRect = grid.getBoundingClientRect();
    const colWidth = gridRect.width / 12;

    resizeState = {
        fieldId: fieldId,
        colEl: colEl,
        grid: grid,
        gridRect: gridRect,
        colWidth: colWidth,
        startX: e.clientX,
        startCols: parseInt(colEl.className.match(/is-(\d+)/)?.[1] || '12')
    };

    handle.classList.add('active');
    document.addEventListener('mousemove', doResize);
    document.addEventListener('mouseup', endResize);
}

function doResize(e) {
    if (!resizeState) return;
    const rs = resizeState;
    const dx = e.clientX - rs.gridRect.left;
    let newCols = Math.round(dx / rs.colWidth);
    newCols = Math.max(1, Math.min(12, newCols));
    rs.colEl.className = rs.colEl.className.replace(/is-\d+/g, '') + ' is-' + newCols;

    let snapLine = document.getElementById('resize-snap');
    if (!snapLine) {
        snapLine = document.createElement('div');
        snapLine.id = 'resize-snap';
        snapLine.className = 'resize-snap-line';
        document.body.appendChild(snapLine);
    }
    const snapX = rs.gridRect.left + newCols * rs.colWidth;
    snapLine.style.left = snapX + 'px';
    snapLine.classList.add('show');

    const badge = rs.colEl.querySelector('.form-col-badge');
    if (badge) badge.textContent = newCols + '/12';
}

function endResize(e) {
    if (!resizeState) return;
    const rs = resizeState;
    document.removeEventListener('mousemove', doResize);
    document.removeEventListener('mouseup', endResize);
    const snapLine = document.getElementById('resize-snap');
    if (snapLine) snapLine.classList.remove('show');

    const dx = e.clientX - rs.gridRect.left;
    let newCols = Math.round(dx / rs.colWidth);
    newCols = Math.max(1, Math.min(12, newCols));

    const f = formFields.find(x => x.id === rs.fieldId);
    if (f && newCols !== rs.startCols) {
        f.columns = String(newCols);
        if (selectedFieldId === rs.fieldId) renderProperties();
        markDirty();
    }

    rs.colEl.className = rs.colEl.className.replace(/is-\d+/g, '') + ' is-' + newCols;
    document.querySelectorAll('.form-resize-handle.active').forEach(h => h.classList.remove('active'));
    resizeState = null;
}

// ═══════════════════════════════════════════════════════════════════
//  INLINE EDITING
// ═══════════════════════════════════════════════════════════════════
function initInlineEditing() {
    document.querySelectorAll('.builder-label').forEach(label => {
        label.removeEventListener('dblclick', handleLabelDblClick);
        label.addEventListener('dblclick', handleLabelDblClick);
    });
    // Input fields: focus selects field, tab moves to next
    document.querySelectorAll('#form-preview .control input[data-fid], #form-preview .control select[data-fid]').forEach(el => {
        el.removeEventListener('focus', handleFieldFocus);
        el.addEventListener('focus', handleFieldFocus);
    });
}

function handleLabelDblClick(e) {
    e.preventDefault();
    e.stopPropagation();
    const label = e.currentTarget;
    const fid = label.dataset.fid;
    const field = label.dataset.field || 'label';
    const currentText = label.textContent.replace(' *', '').trim();

    // Select the field
    selectField(fid);

    const input = document.createElement('input');
    input.type = 'text';
    input.className = 'inline-edit-input';
    input.value = currentText;
    input.style.width = Math.max(120, currentText.length * 10) + 'px';
    label.classList.add('editing');
    label.textContent = '';
    label.appendChild(input);
    input.focus();
    input.select();

    function save() {
        const val = input.value.trim();
        if (val && val !== currentText) {
            updateFieldLabel(fid, field, val);
        }
        label.classList.remove('editing');
        label.textContent = val || currentText;
        const required = formFields.find(x => x.id === fid)?.required;
        if (required) label.innerHTML = esc(val || currentText) + ' <span class="has-text-danger">*</span>';
    }

    input.addEventListener('blur', save);
    input.addEventListener('keydown', function(ev) {
        if (ev.key === 'Enter') { input.blur(); }
        if (ev.key === 'Escape') { label.classList.remove('editing'); label.textContent = currentText; const req = formFields.find(x => x.id === fid)?.required; if (req) label.innerHTML = esc(currentText) + ' <span class="has-text-danger">*</span>'; }
        ev.stopPropagation();
    });
}

function handleFieldFocus(e) {
    const el = e.currentTarget;
    const fid = el.dataset.fid;
    if (fid) selectField(fid);
}

function updateFieldLabel(fid, field, val) {
    const f = formFields.find(x => x.id === fid);
    if (!f) return;
    if (field === 'label') f.label = val;
    else f[field] = val;
    renderProperties();
    markDirty();
}

// ═══════════════════════════════════════════════════════════════════
//  FORM BUILDER — PROPERTIES
// ═══════════════════════════════════════════════════════════════════
function renderProperties() {
    const pane = document.getElementById('js-props-content');
    const f = formFields.find(x => x.id === selectedFieldId);
    if (!f) { pane.innerHTML = '<p class="has-text-grey" style="font-size:0.85rem">Klicke ein Element an</p>'; return; }
    let html = `<div class="prop-group"><label>Feld-ID</label><input value="${esc(f.id)}" disabled></div>`;
    if (f.type !== 'separator' && f.type !== 'group_end') {
        html += propInp('name','Feld-Name',f.name);
        html += propInp('label','Label',f.label);
    }
    if (f.type === 'text') {
        html += propInp('placeholder','Platzhalter',f.placeholder);
        html += propInp('default','Standardwert',f.default);
        html += propChk('required','Erforderlich',f.required);
        html += propInp('inputmode','Input-Mode',f.inputmode);
    }
    if (f.type === 'number') {
        html += propInp('placeholder','Platzhalter',f.placeholder);
        html += propInp('default','Standardwert',f.default);
        html += propChk('required','Erforderlich',f.required);
        html += propInp('min','Minimum',f.min);
        html += propInp('max','Maximum',f.max);
        html += propInp('step','Schrittweite',f.step);
    }
    if (f.type === 'checkbox') html += propChk('default','Standardmäßig aktiviert',f.default);
    if (f.type === 'dropdown' || f.type === 'radio') {
        html += `<div class="prop-group"><label>Optionen</label>`;
        (f.options||[]).forEach((o,i) => {
            html += `<div style="display:flex;gap:4px;margin-bottom:4px">
                <input value="${esc(o.value)}" placeholder="Wert" style="flex:1" onchange="updOpt('${f.id}',${i},'value',this.value)">
                <input value="${esc(o.label)}" placeholder="Label" style="flex:2" onchange="updOpt('${f.id}',${i},'label',this.value)">
                <button class="button is-small is-danger" onclick="remOpt('${f.id}',${i})">✕</button></div>`;
        });
        html += `<button class="button is-small is-light" onclick="addOpt('${f.id}')">+ Option</button></div>`;
        html += propInp('default','Standardwert',f.default);
    }
    if (f.type === 'label') {
        html += `<div class="prop-group"><label>Text</label><textarea onchange="updFld('${f.id}','text',this.value)">${esc(f.text||'')}</textarea></div>`;
    }
    if (f.type === 'group_start') {
        html += propInp('title','Gruppen-Titel',f.title);
        html += propChk('collapsible','Einklappbar',f.collapsible);
    }
    if (!['separator','group_start','group_end'].includes(f.type)) {
        const curCols = f.columns || '12';
        html += `<div class="prop-group"><label>Spaltenbreite</label>
            <div class="select is-fullwidth is-small"><select onchange="updFld('${f.id}','columns',this.value)">
                <option value="12" ${curCols==='12'?'selected':''}>Ganzzeile (12)</option>
                <option value="8" ${curCols==='8'?'selected':''}>2/3 (8)</option>
                <option value="6" ${curCols==='6'?'selected':''}>Hälfte (6)</option>
                <option value="4" ${curCols==='4'?'selected':''}>1/3 (4)</option>
                <option value="3" ${curCols==='3'?'selected':''}>1/4 (3)</option>
                <option value="2" ${curCols==='2'?'selected':''}>1/6 (2)</option>
            </select></div></div>`;
    }
    if (f.type !== 'separator' && f.type !== 'group_end') {
        html += `<hr><div class="prop-group"><label>Bedingt anzeigen (wenn Feld …)</label>
            <select onchange="updFld('${f.id}','condField',this.value)" style="margin-bottom:4px">
                <option value="">— immer anzeigen —</option>`;
        formFields.forEach(other => {
            if (other.id !== f.id && ['checkbox','dropdown','radio'].includes(other.type)) {
                const sel = (f.conditional_show && f.conditional_show.field === other.name) ? 'selected' : '';
                html += `<option value="${esc(other.name)}" ${sel}>${esc(other.label||other.name)}</option>`;
            }
        });
        html += `</select><input placeholder="= Wert (z.B. 'an')" value="${esc((f.conditional_show&&f.conditional_show.value)||'')}" onchange="updFld('${f.id}','condValue',this.value)" style="font-size:0.85rem"></div>`;
    }
    pane.innerHTML = html;
}
function propInp(key,label,val) { return `<div class="prop-group"><label>${label}</label><input value="${esc(val||'')}" onchange="updFld('${selectedFieldId}','${key}',this.value)"></div>`; }
function propChk(key,label,val) { return `<div class="prop-group"><label class="checkbox"><input type="checkbox" ${val?'checked':''} onchange="updFld('${selectedFieldId}','${key}',this.checked)"> ${label}</label></div>`; }

function updFld(id,key,val) {
    const f = formFields.find(x => x.id === id); if (!f) return;
    if (key === 'condField') { if (!f.conditional_show) f.conditional_show={}; f.conditional_show.field=val||undefined; if (!f.conditional_show.field) f.conditional_show=undefined; }
    else if (key === 'condValue') { if (!f.conditional_show) f.conditional_show={}; f.conditional_show.value=val||undefined; if (!f.conditional_show.value) f.conditional_show=undefined; }
    else f[key]=val;
    renderCanvas(); selectField(id); renderProperties(); markDirty();
}
function updOpt(fid,idx,key,val) { const f=formFields.find(x=>x.id===fid); if(!f||!f.options)return; f.options[idx][key]=val; renderCanvas(); renderProperties(); markDirty(); }
function addOpt(fid) { const f=formFields.find(x=>x.id===fid); if(!f||!f.options)return; f.options.push({value:'',label:''}); renderProperties(); markDirty(); }
function remOpt(fid,idx) { const f=formFields.find(x=>x.id===fid); if(!f||!f.options)return; f.options.splice(idx,1); renderProperties(); markDirty(); }

// ═══════════════════════════════════════════════════════════════════
//  FORM BUILDER — SELECTION, CRUD, DRAG
// ═══════════════════════════════════════════════════════════════════
function selectField(id) { selectedFieldId = id; renderCanvas(); renderProperties(); }

function duplicateField(id) {
    const idx = formFields.findIndex(x => x.id === id); if (idx === -1) return;
    const copy = JSON.parse(JSON.stringify(formFields[idx]));
    copy.id = 'fld_' + (nextId.fld++); copy.name = copy.name + '_kopie';
    formFields.splice(idx + 1, 0, copy);
    renderCanvas(); selectField(copy.id); renderProperties(); markDirty();
}
function deleteField(id) {
    const idx = formFields.findIndex(x => x.id === id); if (idx === -1) return;
    formFields.splice(idx, 1);
    if (selectedFieldId === id) selectedFieldId = formFields.length > 0 ? formFields[Math.min(idx, formFields.length-1)].id : null;
    renderCanvas(); renderProperties(); markDirty();
}
function onToolboxDrag(ev) { ev.dataTransfer.setData('text/plain', ev.target.dataset.type); ev.dataTransfer.effectAllowed = 'copy'; }

// Drop indicator
let _dropIndicator = null;
function getDropIndicator() {
    if (!_dropIndicator || !_dropIndicator.isConnected) {
        _dropIndicator = document.createElement('div');
        _dropIndicator.className = 'drop-indicator';
        _dropIndicator.id = 'builder-drop-indicator';
        _dropIndicator.style.display = 'none';
        document.getElementById('js-canvas-list')?.appendChild(_dropIndicator);
    }
    return _dropIndicator;
}

function onCanvasDragOver(ev) {
    ev.preventDefault();
    ev.dataTransfer.dropEffect = 'copy';
    const preview = document.getElementById('form-preview');
    if (!preview) return;
    const items = preview.querySelectorAll(':scope > .field-col, :scope > .group-box, :scope > .structural-placeholder');
    const ind = getDropIndicator();
    ind.style.display = 'none';
    items.forEach(el => {
        const r = el.getBoundingClientRect();
        const mid = r.top + r.height / 2;
        if (ev.clientY >= r.top && ev.clientY <= r.bottom) {
            const pos = ev.clientY < mid ? 'before' : 'after';
            ind.style.display = 'block';
            ind.style.position = 'absolute';
            if (pos === 'before') {
                ind.style.top = (r.top - preview.getBoundingClientRect().top - 2) + 'px';
            } else {
                ind.style.top = (r.bottom - preview.getBoundingClientRect().top + 2) + 'px';
            }
            ind.style.left = '10px';
            ind.style.right = '10px';
            ind.dataset.insertAfter = el.dataset.fid || '';
            ind.dataset.insertPos = pos;
        }
    });
}

function onCanvasDragLeave(ev) {
    const ind = document.getElementById('builder-drop-indicator');
    if (ind) ind.style.display = 'none';
}

function onCanvasDrop(ev) {
    ev.preventDefault();
    const ind = getDropIndicator();
    ind.style.display = 'none';
    const type = ev.dataTransfer.getData('text/plain'); if (!type) return;
    const preview = document.getElementById('form-preview');
    if (!preview) return;

    // Direct children of form-preview (field-cols, group-boxes, structural elements)
    const items = preview.querySelectorAll(':scope > .field-col, :scope > .group-box, :scope > .structural-placeholder');
    let insertAt = formFields.length;
    items.forEach((el, i) => {
        const r = el.getBoundingClientRect();
        if (ev.clientY > r.top + r.height / 2) {
            const fid = el.classList.contains('group-box')
                ? null
                : (el.dataset.fid || null);
            if (fid) {
                const fi = formFields.findIndex(x => x.id === fid);
                if (fi >= 0) insertAt = fi + 1;
            } else if (el.classList.contains('group-box')) {
                const firstField = el.querySelector('.field-col');
                if (firstField) {
                    const innerId = firstField.dataset.fid;
                    if (innerId) {
                        let gi = formFields.findIndex(x => x.id === innerId);
                        while (gi < formFields.length && formFields[gi].type !== 'group_end') gi++;
                        if (gi < formFields.length) insertAt = gi + 1;
                    }
                }
            }
        }
    });
    if (insertAt > formFields.length) insertAt = formFields.length;
    createField(type, insertAt);
    markDirty();
}

// ═══════════════════════════════════════════════════════════════════
//  RULE BUILDER
// ═══════════════════════════════════════════════════════════════════
function getFieldNames() {
    return formFields.filter(f => f.name && f.type !== 'separator' && f.type !== 'group_end' && f.type !== 'label')
        .map(f => ({ name: f.name, label: f.label || f.name, type: f.type }));
}

function getFieldType(fieldName) {
    const f = formFields.find(x => x.name === fieldName);
    return f ? f.type : 'text';
}

function addRule() {
    const id = 'rule_' + (nextId.rule++);
    rules.push({ id, name: 'Neue Regel', conditions: { operator: 'and', items: [] }, actions: [] });
    selectedRuleId = id;
    renderRuleList(); renderRuleEditor(); markDirty();
}

function duplicateRule(id) {
    const idx = rules.findIndex(r => r.id === id); if (idx === -1) return;
    const copy = JSON.parse(JSON.stringify(rules[idx]));
    copy.id = 'rule_' + (nextId.rule++); copy.name = copy.name + ' (Kopie)';
    copy.actions.forEach(a => { a.id = 'act_' + (nextId.act++); });
    rules.splice(idx + 1, 0, copy);
    selectedRuleId = copy.id;
    renderRuleList(); renderRuleEditor(); markDirty();
}

function deleteRule(id) {
    const idx = rules.findIndex(r => r.id === id); if (idx === -1) return;
    rules.splice(idx, 1);
    if (selectedRuleId === id) selectedRuleId = rules.length > 0 ? rules[Math.min(idx, rules.length-1)].id : null;
    renderRuleList(); renderRuleEditor(); markDirty();
}

function renderRuleList() {
    const list = document.getElementById('js-rule-list');
    if (rules.length === 0) {
        list.innerHTML = '<p class="has-text-grey" style="font-size:0.85rem">Keine Regeln definiert.</p>';
        return;
    }
    list.innerHTML = rules.map(r => {
        const sel = r.id === selectedRuleId ? ' selected' : '';
        const cnt = (r.conditions?.items?.length || 0) + ' Bedingungen, ' + (r.actions?.length || 0) + ' Aktionen';
        return `<div class="rule-card${sel}" data-id="${r.id}" onclick="selectRule('${r.id}')">
            <div class="rule-name">${esc(r.name)}</div>
            <div class="rule-summary">${cnt}</div>
            <div class="rule-tools">
                <button onclick="event.stopPropagation();duplicateRule('${r.id}')" title="Duplizieren">📋</button>
                <button onclick="event.stopPropagation();deleteRule('${r.id}')" title="Löschen">✕</button>
            </div>
        </div>`;
    }).join('');

    Sortable.create(document.getElementById('js-rule-list'), {
        animation: 150, handle: '.rule-card',
        onEnd: function(evt) {
            const [item] = rules.splice(evt.oldIndex, 1);
            rules.splice(evt.newIndex, 0, item);
            renderRuleList();
            if (selectedRuleId) renderRuleEditor();
            markDirty();
        }
    });
}

function selectRule(id) {
    selectedRuleId = id;
    renderRuleList(); renderRuleEditor();
}

function renderRuleEditor() {
    const pane = document.getElementById('js-rule-editor-content');
    const r = rules.find(x => x.id === selectedRuleId);
    if (!r) { pane.innerHTML = '<p class="has-text-grey" style="font-size:0.9rem">Wähle links eine Regel aus oder erstelle eine neue.</p>'; return; }

    let html = `<div class="field"><label class="label">Regel-Name</label>
        <input class="input" value="${esc(r.name)}" onchange="updRule('${r.id}','name',this.value)" style="font-size:0.9rem"></div>`;

    // Conditions
    html += `<h4 class="title is-6 mt-4">🎯 Bedingungen <span class="tag is-light">ALLE erfüllen (UND)</span></h4>`;
    html += `<div id="js-cond-list">`;
    (r.conditions?.items || []).forEach((c, i) => {
        html += renderCondRow(r.id, c, i);
    });
    html += `</div>`;
    html += `<button class="button is-small is-light mt-2" onclick="addCond('${r.id}')">+ Bedingung</button>`;

    // Actions
    html += `<h4 class="title is-6 mt-4">⚡ Aktionen (Positionen)</h4>`;
    html += `<div id="js-act-list">`;
    (r.actions || []).forEach((a, i) => {
        html += renderActCard(r.id, a, i);
    });
    html += `</div>`;
    html += `<button class="button is-small is-primary mt-2" onclick="addAction('${r.id}')">+ Aktion (LV-Position)</button>`;

    pane.innerHTML = html;
}

function renderCondRow(ruleId, cond, idx) {
    const fields = getFieldNames();
    const ft = getFieldType(cond.field);
    const opOptions = ft === 'checkbox'
        ? '<option value="is_checked" '+(cond.operator==='is_checked'?'selected':'')+'>ist aktiviert</option>'
        : (ft === 'number'
            ? `<option value="gt" ${cond.operator==='gt'?'selected':''}>></option><option value="gte" ${cond.operator==='gte'?'selected':''}>>=</option><option value="lt" ${cond.operator==='lt'?'selected':''}><</option><option value="lte" ${cond.operator==='lte'?'selected':''}><=</option><option value="eq" ${cond.operator==='eq'?'selected':''}>=</option><option value="between" ${cond.operator==='between'?'selected':''}>zwischen</option>`
            : `<option value="eq" ${cond.operator==='eq'?'selected':''}>=</option><option value="neq" ${cond.operator==='neq'?'selected':''}>≠</option>`);
    const showVal = ft !== 'checkbox' || (cond.operator !== 'is_checked' && cond.operator !== 'is_empty');
    const valInput = showVal
        ? (cond.operator === 'between'
            ? `<input class="col-val" placeholder="Von" value="${esc(cond.value||'')}" style="width:70px" onchange="updCond('${ruleId}',${idx},'value',this.value)">
               <input class="col-val" placeholder="Bis" value="${esc(cond.value2||'')}" style="width:70px" onchange="updCond('${ruleId}',${idx},'value2',this.value)">`
            : `<input class="col-val" placeholder="Wert" value="${esc(cond.value||'')}" onchange="updCond('${ruleId}',${idx},'value',this.value)">`)
        : '';
    return `<div class="cond-row">
        <select onchange="updCond('${ruleId}',${idx},'field',this.value)" style="flex:1;min-width:100px">
            <option value="">— Feld wählen —</option>
            ${fields.map(f => `<option value="${esc(f.name)}" ${f.name===cond.field?'selected':''}>${esc(f.label)}</option>`).join('')}
        </select>
        <select onchange="updCond('${ruleId}',${idx},'operator',this.value)">${opOptions}</select>
        ${valInput}
        <button class="button is-small is-danger" onclick="remCond('${ruleId}',${idx})">✕</button>
    </div>`;
}

function renderActCard(ruleId, act, idx) {
    const colOptions = ['menge','faktor','laenge','breite','tiefe','einheit','kurztext','bemerkung','pos_nr','einzelpreis'];
    const typeOptions = ['fixed','field','formula'];
    const typeLabels = { fixed:'Festwert', field:'Feld', formula:'Formel' };
    let html = `<div class="act-card">
        <div class="act-tools">
            <button onclick="remAction('${ruleId}',${idx})" title="Löschen">✕</button>
        </div>
        <div style="display:flex;gap:8px;margin-bottom:6px;flex-wrap:wrap">
            <div style="flex:1;min-width:150px">
                <label style="font-size:0.8rem;font-weight:600">LV-Positions-Nr</label>
                <input class="input" value="${esc(act.pos_nr||'')}" placeholder="z.B. 1.3.02.0220" onchange="updAct('${ruleId}',${idx},'pos_nr',this.value)" style="font-size:0.85rem">
            </div>
            <div style="display:flex;align-items:flex-end;gap:6px">
                <label class="checkbox" style="font-size:0.85rem">
                    <input type="checkbox" ${act.lv_lookup?'checked':''} onchange="updAct('${ruleId}',${idx},'lv_lookup',this.checked)">
                    Vom LV übernehmen
                </label>
            </div>
        </div>`;
    html += `<div style="margin-top:6px"><label style="font-size:0.8rem;font-weight:600">Spalten-Überschreibungen</label>`;
    const cols = act.columns || {};
    Object.entries(cols).forEach(([colKey, colVal]) => {
        html += `<div class="col-override-row">
            <select onchange="renameCol('${ruleId}',${idx},'${colKey}',this.value)" style="width:110px">
                ${colOptions.map(o => `<option value="${o}" ${o===colKey?'selected':''}>${o}</option>`).join('')}
            </select>
            <select onchange="updColType('${ruleId}',${idx},'${colKey}',this.value)" style="width:80px">
                ${typeOptions.map(t => `<option value="${t}" ${colVal?.type===t?'selected':''}>${typeLabels[t]}</option>`).join('')}
            </select>
            <input class="col-val" placeholder="Wert / Feldname / Formel" value="${esc(colVal?.value||'')}"
                onchange="updColVal('${ruleId}',${idx},'${colKey}',this.value)">
            <button class="button is-small is-danger" onclick="remCol('${ruleId}',${idx},'${colKey}')">✕</button>
        </div>`;
    });
    html += `<button class="button is-small is-light mt-1" onclick="addCol('${ruleId}',${idx})">+ Spalte</button>`;
    html += `</div></div>`;
    return html;
}

// ── Rule CRUD helpers ──────────────────────────────────────────────
function updRule(ruleId, key, val) {
    const r = rules.find(x => x.id === ruleId); if (!r) return;
    r[key] = val; renderRuleList(); markDirty();
}

function addCond(ruleId) {
    const r = rules.find(x => x.id === ruleId); if (!r) return;
    if (!r.conditions) r.conditions = { operator: 'and', items: [] };
    r.conditions.items.push({ field: '', operator: 'eq', value: '' });
    renderRuleEditor(); markDirty();
}
function remCond(ruleId, idx) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.conditions) return;
    r.conditions.items.splice(idx, 1);
    renderRuleEditor(); markDirty();
}
function updCond(ruleId, idx, key, val) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.conditions) return;
    r.conditions.items[idx][key] = val;
    // Re-render if field changed (to update operator options)
    if (key === 'field') renderRuleEditor();
    markDirty();
}

function addAction(ruleId) {
    const r = rules.find(x => x.id === ruleId); if (!r) return;
    const id = 'act_' + (nextId.act++);
    if (!r.actions) r.actions = [];
    r.actions.push({ id, pos_nr: '', lv_lookup: true, columns: { menge: { type: 'field', value: '' } } });
    renderRuleEditor(); markDirty();
}
function remAction(ruleId, idx) {
    const r = rules.find(x => x.id === ruleId); if (!r) return;
    r.actions.splice(idx, 1);
    renderRuleEditor(); markDirty();
}
function updAct(ruleId, idx, key, val) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    r.actions[idx][key] = val;
    markDirty();
}

function addCol(ruleId, actIdx) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    const a = r.actions[actIdx]; if (!a) return;
    if (!a.columns) a.columns = {};
    // Find first unused column
    const allCols = ['menge','faktor','laenge','breite','tiefe','einheit','kurztext','bemerkung','pos_nr','einzelpreis'];
    const used = Object.keys(a.columns);
    const free = allCols.find(c => !used.includes(c));
    a.columns[free || 'menge'] = { type: 'fixed', value: '' };
    renderRuleEditor(); markDirty();
}
function remCol(ruleId, actIdx, colKey) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    const a = r.actions[actIdx]; if (!a || !a.columns) return;
    delete a.columns[colKey];
    renderRuleEditor(); markDirty();
}
function updColType(ruleId, actIdx, colKey, val) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    const a = r.actions[actIdx]; if (!a || !a.columns || !a.columns[colKey]) return;
    a.columns[colKey].type = val; markDirty();
}
function updColVal(ruleId, actIdx, colKey, val) {
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    const a = r.actions[actIdx]; if (!a || !a.columns || !a.columns[colKey]) return;
    a.columns[colKey].value = val; markDirty();
}
function renameCol(ruleId, actIdx, oldKey, newKey) {
    if (oldKey === newKey) return;
    const r = rules.find(x => x.id === ruleId); if (!r || !r.actions) return;
    const a = r.actions[actIdx]; if (!a || !a.columns) return;
    if (a.columns[newKey] !== undefined) return; // target exists
    a.columns[newKey] = a.columns[oldKey];
    delete a.columns[oldKey];
    renderRuleEditor(); markDirty();
}

function markDirty() { updateSaveStatus('✏️ Ungespeicherte Änderungen'); }

// ═══════════════════════════════════════════════════════════════════
//  PREVIEW
// ═══════════════════════════════════════════════════════════════════
function loadPreview() {
    const pane = document.getElementById('js-preview-content');
    pane.innerHTML = '<p class="has-text-grey">⏳ Lade Vorschau…</p>';
    fetch('/custom-modules/' + MODULE_ID + '/api/preview')
        .then(r => r.text())
        .then(html => { pane.innerHTML = html; })
        .catch(() => { pane.innerHTML = '<div class="notification is-danger">Vorschau konnte nicht geladen werden.</div>'; });
}

// ═══════════════════════════════════════════════════════════════════
//  INIT
// ═══════════════════════════════════════════════════════════════════
loadAll();
</script>
{% endblock %}
