<?php

namespace SoftminalB2B\Pricing;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Who sells a product.
 *
 * On a single-merchant store every product belongs to the shop, so this always
 * resolves to 0 (no vendor). On a marketplace the vendor is the product's
 * author: Dokan (and WholesaleX's bridge) stamp the seller as `post_author`.
 * Core exposes the resolution behind the `smb2b_product_vendor_id` filter so the
 * Dokan bridge — or a future WCFM/MVX bridge — can override it in one place
 * without any other part of the suite learning marketplace specifics.
 *
 * A variation's author is unreliable, so variations resolve to their parent
 * product before the author is read.
 */
class ProductVendor
{
    /** @var array<int, int> Per-request memo, keyed by the resolved product id. */
    private static array $memo = [];

    /**
     * The vendor (seller) WP user id for a product or variation, or 0 when the
     * product has no distinct vendor (a single-merchant store, or an
     * admin-owned product).
     */
    public static function for(int $productId, ?int $variationId = null): int
    {
        // A variation inherits its parent's vendor — resolve to the parent id
        // before reading authorship, since variation post_author is not stamped.
        $resolvedId = $variationId ? self::parentId($variationId) : $productId;

        if ($resolvedId <= 0) {
            return 0;
        }

        if (array_key_exists($resolvedId, self::$memo)) {
            return self::$memo[$resolvedId];
        }

        $default = (int) get_post_field('post_author', $resolvedId);

        /**
         * The vendor (seller) user id that owns this product. Default is the
         * product's `post_author` (how Dokan and WholesaleX identify the seller).
         * Return 0 for "no vendor". A marketplace bridge overrides this to plug
         * in its own vendor resolution (e.g. WCFM's store mapping).
         *
         * @param int $vendorId  Resolved vendor id (post_author by default).
         * @param int $productId The parent product id (variations already resolved).
         */
        $vendorId = (int) apply_filters('smb2b_product_vendor_id', $default, $resolvedId);

        return self::$memo[$resolvedId] = max(0, $vendorId);
    }

    /**
     * The parent product id for a variation, or the id itself when it is not a
     * variation. Falls back to WooCommerce's product object so it stays correct
     * under any storage backend.
     */
    private static function parentId(int $variationId): int
    {
        $parent = (int) wp_get_post_parent_id($variationId);

        if ($parent > 0) {
            return $parent;
        }

        $product = wc_get_product($variationId);

        if ($product instanceof \WC_Product) {
            $parentId = $product->get_parent_id();

            return $parentId > 0 ? $parentId : $variationId;
        }

        return $variationId;
    }

    /**
     * Drop the per-request memo. For tests and the "view as" preview seam.
     */
    public static function flush(): void
    {
        self::$memo = [];
    }
}
