/**
 * Alpine factory for the Stock Take (cycle count) editor.
 *
 * Owns the spreadsheet-like rows array, the live KPI / variance math,
 * and the submit-guard for the Post button. Lines submit via plain
 * `<input>` rows named `items[i][...]` so the server controller doesn't
 * need a JSON endpoint.
 *
 * `counted` is intentionally a string (so empty means "skipped") — the
 * server-side UpdateStockTake reads `'' / null` as "skipped" and
 * persists `counted_quantity` as NULL.
 */
export function stockTakeEditor({ rows = [] } = {}) {
    return {
        rows,

        /** Signed variance for one row. Returns 0 for skipped rows so
         *  the KPI math doesn't get NaN. */
        variance(r) {
            if (r.counted === '' || r.counted === null) return 0;
            return (parseFloat(r.counted) || 0) - (parseFloat(r.expected) || 0);
        },

        /** Lines the operator has touched (counted_quantity is not blank). */
        get countedLines() {
            return this.rows.filter(r => r.counted !== '' && r.counted !== null).length;
        },

        /** Lines that will actually emit a movement on post. */
        get varianceLines() {
            return this.rows.filter(r => {
                if (r.counted === '' || r.counted === null) return false;
                return Math.abs(this.variance(r)) > 0.00005;
            }).length;
        },

        /** Sum of every variance — informational only, the ledger
         *  doesn't care about the aggregate. */
        get netVariance() {
            return this.rows.reduce((s, r) => s + this.variance(r), 0);
        },

        get hasAnyCount() {
            return this.countedLines > 0;
        },

        /** Quantity formatting — defers to the system-wide posFormatQty
         *  (which respects currency-decimals + locale) when present. */
        formatQty(v) {
            const n = parseFloat(v) || 0;
            return window.posFormatQty ? window.posFormatQty(n) : n.toString();
        },

        /** Variance with explicit sign and quasi-zero collapsed to '0'. */
        formatVariance(v) {
            const n   = parseFloat(v) || 0;
            const fmt = this.formatQty(Math.abs(n));
            if (n < -0.00005) return '−' + fmt;
            if (n >  0.00005) return '+' + fmt;
            return '0';
        },
    };
}
