import { ShopTradePolicyRegistry } from "./ShopTradePolicyRegistry.js";

export class ShopQuoteService {
    static async quoteCustomerPurchase({ shop, row, product } = {}) {
        const listedAmount = this.#amount(product?.price?.amount);
        const basisAmount = row?.priceOverride === null || row?.priceOverride === undefined
            ? listedAmount
            : this.#amount(row.priceOverride);
        const defaultAmount = Math.max(0, Math.round(
            basisAmount * Number(shop?.configuration?.customerPurchaseMultiplier ?? 1)
        ));
        const policy = this.#policy(shop);
        const result = policy?.quoteCustomerPurchase
            ? await policy.quoteCustomerPurchase({ shop, row, product, listedAmount, basisAmount, defaultAmount })
            : null;
        return this.#finalize({
            result,
            listedAmount,
            basisAmount,
            defaultAmount,
            direction: "purchase",
            policyApplied: Boolean(policy),
            defaultDisposition: "stock"
        });
    }

    static async quoteCustomerSale({ shop, item, actor, adapterQuote } = {}) {
        const listedAmount = this.#amount(adapterQuote?.baseAmount);
        if (!adapterQuote?.eligible) {
            return {
                allowed: false,
                reason: adapterQuote?.reason || `${item?.name || "This item"} cannot be sold here.`,
                listedAmount,
                basisAmount: listedAmount,
                amount: 0,
                disposition: "stock",
                priceClass: "is-price-rejected"
            };
        }
        const defaultAmount = Math.max(0, Math.floor(
            listedAmount * Number(shop?.configuration?.customerSaleMultiplier ?? 0.75)
        ));
        const policy = this.#policy(shop);
        const productReference = this.#productReference(item);
        const result = policy?.quoteCustomerSale
            ? await policy.quoteCustomerSale({
                shop, item, actor, productReference, listedAmount,
                basisAmount: listedAmount, defaultAmount
            })
            : null;
        return this.#finalize({
            result,
            listedAmount,
            basisAmount: listedAmount,
            defaultAmount,
            direction: "sale",
            policyApplied: Boolean(policy),
            defaultDisposition: "stock"
        });
    }

    static #finalize({ result, listedAmount, basisAmount, defaultAmount, direction, policyApplied, defaultDisposition }) {
        const allowed = result?.allowed !== false;
        const disposition = result?.disposition === "consume" ? "consume" : defaultDisposition;
        if (!allowed) {
            return {
                allowed: false,
                reason: String(result?.reason || "This item is not accepted here."),
                listedAmount,
                basisAmount,
                amount: 0,
                disposition,
                priceClass: "is-price-rejected"
            };
        }
        const explicitAmount = Number(result?.amount);
        const multiplier = Number(result?.multiplier);
        const amount = Number.isFinite(explicitAmount)
            ? this.#amount(explicitAmount)
            : Number.isFinite(multiplier)
                ? this.#amount(defaultAmount * multiplier)
                : defaultAmount;
        let priceClass = "is-price-standard";
        if (policyApplied && amount !== listedAmount) {
            const favorable = direction === "purchase" ? amount < listedAmount : amount > listedAmount;
            priceClass = favorable ? "is-price-favorable" : "is-price-unfavorable";
        }
        return {
            allowed: true,
            reason: String(result?.reason || ""),
            listedAmount,
            basisAmount,
            amount,
            disposition,
            priceClass
        };
    }

    static #policy(shop) {
        return ShopTradePolicyRegistry.get(shop?.configuration?.tradePolicyId);
    }

    static #productReference(item) {
        try {
            return item?.getFlag?.("augur-nexus", "shopProduct")
                || item?.flags?.["augur-nexus"]?.shopProduct
                || null;
        } catch (_error) {
            return item?.flags?.["augur-nexus"]?.shopProduct || null;
        }
    }

    static #amount(value) {
        const amount = Number(value);
        return Number.isFinite(amount) ? Math.max(0, Math.round(amount)) : 0;
    }
}
