<?php

namespace KupShop\FeedsBundle\Wrapper;

use KupShop\CatalogBundle\Util\RelatedProductsUtil;
use KupShop\ConvertorsBundle\Utils\ConvertorsUtil;
use KupShop\FeedsBundle\FeedProductCollection;
use KupShop\FeedsBundle\Utils\FeedUtils;
use KupShop\GraphQLBundle\ApiAdmin\Annotation\Module;
use KupShop\I18nBundle\Util\PriceConverter;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\UnitsBundle\Utils\MeasureUnitUtil;
use Query\Operator;
use Symfony\Contracts\Service\Attribute\Required;

class ProductWrapper extends BaseWrapper
{
    protected static $objectType = \Product::class;

    /** @var FeedProductCollection */
    protected $products;

    /**
     * @var ProductPriceWithLayersWrapper
     */
    protected $productPriceWrapper;

    /** @var PriceWrapper */
    protected $priceForDiscountWrapper;

    /**
     * @var PhotoWrapper
     */
    protected $photoWrapper;

    /**
     * @var PhotoWrapper
     */
    protected $producerPhotoWrapper;

    /** @var SectionWrapper */
    protected $sectionWrapper;
    /**
     * @var DeliveryWrapper
     */
    protected $deliveryWrapper;

    /** @var MultiWrapper */
    protected $sectionsWrapper;

    /** @var MultiWrapper */
    protected $photosWrapper;

    /** @var MultiWrapper */
    protected $variationPhotosWrapper;

    /** @var MultiWrapper */
    protected $giftsWrapper;

    protected MultiWrapper $setsWrapper;

    /** @var MultiWrapper */
    protected $blocksWrapper;

    /** @var ObjectMultiWrapper */
    protected $pricelistsWrapper;

    protected ObjectMultiWrapper $priceLevelsWrapper;

    protected ObjectMultiWrapper $templateWrapper;

    protected ObjectMultiWrapper $chargeWrapper;

    protected ObjectMultiWrapper $labelsWrapper;

    protected MultiWrapper $quantityDiscountsWrapper;

    /** @var CurrencyContext */
    protected $currencyContext;

    /** @var PriceConverter */
    protected $priceConverter;

    protected FeedUtils $feedUtils;

    /** @var array */
    protected $feedRow;

    protected ?ConvertorsUtil $convertorsUtil = null;
    protected ?MeasureUnitUtil $measureUnitUtil = null;

    protected RelatedProductsUtil $relatedProductsUtil;

    public function __construct(
        ProductPriceWithLayersWrapper $productPriceWrapper,
        PriceWrapper $priceForDiscountWrapper,
        PhotoWrapper $photoWrapper,
        SectionWrapper $sectionWrapper,
        DeliveryWrapper $deliveryWrapper,
        CurrencyContext $currencyContext,
        PriceConverter $priceConverter,
        SectionWrapperFactory $sectionWrapperFactory,
        PhotoWrapperFactory $photoWrapperFactory,
        GiftWrapperFactory $giftWrapperFactory,
        SetWrapperFactory $setWrapperFactory,
        BlockWrapper $blockWrapper,
        BlockWrapperFactory $blockWrapperFactory,
        PricelistWrapperFactory $pricelistWrapperFactory,
        PriceLevelsWrapperFactory $priceLevelsWrapperFactory,
        TemplateWrapperFactory $templateWrapperFactory,
        ChargeWrapperFactory $chargeWrapperFactory,
        LabelWrapperFactory $labelWrapperFactory,
        QuantityDiscountWrapper $quantityDiscountWrapper,
        QuantityDiscountWrapperFactory $quantityDiscountWrapperFactory,
        FeedUtils $feedUtils,
    ) {
        $this->productPriceWrapper = $productPriceWrapper;
        $this->priceForDiscountWrapper = $priceForDiscountWrapper;
        $this->photoWrapper = $photoWrapper;
        $this->producerPhotoWrapper = $photoWrapperFactory->create();
        $this->sectionWrapper = $sectionWrapper;
        $this->deliveryWrapper = $deliveryWrapper;
        $this->sectionsWrapper = new MultiWrapper($sectionWrapper, $sectionWrapperFactory);
        $this->photosWrapper = new MultiWrapper($photoWrapper, $photoWrapperFactory);
        $this->variationPhotosWrapper = new MultiWrapper($photoWrapperFactory->create(), $photoWrapperFactory);
        $this->giftsWrapper = new ObjectMultiWrapper($giftWrapperFactory);
        $this->setsWrapper = new MultiWrapper($setWrapperFactory->create(), $setWrapperFactory);
        $this->currencyContext = $currencyContext;
        $this->priceConverter = $priceConverter;
        $this->blocksWrapper = new MultiWrapper($blockWrapper, $blockWrapperFactory);
        $this->pricelistsWrapper = new ObjectMultiWrapper($pricelistWrapperFactory);
        $this->priceLevelsWrapper = new PriceLevelsWrapper($priceLevelsWrapperFactory);
        $this->templateWrapper = new ObjectMultiWrapper($templateWrapperFactory);
        $this->chargeWrapper = new ObjectMultiWrapper($chargeWrapperFactory);
        $this->labelsWrapper = new ObjectMultiWrapper($labelWrapperFactory);
        $this->quantityDiscountsWrapper = new MultiWrapper($quantityDiscountWrapper, $quantityDiscountWrapperFactory);
        $this->feedUtils = $feedUtils;
    }

