<?php

namespace App\Domains\Purchase\Services;

use App\Domains\Cart\Models\Cart;
use App\Domains\Catalog\Models\StockReservation;
use App\Domains\Purchase\Exceptions\PurchaseExpiredException;
use App\Domains\Purchase\Models\Purchase;
use Illuminate\Validation\ValidationException;

class PurchaseStateGuard
{
    public function assertNotExpired(Purchase $purchase): void
    {
        if ($purchase->status === Purchase::STATUS_EXPIRED) {
            throw new PurchaseExpiredException;
        }

        if (! in_array($purchase->status, [
            Purchase::STATUS_CREATED,
            Purchase::STATUS_PENDING_PAYMENT,
        ], true)) {
            return;
        }

        /** @var StockReservation|null $reservation */
        $reservation = $purchase->relationLoaded('stockReservation')
            ? $purchase->getRelation('stockReservation')
            : ($purchase->exists
                ? $purchase->stockReservation()->first()
                : null);

        if ($reservation !== null && (
            $reservation->status === StockReservation::STATUS_EXPIRED
            || (
                $reservation->status === StockReservation::STATUS_ACTIVE
                && $reservation->expires_at !== null
                && ! $reservation->expires_at->isFuture()
            )
        )) {
            throw new PurchaseExpiredException;
        }
    }

    public function lockCurrentCart(Purchase $purchase): Cart
    {
        /** @var Cart|null $cart */
        $cart = $purchase->cart()->withTrashed()->lockForUpdate()->first();

        if ($cart === null || $cart->current_purchase_id !== $purchase->getKey()) {
            throw ValidationException::withMessages([
                'purchase' => __('api.purchase.not_current'),
            ]);
        }

        return $cart;
    }
}
