/** @odoo-module
 *
 * PaymentScreen patch — minimal laundry behaviors:
 *   1. Settlement orders: hide pay-later methods, custom validateOrder
 *      that calls settle_laundry_dues_rpc and bypasses normal sync.
 *   2. Legacy laundry orders: trigger order-type popup at payment time
 *      (NOT on add-line). Block payment if type is required and missing.
 *
 * STRICT CONTRACT:
 *   - Does NOT touch order.lines, pricing, taxes
 *   - Does NOT override PosOrder.setup
 *   - Selections stored as primitives only (handled in pos_store_patch.js)
 *   - For non-laundry orders, super.validateOrder runs unchanged.
 */
import { patch } from "@web/core/utils/patch";
import { _t } from "@web/core/l10n/translation";
import { PaymentScreen } from "@point_of_sale/app/screens/payment_screen/payment_screen";
import { AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { LaundrySettlementReceipt } from "@laundry_management/js/settlement_receipt";

function isSettlementOrder(order) {
    return (
        order &&
        order.lines &&
        order.lines.some(
            (line) => line.product_id?.product_tmpl_id?.is_laundry_settlement
        )
    );
}

patch(PaymentScreen.prototype, {
    setup() {
        super.setup(...arguments);
        // For settlement orders, hide Customer Account / pay-later methods.
        if (isSettlementOrder(this.currentOrder)) {
            this.payment_methods_from_config =
                this.payment_methods_from_config.filter(
                    (pm) => !pm.split_transactions
                );
        }
    },

    /**
     * Pre-payment gate for the legacy laundry order-type flow.
     *   - true  → continue with payment
     *   - false → block payment
     *
     * Skipped for: feature disabled, settlement orders, non-laundry orders,
     * and orders that already have a type. If required + missing, opens the
     * popup; blocks if the user closes/cancels.
     */
    async beforePaymentFlow(order) {
        const pos = this.pos;
        const config = pos.config;
        if (!order || !config?.enable_laundry_order_type) {
            return true;
        }
        if (isSettlementOrder(order)) {
            return true;
        }
        if (!pos.orderHasLaundryServiceLine(order)) {
            return true;
        }
        if (order.laundry_order_type_id) {
            return true;
        }
        await pos.runLaundryOrderTypeFlow(order);
        if (config.require_laundry_order_type && !order.laundry_order_type_id) {
            pos.notification.add(
                _t("Order type is required to proceed to payment."),
                { type: "warning" }
            );
            return false;
        }
        return true;
    },

    async validateOrder(isForceValidate) {
        const order = this.currentOrder;

        // ── Settlement validation — bypass normal POS sync ──
        if (isSettlementOrder(order)) {
            return this._validateSettlementOrder(order);
        }

        // ── Legacy laundry order-type gate ──
        const allowed = await this.beforePaymentFlow(order);
        if (!allowed) {
            return false;
        }

        return super.validateOrder(isForceValidate);
    },

    async _validateSettlementOrder(order) {
        const paymentLines = order.payment_ids
            .filter((pl) => pl.getAmount() > 0)
            .map((pl) => ({
                pos_payment_method_id: pl.payment_method_id.id,
                amount: pl.getAmount(),
            }));

        if (paymentLines.length === 0) {
            this.notification.add(
                _t("Please add at least one payment."),
                { type: "warning" }
            );
            return false;
        }

        const partnerId = order.partner_id?.id;
        if (!partnerId) {
            this.notification.add(_t("No customer selected."), {
                type: "danger",
            });
            return false;
        }

        const sessionId = this.pos.session?.id || null;

        let response;
        try {
            this.ui.block();
            response = await this.pos.data.call(
                "res.partner",
                "settle_laundry_dues_rpc",
                [partnerId, paymentLines, sessionId]
            );
        } catch (err) {
            this.dialog.add(AlertDialog, {
                title: _t("Settlement Failed"),
                body:
                    err?.data?.message ||
                    err?.message ||
                    _t("Unknown error."),
            });
            return false;
        } finally {
            this.ui.unblock();
        }

        if (
            order.payment_ids.some(
                (pl) => pl.payment_method_id.is_cash_count && pl.getAmount() > 0
            )
        ) {
            this.pos.hardwareProxy.openCashbox();
        }

        this.dialog.add(LaundrySettlementReceipt, {
            partnerName: order.partner_id.name,
            settledTotal: response.settled_total || 0,
            remainingDue: response.remaining_due || 0,
            payments: response.payments || [],
            settledOrders: response.settled_orders || [],
        });

        this.pos._lastSettlementMethodId =
            paymentLines[0]?.pos_payment_method_id || null;

        this.pos.removeOrder(order, false);
        this.pos.addNewOrder();
        this.pos.navigate("ProductScreen");
        return true;
    },
});
