<?php

namespace App\Support;

use App\Models\FactoryProduct;
use App\Models\StockMovement;

class NonSaleableFinishedGoodsStock
{
    /**
     * @param  array{
     *     type: string,
     *     reference_type?: class-string|null,
     *     reference_id?: int|null,
     *     notes?: string|null
     * }|null  $movement
     */
    public static function adjustDefective(int $productId, float $delta, ?array $movement = null): void
    {
        self::adjust($productId, 'defective_stock', StockMovementType::SALE_RETURN_DEFECTIVE, $delta, $movement);
    }

    /**
     * @param  array{
     *     type: string,
     *     reference_type?: class-string|null,
     *     reference_id?: int|null,
     *     notes?: string|null
     * }|null  $movement
     */
    public static function adjustExpired(int $productId, float $delta, ?array $movement = null): void
    {
        self::adjust($productId, 'expired_stock', StockMovementType::SALE_RETURN_EXPIRED, $delta, $movement);
    }

    /**
     * @param  array{
     *     type: string,
     *     reference_type?: class-string|null,
     *     reference_id?: int|null,
     *     notes?: string|null
     * }|null  $movement
     */
    private static function adjust(
        int $productId,
        string $column,
        string $movementType,
        float $delta,
        ?array $movement = null,
    ): void {
        if (abs($delta) < 0.0000001) {
            return;
        }

        $product = FactoryProduct::query()
            ->whereKey($productId)
            ->lockForUpdate()
            ->first();

        if ($product === null) {
            return;
        }

        $product->{$column} = round(max(0, (float) $product->{$column} + $delta), 3);
        $product->save();

        StockMovement::record(
            StockKind::FINISHED_GOODS,
            $productId,
            $delta,
            (float) $product->{$column},
            array_merge(['type' => $movementType], $movement ?? []),
        );
    }
}
