<?php

declare(strict_types=1);

namespace App\Business\Product;

use App\Models\DberpProduct;
use App\Models\DberpProductSku;
use App\Support\DberpLineProductSkuFormFields;
use Illuminate\Validation\ValidationException;

/**
 * 库存过账：优先使用单据行上的规格组合（product_sku_id），必要时回退到 {@see LedgerProductSkuResolver}。
 */
final class InventoryPostingProductSkuResolver
{
    /**
     * 已启用规格矩阵且存在多条可用规格组合时，禁止在未显式选择规格的情况下走默认解析。
     */
    public static function productRequiresExplicitSkuBeforeDefault(DberpProduct $product): bool
    {
        return (bool) $product->spec_enabled
            && DberpLineProductSkuFormFields::enabledSkuCountForProduct((int) $product->getKey()) > 1;
    }

    /**
     * @param  ?int  $lineProductSkuId  业务行上的规格组合主键；可空表示由规则回退。
     */
    public static function resolveSkuForPosting(DberpProduct $product, ?int $lineProductSkuId, string $validationAttribute = 'items'): DberpProductSku
    {
        if ($lineProductSkuId !== null && $lineProductSkuId > 0) {
            return self::resolveExplicitSkuForProduct($product, $lineProductSkuId, $validationAttribute);
        }

        if (self::productRequiresExplicitSkuBeforeDefault($product)) {
            throw ValidationException::withMessages([
                $validationAttribute => (string) __('dberp.errors.inventory_posting_spec_required_before_posting'),
            ]);
        }

        return LedgerProductSkuResolver::defaultSkuForProductInventoryLine($product);
    }

    public static function resolveExplicitSkuForProduct(DberpProduct $product, int $productSkuId, string $validationAttribute = 'items'): DberpProductSku
    {
        $sku = DberpProductSku::query()
            ->whereKey($productSkuId)
            ->where('product_id', $product->getKey())
            ->where('is_enabled', true)
            ->first();

        if (! $sku instanceof DberpProductSku) {
            throw ValidationException::withMessages([
                $validationAttribute => (string) __('dberp.errors.inventory_posting_line_spec_invalid'),
            ]);
        }

        return $sku;
    }
}
