(function () {
    'use strict';
    const base = window.projectsBaseUrl || '';
    let csrf = window.projectsCsrfToken || '';
    const el = document.getElementById('projectScriptModal');
    if (!el || typeof bootstrap === 'undefined') return;
    const modal = bootstrap.Modal.getOrCreateInstance(el);
    let card = null, objects = [];

    const $ = (id) => document.getElementById(id);
    const esc = (s) => String(s == null ? '' : s).replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
    const fmt = (n) => Number(n || 0).toLocaleString();

    function busy(btn, on, label) {
        if (on) { btn.dataset.html = btn.innerHTML; btn.classList.add('busy'); btn.disabled = true; btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>' + label; }
        else { btn.classList.remove('busy'); btn.disabled = false; btn.innerHTML = btn.dataset.html || btn.innerHTML; }
    }

    // ── open + load ─────────────────────────────────────────────────────
    document.getElementById('projectsCollection')?.addEventListener('click', (e) => {
        const a = e.target.closest('[data-project-action="script"]');
        if (!a) return;
        e.preventDefault();
        card = a.closest('[data-project-card]');
        if (!card) return;
        $('scriptProjectName').textContent = card.dataset.name || '';
        modal.show();
        load();
    });

    async function load() {
        if (!card) return;
        objects = [];
        $('scriptObjects').innerHTML = '<div class="psql-hint">Reading database…</div>';
        try {
            const r = await fetch(`${base}/project/${encodeURIComponent(card.dataset.projectSlug)}/script`, { headers: { Accept: 'application/json' }, credentials: 'same-origin' });
            const d = await r.json();
            if (!r.ok || !d.success) throw new Error(d.message || 'Could not read the database.');
            objects = d.objects || [];
            $('scriptConnLabel').textContent = (d.info && (d.info.database || d.info.host)) ? ((d.info.database || '') + (d.info.host ? ' @ ' + d.info.host : '')) : (d.project && d.project.name) || 'Database';
            $('scriptEngine').textContent = (d.info && d.info.dialect && (d.info.dialect.label || d.info.dialect.id)) || 'SQL';
            // Target-engine picker: convert the script into any engine the platform lists.
            const sel = $('scriptTarget');
            if (sel && Array.isArray(d.targets)) {
                const sourceId = (d.info && d.info.dialect && d.info.dialect.id) || '';
                sel.innerHTML = '<option value="">Same engine as the source (' + (($('scriptEngine').textContent) || 'native') + ')</option>';
                d.targets.forEach((t) => {
                    if (!t || !t.id || t.id === sourceId) return;
                    const o = document.createElement('option');
                    o.value = t.id; o.textContent = t.label + ' (converted)';
                    sel.appendChild(o);
                });
                sel.onchange = () => { const h = $('scriptTargetHint'); if (h) h.style.display = sel.value ? '' : 'none'; };
            }
            render();
        } catch (err) {
            $('scriptObjects').innerHTML = '';
            Swal.fire('Cannot read the database', err.message, 'error');
        }
    }

    const scope = () => (document.querySelector('input[name="scriptScope"]:checked') || {}).value || 'project';
    const mode = () => (document.querySelector('input[name="scriptMode"]:checked') || {}).value || 'both';
    const inScope = (o) => scope() === 'all' ? true : !!o.in_project;

    function render() {
        const projCount = objects.filter((o) => o.in_project).length;
        document.querySelector('[data-script-count="project"]').textContent = projCount;
        document.querySelector('[data-script-count="all"]').textContent = objects.length;
        renderObjects();
        syncRowLimit();
    }

    function renderObjects() {
        const root = $('scriptObjects');
        const list = objects.filter(inScope);
        $('scriptPickCount').textContent = list.length ? '· ' + list.length : '';
        root.innerHTML = '';
        if (!list.length) { root.innerHTML = '<div class="psql-hint">No tables in this scope.</div>'; return; }
        list.forEach((o) => {
            const row = document.createElement('label');
            row.className = 'psql-obj';
            row.innerHTML =
                '<input type="checkbox" data-script-obj value="' + esc(o.name) + '" checked>' +
                '<span class="name">' + esc(o.name) + '</span>' +
                (o.type === 'VIEW' ? '<span class="badge-view">VIEW</span>' : '') +
                (o.system ? '<span class="badge-sys">system</span>' : '') +
                '<span class="rows">' + (o.type === 'VIEW' ? 'view' : fmt(o.rows) + ' rows') + '</span>';
            root.append(row);
        });
        $('scriptSelectAll').checked = true;
    }

    function selected() {
        return Array.from(document.querySelectorAll('[data-script-obj]:checked')).map((x) => x.value);
    }

    function syncRowLimit() {
        const wrap = document.querySelector('.psql-rowlimit');
        if (wrap) wrap.classList.toggle('disabled', mode() === 'structure');
    }

    document.querySelectorAll('input[name="scriptScope"]').forEach((r) => r.addEventListener('change', renderObjects));
    document.querySelectorAll('input[name="scriptMode"]').forEach((r) => r.addEventListener('change', syncRowLimit));
    $('scriptSelectAll')?.addEventListener('change', (e) => {
        document.querySelectorAll('[data-script-obj]').forEach((c) => { c.checked = e.target.checked; });
    });

    // ── generate + download ─────────────────────────────────────────────
    $('scriptGenerate')?.addEventListener('click', async (e) => {
        const picked = selected();
        const all = objects.filter(inScope).map((o) => o.name);
        // If everything in the scope is ticked, send an empty list so the server
        // exports the full scope (also covers objects added since the modal opened).
        const tables = picked.length === all.length ? [] : picked;
        if (picked.length === 0) { Swal.fire('Nothing selected', 'Tick at least one table to export.', 'info'); return; }

        const payload = {
            scope: scope(),
            mode: mode(),
            rowLimit: Math.max(0, parseInt($('scriptRowLimit').value, 10) || 0),
            tables: tables,
            dropTable: $('scriptDropTable').checked,
            ifNotExists: $('scriptIfNotExists').checked,
            disableForeignKeys: $('scriptDisableFks').checked,
            transaction: $('scriptTransaction').checked,
            extendedInsert: $('scriptExtended').checked,
            comments: $('scriptComments').checked,
            targetType: ($('scriptTarget') && $('scriptTarget').value) || '',
            _token: csrf,
        };
        const btn = e.currentTarget;
        busy(btn, true, 'Generating…');
        try {
            const res = await fetch(`${base}/project/${encodeURIComponent(card.dataset.projectSlug)}/script/generate`, {
                method: 'POST', credentials: 'same-origin',
                headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload),
            });
            const ct = res.headers.get('Content-Type') || '';
            if (!res.ok || ct.indexOf('application/sql') === -1) {
                const j = await res.json().catch(() => ({ message: 'The script could not be generated.' }));
                throw new Error(j.message || 'The script could not be generated.');
            }
            const blob = await res.blob();
            const filename = res.headers.get('X-Script-Filename') || ((card.dataset.projectSlug || 'export') + '.sql');
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove();
            setTimeout(() => URL.revokeObjectURL(url), 4000);
            const tCount = res.headers.get('X-Script-Tables') || '0';
            const rCount = res.headers.get('X-Script-Rows') || '0';
            const kb = Math.max(1, Math.round(blob.size / 1024));
            Swal.fire({ icon: 'success', title: 'Script downloaded',
                html: '<div style="text-align:left;font-size:.9rem">' + esc(filename) + '<br>' +
                      '<b>' + esc(tCount) + '</b> object(s) · <b>' + fmt(rCount) + '</b> row(s) · ' + fmt(kb) + ' KB</div>' });
        } catch (err) {
            Swal.fire('Generation failed', err.message, 'error');
        } finally {
            busy(btn, false);
        }
    });
})();
