// add-row.js — new-row creation.
//
// Two paths, chosen by the table's schema:
//   - Record-tables (identity composed from required fields that aren't
//     columns — e.g. the risk register's tracking-number components): "+ Add
//     row" navigates to the compose form (<dir>/form.html), the only place
//     those components can be supplied. See needsComposeForm().
//   - Simple tables (all required fields are columns): "+ Add row" appends a
//     draft row at the end of state.rows, focuses its first editable cell, and
//     accumulates typing into the drafts buffer like any other row. On
//     row-blur, save.js detects row.isNew and POSTs to <dir>/form.html; the
//     201 Location swaps the synthetic url and the draft becomes a saved row.
//
// Synthetic identity: each new row gets a temporary "__new-<N>" url
// so rowKey() returns something unique for selection + draft tracking.
// The temporary url is replaced after a successful POST. There is no
// "save on click" UX — the existing row-blur trigger is the save path,
// same as for edits.
(function (app) {
    'use strict';

    let _counter = 0;

    function makeSyntheticKey() {
        _counter += 1;
        return '__new-' + _counter;
    }

    // Compute the form-create URL for the current page. Both
    // /<dir>/table.html and /<dir>/ (default_tool: tables) shape work;
    // /<dir>/form.html is the form handler's "create" endpoint either
    // way (the form handler keys off the in-dir convention, not the
    // visiting URL shape).
    function formCreateUrl() {
        let dir = (location.pathname || '/').replace(/\/table\.html$/, '/');
        if (!dir.endsWith('/')) dir += '/';
        return dir + 'form.html';
    }

    // True when a new record's identity is composed from required fields that
    // AREN'T table columns (e.g. the risk register's project/discipline/
    // sequence tracking-number components). Such rows can't be created by
    // typing into the grid — they need the compose form. Server mode only
    // (the form handler is server-side).
    function needsComposeForm() {
        const ctx = app.context || {};
        if (!app.state || app.state.source !== 'server') return false;
        const req = (ctx.rowSchema && Array.isArray(ctx.rowSchema.required)) ? ctx.rowSchema.required : [];
        if (!req.length) return false;
        const colFields = {};
        (ctx.columns || []).forEach(function (c) { if (c && c.field) colFields[c.field] = true; });
        return req.some(function (f) { return !colFields[f]; });
    }

    // Create-and-paint: the user-facing path. Record-tables (composed identity)
    // open the compose form directly — the grid can't supply their
    // tracking-number components; simple tables append an inline draft row.
    function invoke() {
        if (needsComposeForm()) {
            window.location.href = formCreateUrl();
            return;
        }
        const key = createSilent();
        if (typeof app.repaint === 'function') app.repaint();
        focusNewRow(key);
    }

    // Push a draft row WITHOUT painting or focusing. Used by multi-row
    // paste (clipboard.js) to create N rows in a single batch, with one
    // paint at the end. Returns the synthetic url so callers can address
    // the new row in their draft writes.
    function createSilent() {
        const key = makeSyntheticKey();
        const draftRow = {
            url: key,
            yamlUrl: null,
            data: {},
            etag: null,
            editable: true,
            isNew: true,
        };
        if (!Array.isArray(app.state.rows)) {
            app.state.rows = [];
        }
        app.state.rows.push(draftRow);
        return key;
    }

    function focusNewRow(key) {
        // After repaint, find the tr with our synthetic data-row-id and
        // tell the editor to select its first cell. Filtering may have
        // hidden the new row if a default filter excludes it; we accept
        // that — clearing filters surfaces it.
        const tbody = document.querySelector('#table-root tbody');
        if (!tbody) return;
        const trs = tbody.querySelectorAll('tr');
        for (let i = 0; i < trs.length; i++) {
            if (trs[i].getAttribute('data-row-id') === key) {
                const editor = app.modules.editor;
                if (editor && typeof editor.setSelected === 'function') {
                    // Scroll into view so the user sees the new row.
                    trs[i].scrollIntoView({ block: 'nearest', behavior: 'auto' });
                    editor.setSelected(i, 0);
                }
                return;
            }
        }
    }

    // Cancel-new-row helper: drop the synthetic row entirely. Used when
    // the user adds a row, makes no edits, and clicks Add again or
    // navigates away — there's nothing to save and an empty draft just
    // clutters the table. The save module calls this from row-blur when
    // it sees a new row with no drafts.
    function discardEmpty(rowId) {
        const rows = app.state.rows || [];
        for (let i = 0; i < rows.length; i++) {
            if (rows[i].isNew && rows[i].url === rowId) {
                rows.splice(i, 1);
                if (typeof app.repaint === 'function') app.repaint();
                return true;
            }
        }
        return false;
    }

    app.modules.addRow = {
        invoke: invoke,
        createSilent: createSilent,
        formCreateUrl: formCreateUrl,
        discardEmpty: discardEmpty,
    };
})(window.tablesApp);
