<?php

namespace Modules\Vrc\Services\Adapters\Erp;

use App\Utils\ProductUtil;
use App\VariationLocationDetails;
use Illuminate\Support\Facades\DB;
use Modules\Vrc\Entities\VrcRepairOrder;
use Modules\Vrc\Entities\VrcRepairOrderPart;
use Modules\Vrc\Services\Contracts\StockServiceContract;

/**
 * ERP adapter: consumes ERP stock through ProductUtil and reads availability
 * from variation_location_details. Repair invoices are header-level service
 * invoices (no ERP sell lines), so stock is consumed here exactly once per
 * part line — idempotent via the erp_stock_movement_id marker.
 */
class ErpStockService implements StockServiceContract
{
    public function __construct(protected ProductUtil $productUtil)
    {
    }

    public function consumeForOrder(VrcRepairOrder $ro): int
    {
        $locationId = (int) ($ro->location_id ?: 0);
        $consumed = 0;

        DB::transaction(function () use ($ro, $locationId, &$consumed) {
            $parts = VrcRepairOrderPart::where('repair_order_id', $ro->id)
                ->where('source', 'stock')
                ->whereNull('erp_stock_movement_id')
                ->whereNotNull('erp_product_id')
                ->whereNotNull('erp_variation_id')
                ->lockForUpdate()->get();

            foreach ($parts as $part) {
                $this->productUtil->decreaseProductQuantity(
                    (int) $part->erp_product_id,
                    (int) $part->erp_variation_id,
                    $locationId,
                    (float) $part->qty
                );
                // Mark consumed; reference the invoice if present, else the order.
                $part->update(['erp_stock_movement_id' => $ro->erp_invoice_id ?: $ro->id]);
                $consumed++;
            }
        });

        return $consumed;
    }

    public function available(int $businessId, int $productId, int $variationId, int $locationId): float
    {
        $row = VariationLocationDetails::where('product_id', $productId)
            ->where('variation_id', $variationId)
            ->where('location_id', $locationId)
            ->first();

        return $row ? (float) $row->qty_available : 0.0;
    }

    public function lowStock(int $businessId, ?int $locationId = null, int $limit = 10): array
    {
        return VariationLocationDetails::join('products as p', 'p.id', '=', 'variation_location_details.product_id')
            ->where('p.business_id', $businessId)
            ->where('p.enable_stock', 1)
            ->whereColumn('variation_location_details.qty_available', '<=', 'p.alert_quantity')
            ->when($locationId, fn ($q) => $q->where('variation_location_details.location_id', $locationId))
            ->select(['p.name', 'variation_location_details.qty_available', 'p.alert_quantity'])
            ->orderBy('variation_location_details.qty_available')
            ->limit($limit)->get()->toArray();
    }
}