    /**
     * @param array|null $feedRow
     *
     * @private
     */
    public function setFeedRow($feedRow)
    {
        $this->feedRow = $feedRow;
        $this->sectionWrapper->setFeedRow($feedRow);
    }

    /**
     * @private
     */
    public function setProductCollection(FeedProductCollection $products)
    {
        $this->products = $products;
    }

    /**
     * @private
     */
    #[Required]
    public function setConvertorsUtil(?ConvertorsUtil $convertorsUtil): void
    {
        $this->convertorsUtil = $convertorsUtil;
    }

    /**
     * @private
     */
    #[Required]
    public function setMeasureUnitUtil(?MeasureUnitUtil $measureUnitUtil): void
    {
        $this->measureUnitUtil = $measureUnitUtil;
    }

    /**
     * @private
     */
    #[Required]
    public function setRelatedProductsUtil(RelatedProductsUtil $relatedProductsUtil): void
    {
        $this->relatedProductsUtil = $relatedProductsUtil;
    }

    /** @var \Product */
    protected $object;

    /** SEO */
    public function field_seo()
    {
        $product = $this->object;

        return [
            'title' => $product->meta_title === '' ? $product->title : $product->meta_title,
            'description' => $product->meta_description,
        ];
    }

    /**
     * @module PRODUCTS_RELATED
     */
    public function field_related_products()
    {
        if (!isset($this->products->_related_products_fetched)) {
            $related = $this->relatedProductsUtil->getRelatedProductList($this->products->getProductIds());
            $qb = $related->getQueryBuilder()->select('p.title as title, p.ean as ean, p.code as code, 
                pr.id_top_product, pr.id_rel_product as related_id, pr.position');
            if (findModule(\Modules::PRODUCTS_RELATED, \Modules::SUB_TYPES)) {
                $qb->addSelect('GROUP_CONCAT(pr.type) as types');
            }

            $productsArray = $this->products->toArray();
            foreach ($qb->execute() as $row) {
                $id_top_product = $row['id_top_product'];
                unset($row['id_top_product']);
                $topProducts = array_filter($productsArray, function ($product) use ($id_top_product) {
                    return $product->id == $id_top_product;
                });
                foreach ($topProducts as $topProduct) {
                    $topProduct->related_products[] = $row;
                }
            }

            $this->products->_related_products_fetched = true;
        }

        return $this->object->related_products ?? [];
    }

    /** Název produktu */
    public function field_title()
    {
        return $this->object['fp_title'] ?? $this->object['title'];
    }

    /** Obecný název produktu */
    public function field_title_original()
    {
        return $this->object['title'];
    }

    /** Kód hlavního produktu, pod kterým jsou varianty */
    public function field_product_code(): ?string
    {
        return $this->object['product_code'] ?? null;
    }

    /** Kód produktu / varianty */
    public function field_code()
    {
        return $this->object->code;
    }

    /** Interní ID produktu */
    public function field_id()
    {
        return $this->object->id;
    }

    /** Interní ID varianty */
    public function field_variation_id()
    {
        return $this->object->variationId ?? '';
    }

    /** Jmenovky varianty. */
    public function field_variation()
    {
        $this->products->fetchVariationLabels();

        return !empty($this->object->variationLabels) ? $this->object->variationLabels : [];
    }

    /** CPC */
    public function field_cpc()
    {
        return $this->object['fp_cpc'] ?? $this->object['max_cpc'] ?? '';
    }

    /** Čas doručení */
    public function field_delivery_time()
    {
        return $this->object->deliveryTime;
    }

    /** EAN */
    public function field_ean()
    {
        return formatEAN($this->object->ean);
    }

    /** Hlavní sekce */
    public function field_section()
    {
        $this->products->fetchSections();
        $section = $this->object->sections[0] ?? false;
        if ($section) {
            $section = $this->sectionWrapper->setObject($section);
            $section->setProduct($this->object);
        }

        return $section;
    }

    /** Všechny sekce */
    public function field_sections()
    {
        $this->products->fetchSections();
        $this->sectionsWrapper->setObject($this->object->sections);

        return $this->sectionsWrapper;
    }

    /** Hlavní obrázek */
    public function field_main_photo()
    {
        return ($this->object->image['src'] ?? false) ? $this->photoWrapper->setObject($this->object->image) : null;
    }

    /** Dodatečné obrázky */
    public function field_photos()
    {
        $this->products->fetchPhotos('default_feed');
        $photos = $this->object->photos;
        // deduplicate photos
        if (findModule(\Modules::PRODUCTS_VARIATIONS_PHOTOS)) {
            $tmpPhotos = [];
            foreach ($photos as $photo) {
                if ($photo['id'] == ($this->object->image['id'] ?? false)) {
                    continue; // skip main photo
                }
                $tmpPhotos[$photo['id']] = $photo;
            }
            // array_values() to reindex photos from 0, otherwise js2php doesn't work properly
            $photos = array_values($tmpPhotos);
        }
        $this->photosWrapper->setObject($photos);

        return $this->photosWrapper;
    }

    /** Dodatečné obrázky variant.
     *
     * Obsahuje všechny obrázky pro danou variantu produktu nebo pro produkt bez variant. Využijte v případě, že používáte obrázky k variantám.
     *
     * @module PRODUCTS_VARIATIONS_PHOTOS
     */
    public function field_variation_photos()
    {
        $cfg = Config::get();
        // fetch separately by product IDs and assign using product/variation ID (ignore photo type)
        if (!isset($this->products->_variation_photos_fetched)) {
            $qb = sqlQueryBuilder()->select("CONCAT_WS('/', pp.id_product, pp.id_variation) AS object_id, pp.id_product, pp.id_variation, p.id, p.descr, p.source, p.image_2, pp.show_in_lead, p.date_update")
                ->from('photos', 'p')
                ->join('p', 'photos_products_relation', 'pp', 'pp.id_photo=p.id')
                ->where('pp.active=\'Y\'')
                ->andWhere(Operator::inIntArray($this->products->getProductIds(), 'pp.id_product'))
                ->orderBy('pp.id_product, pp.position, pp.id_variation IS NULL, pp.id_variation');
            $tmpPhotos = [];
            foreach ($qb->execute() as $photo) {
                $existing = $tmpPhotos[$photo['id']] ?? [];
                $types = $existing['_types'] ?? [];
                $types[$photo['show_in_lead']] = $cfg['Photo']['kind'][$photo['show_in_lead']] ?? $photo['show_in_lead'];
                $tmpPhotos[$photo['id']] = array_merge(
                    getImage($photo['id'], $photo['image_2'], $photo['source'], 102, $photo['descr'], strtotime($photo['date_update'])),
                    [
                        'show_in_lead' => $photo['show_in_lead'],
                        'id_variation' => $photo['id_variation'],
                        'id_product' => $photo['id_product'],
                        '_types' => $types,
                        '_variation_ids' => array_unique(array_merge(
                            $existing['_variation_ids'] ?? [],
                            !empty($photo['id_variation']) ? [$photo['id_variation']] : []
                        )),
                    ]
                );
            }

            if (!empty($tmpPhotos)) {
                foreach ($this->products as &$product) {
                    $product->_variation_photos = $product->_variation_photos ?? [];
                    foreach ($tmpPhotos as $photoID => $photo) {
                        if ($photo['id_product'] != $product->id) {
                            continue; // skip other products
                        }
                        if (!empty($photo['_variation_ids']) && !in_array($product->variationId, $photo['_variation_ids'])) {
                            continue; // skip VARIATION photos from other variations (photo has some id_variation, but current variation ID doesn't match)
                        }
                        if ($photo['id'] == ($product->image['id'] ?? false)) {
                            continue; // skip main photo
                        }
                        $product->_variation_photos[] = $photo; // index from 0, otherwise js2php doesn't work properly
                    }
                }
            }
            $this->products->_variation_photos_fetched = true;
        }

        $this->variationPhotosWrapper->setObject($this->object->_variation_photos ?? []);

        return $this->variationPhotosWrapper;
    }

    /** Cena */
    public function field_price(): ProductPriceWithLayersWrapper
    {
        return $this->productPriceWrapper->setObject($this->object->getProductPrice());
    }

    /** Cena pro slevu.
     *
     * @module PRICE_HISTORY
     */
    public function field_price_for_discount()
    {
        if (!isset($this->object->priceForDiscount)) {
            return null;
        }

        return $this->priceForDiscountWrapper->setObject($this->object->priceForDiscount);
    }

    /** Sleva */
    public function field_discount()
    {
        return $this->object->discount->asFloat();
    }

    /** Nákupní cena.
     *
     * (bez DPH)
     *
     * @module PRODUCTS__PRICE_BUY
     */
    public function field_price_buy()
    {
        return \Decimal::ensureDecimal($this->object['price_buy']['value_without_vat'] ?? 0)->asFloat();
    }

    /** Skrtlá cena.
     * @module PRODUCTS__PRICE_COMMON
     */
    public function field_price_common()
    {
        return \Decimal::ensureDecimal($this->object['priceCommon']['value_with_vat'] ?? 0)->asFloat();
    }

    /** Pole aktivních kampaní u produktu. Indexované podle kódu kampaně. */
    public function field_campaigns()
    {
        return $this->object->campaign_codes;
    }

    /** URL adresa detailu produkt */
    public function field_url()
    {
        return createScriptURL([
            's' => 'product',
            'IDproduct' => $this->object->id,
            'TITLE' => $this->object->title,
            'absolute' => true,
        ]);
    }

    /** Počet kusů skladem */
    public function field_in_store(): int
    {
        return $this->object->inStore ?? 0;
    }

    /** Reálný počet kusů skladem.
     *
     * Počet bez omezení hodnotou "Zobrazit max."
     *
     * @module PRODUCTS__SHOW_MAX
     */
    public function field_in_store_real(): int
    {
        if (!isset($this->products->_in_store_real_fetched)) {
            $qb = sqlQueryBuilder()->select("CONCAT_WS('/', p.id, pv.id) AS id, COALESCE(pv.in_store, p.in_store) AS in_store")->from('products', 'p')
                ->joinVariationsOnProducts()
                ->where(Operator::inIntArray($this->products->getProductIds(), 'p.id'))
                ->groupBy('p.id, pv.id')
                ->orderBy('p.id, pv.id');
            foreach ($qb->execute() as $row) {
                if (isset($this->products[$row['id']])) {
                    $this->products[$row['id']]->_in_store_real = $row['in_store'];
                }
            }
            $this->products->_in_store_real_fetched = true;
        }

        return $this->object->_in_store_real ?? 0;
    }

    /**
     * @module CONVERTORS
     */
    public function field_convertors()
    {
        if (!isset($this->products->_convertors_fetched)) {
            $qb = $this->convertorsUtil->getConvertorsQueryBuilder($this->products->getProductIds(), showHiddenVariations: true)
                ->select("CONCAT_WS('/', pv.id_product, pv.id) id, cdp.name param_name, pl.value param_value, pvcv.value label_value, cd.name convertor_name, cd.id id_convertor, pl.id_parameter");

            foreach ($qb->execute() as $row) {
                if (isset($this->products[$row['id']])) {
                    if (!isset($this->products[$row['id']]->convertors)) {
                        $this->products[$row['id']]->convertors = [];
                    }

                    if (!isset($this->products[$row['id']]->convertors[$row['id_convertor']])) {
                        $this->products[$row['id']]->convertors[$row['id_convertor']] = [
                            'name' => $row['convertor_name'],
                            'parameters' => [],
                        ];
                    }

                    if (!isset($this->products[$row['id']]->convertors[$row['id_convertor']]['parameters'][$row['id_parameter']])) {
                        $this->products[$row['id']]->convertors[$row['id_convertor']]['parameters'][$row['id_parameter']]['name'] = $row['param_name'];
                    }
                    $this->products[$row['id']]->convertors[$row['id_convertor']]['parameters'][$row['id_parameter']]['values'][] = $row['param_value'];
                }
            }

            $this->products->_convertors_fetched = true;
        }

        return $this->object->convertors ?? [];
    }

    /**
     * Měrné jednotky.
     *
     * @module PRODUCTS__UNITS
     */
    public function field_measure_unit()
    {
        $this->products->fetchMeasureUnits();

        if (empty($this->object->measureUnits)) {
            return [];
        }

        $data = $this->object->measureUnits[array_key_first($this->object->measureUnits)] ?? null;
        if ($this->object->variationId) {
            $data = $this->object->measureUnits[$this->object->variationId] ?? null;
        }

        $result = $this->measureUnitUtil->calculatePriceUnit($this->object->getProductPrice(), $data);

        if (!$result) {
            return [];
        }

        $result['price'] = $result['price']->getPriceWithVat()->asFloat();
        if (isset($result['price_without_discount'])) {
            $result['price_without_discount'] = $result['price_without_discount']->getPriceWithVat()->asFloat();
        }

        return $result;
    }

    /**
     * Počet kusů skladem u dodavatele.
     *
     * @module PRODUCTS_SUPPLIERS
     */
    public function field_in_store_suppliers(): int
    {
        $this->products->fetchProductOfSuppliersInStore();

        return $this->object->in_store_suppliers_original ?? 0;
    }

    /**
     * Dodavatelé.
     *
     * @module SUPPLIERS
     */
    public function field_suppliers(): array
    {
        $this->products->fetchSuppliers();

        return $this->object->suppliers ?? [];
    }

    /**
     * Minimální počet kusů skladem.
     *
     * @module MISSING_PRODUCTS
     */
    public function field_in_store_min(): int
    {
        return $this->object->in_store_min ?? 0;
    }

    /** Počet kusů v jednotlivých skladech.
     * @module STORES
     */
    public function field_stores()
    {
        $this->products->fetchStoresInStore();

        return !empty($this->object->storesInStore) ? $this->object->storesInStore : [];
    }

    /**
     * Výrobce.
     *
     * title - název výrobce
     * photo - url fotky výrobce.
     * qpsr - GPSR kontaktní údaje
     */
    public function field_producer()
    {
        $this->products->fetchProducers();
        if (!isset($this->object->producer['id'])) {
            return false;
        }
        $producer = $this->object->producer;
        $photo = $producer['image'] ?? false;
        if ($photo) {
            $photo = $this->producerPhotoWrapper->setObject($producer['image']);
        }

        $data = [
            'title' => $producer['title'],
            'photo' => $photo,
        ];

        if (isset($producer['import_company_name'])) {
            $data['gpsr'] = [
                'name' => $producer['import_company_name'],
                'street' => $producer['import_company_street'],
                'city' => $producer['import_company_city'],
                'zip' => $producer['import_company_zip'],
                'country' => $producer['import_company_country'],
                'email' => $producer['import_company_email'],
                'web' => $producer['import_company_web'],
            ];
        } else {
            $data['gpsr'] = [
                'name' => $producer['company_name'],
                'street' => $producer['company_street'],
                'city' => $producer['company_city'],
                'zip' => $producer['company_zip'],
                'country' => $producer['company_country'],
                'email' => $producer['company_email'],
                'web' => $producer['company_web'],
            ];
        }

        return $data;
    }

    /** Anotace produktu */
    public function field_annotation()
    {
        return $this->object->descr;
    }

    /** Popis produktu */
    public function field_description()
    {
        return $this->object->longDescr;
    }

    /** Rozšiřující popis produktu */
    public function field_extended_description()
    {
        return $this->object->parameters;
    }

    /** Doprava */
    public function field_delivery()
    {
        return $this->deliveryWrapper->setObject($this->object);
    }

    /** Seznam doprav */
    public function field_deliveries()
    {
        $this->deliveryWrapper->setObject($this->object);

        return $this->deliveryWrapper->getDeliveryWrappers();
    }

    /** Seznam všech doprav bez omezení */
    public function field_deliveries_all()
    {
        $this->deliveryWrapper->setObject($this->object);

        return $this->deliveryWrapper->getDeliveryWrappers(false, true);
    }

    /**
     * Parametry.
     */
    public function field_params()
    {
        $this->products->fetchParameters();

        if (!isset($this->object->param_feeds)) {
            $this->object->param_feeds = array_map(function ($param) {
                return [
                    'name' => $param['name'],
                    'value' => $param['value'],
                    'unit' => $param['unit'],
                    'value_type' => $param['value_type'],
                    'value_id' => $param['value_id'],
                    'value_desc' => $param['description'],
                    'values' => array_map(function ($value) {
                        return [
                            'id' => $value['id'] ?? null,
                            'name' => $value['value'],
                            'desc' => $value['descr'] ?? '',
                            'unit' => $value['unit'],
                            'weight' => $value['weight'] ?? null,
                        ];
                    }, $param['values']),
                ];
            }, $this->object->param);
        }

        return $this->object->param_feeds;
    }

    /** Hmotnost */
    public function field_weight()
    {
        return $this->object->weight ?? '';
    }

    /** Odkazy */
    public function field_links()
    {
        $this->products->fetchLinks();

        return $this->object->links;
    }

    /**
     * Dárky.
     *
     * @module PRODUCT_GIFTS
     */
    public function field_gifts()
    {
        $this->products->fetchGifts();
        $this->giftsWrapper->setObjects($this->object->gifts ?? []);

        $tmp = [];
        foreach ($this->giftsWrapper as $key => $value) {
            $tmp[$key] = $value;
        }

        return $this->giftsWrapper->getAsArray();
    }

    /**
     * Sety.
     *
     * @module PRODUCT_SETS
     */
    public function field_sets()
    {
        if (isset($this->feedRow['id'])) {
            $this->products->fetchSets();
        }
        $this->setsWrapper->setObject($this->object->sets ?? []);

        return $this->setsWrapper;
    }

    /**
     * Množstevní slevy.
     *
     * pieces - počet kusů, od kterých začíná sleva
     * discount - sleva
     *
     * @module QUANTITY_DISCOUNT
     */
    public function field_quantity_discounts()
    {
        $this->products->fetchQuantityDiscounts();

        $this->quantityDiscountsWrapper->setObject($this->object->quantityDiscounts ?? []);

        return $this->quantityDiscountsWrapper;
    }

    /** Záruka */
    public function field_guarantee()
    {
        return $this->object->guarantee ?? 24;
    }

    /** Datum vytvoření */
    public function field_date_added()
    {
        return $this->object->date_added ?? '';
    }

    /**
     * Datum naskladnění.
     *
     * Použití kompatibilní s V8: typeof date_stock_in.format === 'function' ? date_stock_in.format('Y-m-d\\TH:i:s') : (typeof date_stock_in.toISOString === 'function' ? date_stock_in.toISOString().substring(0, 19) : date_stock_in)
     *
     * @module STOCK_IN
     */
    public function field_date_stock_in(): ?\DateTime
    {
        // legacy support: typeof date_stock_in.format === 'function' ? date_stock_in.format('Y-m-d H:i:s') : (typeof date_stock_in.toISOString === 'function' ? date_stock_in.toISOString().replace('T', ' ').substring(0, 19) : date_stock_in)
        return $this->object->date_stock_in ?? null;
    }

    /** Viditelnost zboží.
     *
     * Y - Viditelné
     * N - Skryté
     * O - Prodej ukončen
     */
    public function field_visibility()
    {
        return $this->object->visible ?? '';
    }

    /** Viditelnost varianty.
     *
     * Y - Viditelné
     * N - Skryté
     */
    public function field_variation_visibility(): ?string
    {
        return $this->object->variationVisible ?? null;
    }

    /**
     * Šablony produktů.
     *
     * @module TEMPLATES
     */
    public function field_templates()
    {
        $this->products->fetchTemplates();

        return !empty($this->object->templates) ? $this->templateWrapper->setObjects($this->object->templates)->getAsArray() : [];
    }

    /**
     * Bloky (obsah).
     *
     * @module PRODUCTS__DESCR_PLUS
     */
    public function field_blocks()
    {
        $this->feedUtils->fetchCollectionBlocks($this->products);

        return !empty($this->object->_raw_blocks) ? $this->blocksWrapper->setObject($this->object->_raw_blocks) : [];
    }

    /**
     * Ceníky.
     *
     * @module PRICELISTS
     */
    public function field_pricelists()
    {
        $this->products->fetchPricelists();

        return $this->pricelistsWrapper->setObjects($this->object->pricelists ?? [])->getAsArray();
    }

    /**
     * Cenové hladiny.
     *
     * @module PRICE_LEVELS
     */
    public function field_price_levels()
    {
        $this->products->fetchSections();

        return $this->priceLevelsWrapper->setProduct($this->object)->getAsArray();
    }

    /** Rozměry zboží.
     *
     * width - šířka
     * height - výška
     * depth - hloubka
     */
    public function field_dimensions()
    {
        $dimensions = [];

        if (!empty($this->object->width)) {
            $dimensions['width'] = (float) $this->object->width;
        }
        if (!empty($this->object->height)) {
            $dimensions['height'] = (float) $this->object->height;
        }
        if (!empty($this->object->depth)) {
            $dimensions['depth'] = (float) $this->object->depth;
        }

        return $dimensions;
    }

    /**
     * Příplatky.
     *
     * @module PRODUCTS_CHARGES
     */
    public function field_charges()
    {
        $this->products->fetchCharges();

        return !empty($this->object->charges) ? $this->chargeWrapper->setObjects($this->object->charges)->getAsArray() : [];
    }

    /**
     * Přílohy k produktu.
     *
     * link - odkaz
     * title - název
     * position - pozice
     *
     * @module ATTACHMENTS
     */
    public function field_attachments(): array
    {
        $this->products->fetchAttachments();

        return $this->object->attachments ?? [];
    }

    /**
     * Štítky produktu.
     *
     * @module LABELS
     */
    public function field_labels(): array
    {
        $this->products->fetchProductLabels('all');

        return $this->labelsWrapper->setObjects($this->object->labels ?? [])->getAsArray();
    }

    /**
     * Hlavní produkt kolekcí.
     *
     * id - id hlavního produktu
     * code - kod hlavního produktu
     *
     * @module PRODUCTS_COLLECTIONS
     */
    public function field_collection_master_products(): array
    {
        // nactu produkty v jejichz kolekcich se produkt nachazi
        $othersCollections = $this->object->fetchCollections()['others'] ?? [];

        $masterProducts = [];
        foreach ($othersCollections as $key => $item) {
            $masterProducts[$key] = [
                'id' => $item->id,
                'code' => $item->code,
            ];
        }

        return $masterProducts;
    }

    /**
     * @module PRODUCT_RESERVATIONS
     */
    public function field_reservations(): array
    {
        $this->products->fetchReservations();

        return [
            'total' => array_sum(array_map(fn ($x) => $x['quantity'], $this->object->reservations ?? [])),
            'items' => $this->object->reservations ?? [],
        ];
    }

    /**
     * Recyklační příspěvek.
     *
     * @module PRODUCTS__RECYCLING_FEE
     */
    public function field_recycling_fee(): ?float
    {
        if ($recyclingFee = ($this->object->getData()['recycling_fee'] ?? null)) {
            return (float) $recyclingFee;
        }

        return null;
    }

    /**
     * OSS kód.
     *
     * @module OSS_VATS
     */
    public function field_vat_cn_code(): ?int
    {
        return $this->object->id_cn;
    }

    /**
     * Poznámka na produktu.
     *
     * @module PRODUCTS__NOTE
     */
    public function field_note(): ?string
    {
        return $this->object->note_;
    }
}
