<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Commerce\Catalog;

use CpCreation\VitiCore\Cart\CartService;
use CpCreation\VitiCore\Commerce\Catalog\Api\Resource\CatalogAvailability;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductVariant;
use CpCreation\VitiCore\Shop\Model\ShopConfig;

final readonly class CatalogInventoryResolver
{
    public function __construct(private CartService $cartService) {}

    public function resolve(
        Product $product,
        ProductVariant $variant,
        ?ShopConfig $shopConfig,
        bool $hasPublicPrice,
        bool $productPublished,
        bool $hasPurchaseUrl,
        \DateTimeImmutable $now,
    ): CatalogAvailability {
        $quantity = $this->cartService->getRemainingStockForVariant($variant);
        $reasons = [];
        $outOfStock = false;

        if ($product->isSoldOut()) {
            $reasons[] = 'product_sold_out';
            $outOfStock = true;
        }
        if ($variant->isSoldOut()) {
            $reasons[] = 'variant_sold_out';
            $outOfStock = true;
        }
        if (null !== $quantity && $quantity <= 0) {
            $reasons[] = 'stock_exhausted';
            $outOfStock = true;
        }
        if (!$hasPublicPrice) {
            $reasons[] = 'public_price_missing';
        }
        if (!$productPublished) {
            $reasons[] = 'product_not_published';
        }
        if (!$hasPurchaseUrl) {
            $reasons[] = 'purchase_url_missing';
        }
        if (true === $shopConfig?->isHidePriceDefault()) {
            $reasons[] = 'price_hidden';
        }
        if (true === $shopConfig?->isOrderingDisabledForVacation($now)) {
            $reasons[] = 'ordering_paused';
        }
        if (true === $shopConfig?->isShopDisabledForVacation($now)) {
            $reasons[] = 'shop_paused';
        }

        $orderable = [] === $reasons;

        return new CatalogAvailability(
            status: $outOfStock ? 'out_of_stock' : 'in_stock',
            orderable: $orderable,
            tracked: null !== $variant->getStock(),
            quantity: $quantity,
            as_of: $now->format(\DATE_ATOM),
            reasons: $reasons,
        );
    }
}
