/** @odoo-module
 *
 * PosOrder patch — laundry context fields.
 *
 * Two responsibilities:
 *   1. setup(): seed primitive defaults on the reactive proxy so that
 *      OWL components (panel, receipt) which read these slots track
 *      future writes and re-render. Without seeding, assigning a fresh
 *      property after first render does NOT trigger reactivity.
 *      No fields are pulled from the loader — pure in-memory defaults.
 *
 *   2. serializeForORM(): inject the laundry slots into the sync_from_ui
 *      payload so the backend pos.order columns are populated, exactly
 *      like `general_customer_note`.
 *      - laundry_order_type_id        → integer id  (Many2one)
 *      - laundry_order_attribute_ids  → [[6, 0, ids]]  (Many2many "set")
 *      - laundry_is_delivery          → boolean
 *      - laundry_delivery_address     → string | false
 *      - laundry_delivery_scheduled_at → string | false
 *
 * NOTE: this patch does NOT touch order.lines, pricing, taxes, or any
 * relational field exposed by _load_pos_data_fields.
 */
import { patch } from "@web/core/utils/patch";
import { PosOrder } from "@point_of_sale/app/models/pos_order";

function pickId(v) {
    if (!v) return false;
    if (typeof v === "number") return v;
    if (typeof v === "object" && Number.isInteger(v.id)) return v.id;
    return false;
}

function pickIds(arr) {
    if (!Array.isArray(arr)) return [];
    const out = [];
    const seen = new Set();
    for (const v of arr) {
        const id = pickId(v);
        if (id && !seen.has(id)) {
            seen.add(id);
            out.push(id);
        }
    }
    return out;
}

function normalizeDateTime(value) {
    if (!value || typeof value !== "string") return false;

    let v = value;

    // Remove timezone like +03:00 or -03:00
    const tzMatch = v.match(/([+-]\d{2}:\d{2})$/);
    if (tzMatch) {
        v = v.replace(tzMatch[0], "");
    }

    // Remove Z
    if (v.endsWith("Z")) {
        v = v.slice(0, -1);
    }

    // Remove milliseconds
    if (v.includes(".")) {
        v = v.split(".")[0];
    }

    // Replace T with space
    v = v.replace("T", " ");

    // Ensure seconds exist
    if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(v)) {
        v += ":00";
    }

    return v;
}

patch(PosOrder.prototype, {
    setup(...args) {
        super.setup(...args);
        // Seed defaults on the reactive proxy. Assigning after first
        // render only triggers OWL reactivity if the key already exists
        // on the proxy at observation time.
        if (this.laundry_order_type_id === undefined) {
            this.laundry_order_type_id = false;
        }
        if (this.laundry_order_attribute_ids === undefined) {
            this.laundry_order_attribute_ids = [];
        }
        if (this.laundry_is_delivery === undefined) {
            this.laundry_is_delivery = false;
        }
        if (this.laundry_delivery_address === undefined) {
            this.laundry_delivery_address = false;
        }
        if (this.laundry_delivery_scheduled_at === undefined) {
            this.laundry_delivery_scheduled_at = false;
        }
    },

    initState(...args) {
        super.initState(...args);
        // Reactive flag for POS Mode system: when true, the order is a
        // dedicated settlement context — products cannot be added,
        // quantities cannot be edited, line cannot be deleted.
        // Seeded here so OWL reactivity tracks future writes.
        if (this.uiState && !("is_laundry_settle_due" in this.uiState)) {
            this.uiState.is_laundry_settle_due = false;
        }
    },

    serializeForORM(opts = {}) {
        const data = super.serializeForORM(opts);

        const typeId = pickId(this.laundry_order_type_id);
        data.laundry_order_type_id = typeId || false;

        const attrIds = pickIds(this.laundry_order_attribute_ids);
        data.laundry_order_attribute_ids = [[6, 0, attrIds]];

        data.laundry_is_delivery = !!this.laundry_is_delivery;
        data.laundry_delivery_address = this.laundry_delivery_address || false;
        // ABSOLUTE GUARANTEE: nothing with a "T", ".000", or timezone reaches
        // the backend. Run the full normalizer even if upstream already did;
        // normalize(normalize(x)) === normalize(x), so this is a zero-cost net.
        data.laundry_delivery_scheduled_at =
            normalizeDateTime(this.laundry_delivery_scheduled_at) || false;

        return data;
    },
});
