<?php

namespace App\Domains\Purchase\Services\Checkout;

use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Inventory;
use App\Domains\Catalog\Models\Variant;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class CatalogSelectionResolver
{
    public function resolve(
        Tenant $tenant,
        int $catalogItemId,
        ?int $variantId,
        string $fieldPrefix = 'direct_items',
    ): CatalogItem|Variant {
        /** @var CatalogItem|null $catalogItem */
        $catalogItem = CatalogItem::query()
            ->whereKey($catalogItemId)
            ->where('tenant_code', $tenant->codigo)
            ->lockForUpdate()
            ->first();

        if ($catalogItem === null) {
            throw new NotFoundHttpException('Catalog item not found for tenant.');
        }

        if ($catalogItem->isBundle()) {
            if ($variantId !== null) {
                throw ValidationException::withMessages([
                    "{$fieldPrefix}.variant_id" => __('api.cart.bundle_variant_forbidden'),
                ]);
            }

            if (! $catalogItem->bundleComponents()->exists()) {
                throw ValidationException::withMessages([
                    "{$fieldPrefix}.catalog_item_id" => __('api.cart.empty_bundle'),
                ]);
            }

            return $catalogItem;
        }

        if ($variantId === null) {
            if ($catalogItem->inventory_id === null) {
                throw ValidationException::withMessages([
                    "{$fieldPrefix}.variant_id" => __('api.cart.variant_required'),
                ]);
            }

            $catalogItem->setRelation(
                'inventory',
                Inventory::query()->whereKey($catalogItem->inventory_id)->lockForUpdate()->firstOrFail(),
            );

            return $catalogItem;
        }

        /** @var Variant|null $variant */
        $variant = Variant::query()
            ->whereKey($variantId)
            ->where('catalog_item_id', $catalogItem->id)
            ->lockForUpdate()
            ->first();

        if ($variant === null) {
            throw new NotFoundHttpException('Variant not found for catalog item.');
        }

        $variant->setRelation('catalogItem', $catalogItem);
        $variant->setRelation(
            'inventory',
            Inventory::query()->whereKey($variant->inventory_id)->lockForUpdate()->firstOrFail(),
        );

        return $variant;
    }
}
