<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Business\Inventory;

use App\Models\DberpInventoryBalance;
use App\Models\DberpInventoryRule;
use App\Support\DberpNumberFormatter;
use Illuminate\Database\Eloquent\Builder;

final class InventoryRuleEvaluatorService
{
    public function query(): Builder
    {
        return DberpInventoryRule::query()->with(['product', 'warehouse']);
    }

    /**
     * @return array<string, string|bool>
     */
    public function metrics(DberpInventoryRule $rule): array
    {
        $realtime = (float) DberpInventoryBalance::query()
            ->where('product_id', $rule->product_id)
            ->where('warehouse_id', $rule->warehouse_id)
            ->sum('realtime_quantity');
        $available = (float) DberpInventoryBalance::query()
            ->where('product_id', $rule->product_id)
            ->where('warehouse_id', $rule->warehouse_id)
            ->sum('available_quantity');
        $occupied = (float) DberpInventoryBalance::query()
            ->where('product_id', $rule->product_id)
            ->where('warehouse_id', $rule->warehouse_id)
            ->sum('occupied_quantity');
        $safetyStock = (float) $rule->safety_stock;
        $reorderPoint = (float) $rule->reorder_point;

        return [
            'realtime_quantity' => DberpNumberFormatter::quantity($realtime),
            'available_quantity' => DberpNumberFormatter::quantity($available),
            'occupied_quantity' => DberpNumberFormatter::quantity($occupied),
            'safety_stock' => DberpNumberFormatter::quantity($safetyStock),
            'reorder_point' => DberpNumberFormatter::quantity($reorderPoint),
            'is_low_stock' => $available <= $safetyStock && $available > 0,
            'is_zero_stock' => $realtime <= 0,
            'is_reorder_due' => $available <= $reorderPoint,
        ];
    }

    public function suggestedQuantity(DberpInventoryRule $rule): string
    {
        $metrics = $this->metrics($rule);
        $target = max((float) $rule->replenish_target_quantity, (float) $rule->reorder_point, (float) $rule->safety_stock);
        $available = (float) $metrics['available_quantity'];
        $suggested = max(0, $target - $available);

        return number_format($suggested, 4, '.', '');
    }
}
