<?php

namespace App\Services;

use App\Models\Catalog\Product;
use App\Models\Catalog\ProductUnit;

/**
 * Converts a transaction-entered quantity (e.g. "1 BOX") into the product's
 * base-unit quantity that StockMovementService::record() expects.
 *
 * Products with no `product_units` rows configured fall back to a 1:1
 * conversion against their own base unit — this keeps every product that
 * predates unit-of-measure support working unchanged (plan decision A3).
 */
class UnitConversionService
{
    /** @var array<string, ?ProductUnit> */
    private array $unitCache = [];

    public function toBaseUnit(Product $product, int $unitId, float $quantity): float
    {
        if ($unitId === (int) $product->base_unit_id) {
            return $quantity;
        }

        $productUnit = $this->findProductUnit($product, $unitId);

        $factor = $productUnit ? (float) $productUnit->conversion_factor : 1.0;

        return $quantity * $factor;
    }

    public function defaultSaleUnit(Product $product): ?ProductUnit
    {
        return ProductUnit::query()
            ->where('product_id', $product->id)
            ->where('is_default_sale_unit', true)
            ->first();
    }

    private function findProductUnit(Product $product, int $unitId): ?ProductUnit
    {
        $key = $product->id.':'.$unitId;
        if (array_key_exists($key, $this->unitCache)) {
            return $this->unitCache[$key];
        }

        return $this->unitCache[$key] = ProductUnit::query()
            ->where('product_id', $product->id)
            ->where('unit_id', $unitId)
            ->first();
    }
}
