<?php

namespace KupShop\GTMBundle\Utils\DataLoaders;

use KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\CatalogBundle\ProductList\ProductCollectionWrapper;
use KupShop\CatalogElasticBundle\View\SectionView;
use KupShop\ComponentsBundle\Entity\Thumbnail;
use KupShop\ContentBundle\Entity\Wrapper\ProductUnifiedWrapper;
use KupShop\ContentBundle\Util\ImageLocator;
use KupShop\ContentBundle\View\ProductView;
use KupShop\ContentBundle\View\VariationBlockView;
use KupShop\GTMBundle\Utils\PriceComputer;
use KupShop\GTMBundle\Utils\Providers\ProductDataProvider;
use KupShop\GTMBundle\Utils\ViewDataHelper;
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Util\Price\ProductPrice;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use KupShop\KupShopBundle\Views\View;
use KupShop\KupShopBundle\Wrapper\PriceWrapper;
use Symfony\Contracts\Service\Attribute\Required;

class Products
{
    use ViewDataHelper;

    #[Required]
    public PurchaseState $purchaseState;

    public function __construct(
        protected readonly ProductDataProvider $gtmProductDataProvider,
        protected readonly UrlFinder $urlFinder,
        protected readonly PriceComputer $priceComputer,
        protected readonly ImageLocator $imageLocator,
    ) {
    }

    /**
     * @param \Product $product
     *
     * @return \stdClass
     */
    public function getData($product, ?View $view = null)
    {
        $cfg = Config::get();

        $p = new \stdClass();

        $p->id = $product->id;
        $p->idProduct = $product->id;
        $p->EAN = $product->ean ?? '';
        $p->code = $product->code;
        $p->productCode = $product->productCode ?? '';

        $p->hasVariations = null;
        $p->variationsIds = null;
        $p->idVariation = null;
        $p->variationCode = null;
        $p->variationName = null;
        $p->soldOut = null;
        if (findModule(\Modules::PRODUCTS_VARIATIONS)) {
            if (($view instanceof ProductView || $view instanceof VariationBlockView) && !empty($product->variations['variations'])) {
                $first_variation = !empty($product->gtmIdVariation) ? $product->variations['variations'][$product->gtmIdVariation] : array_values($product->variations['variations'])[0];
                $p->idVariation = $first_variation['id'] ?? '';
                $p->variationCode = $first_variation['variationCode'] ?? '';
                $p->id = $product->id.'_'.$p->idVariation;
                $p->variationName = $first_variation['title'];
            } elseif (!empty($product->variationId)) { // v případě detailu produktu
                $p->idVariation = $product->variationId;
                $p->id = $product->id.'_'.$product->variationId;
                $p->variationCode = $product->variationCode ?? '';
                $p->variationName = $product->variationTitle;
            }

            if (($soldOut = $this->purchaseState->getSoldOut($product)) !== null) {
                $p->soldOut = $soldOut;
            }

            $p->variationsIds = array_values($product->variationsIds ?? []);
            $p->hasVariations = !empty($p->variationsIds);
            $p->idAll = array_map(fn ($v) => "{$product->id}_{$v}", $p->variationsIds);
        }

        $p->categoryMain = [];
        if ($product->sections && ($section = reset($product->sections))) {
            foreach ($section->getParents() ?? [] as $cat) {
                if ($cat->getId()) {
                    $p->categoryMain[] = [
                        'ID' => $cat->getId(),
                        'text' => $cat->getName(),
                    ];
                }
            }
        }
        $p->categoryMain = self::getCategoriesMap($p->categoryMain);

        if ($view) {
            $p->categoryCurrent = $this->getBreadcrumbsWithoutCurrent($view);
        } else {
            $p->categoryCurrent = [];
        }

        $p->producer = findModule(\Modules::PRODUCERS) ? ($product->producer['title'] ?? '') : null;

        $p->campaigns = array_map(function ($campaign) {
            return ['id' => $campaign['short'], 'name' => $campaign['singular']];
        }, $product->campaign_codes);
        if (findModule(\Modules::LABELS, \Modules::SUB_PRODUCT_LABELS)) {
            $labels = array_filter($product->labels ?? [], fn ($label) => $label['is_visible']);
            $labels = array_map(function ($label) {
                return ['id' => $label['id'], 'name' => $label['name']];
            }, $labels);
            $p->campaigns += $labels;
        }

        $p->name = $product->title;

        $priceField = $product->getProductPrice();

        $p->vat = $product->getProductPrice()?->getVat();

        if (!empty($p->idVariation) && !empty($first_variation)) {
            $priceField = $first_variation['productPrice'];
        }

        $this->setProductPriceData($p, $priceField);

        $p->discount = $product->discount->asFloat();
        $p->hasDiscount = !$product->discount->isZero();

        if (empty($product->deliveryTimeText)) {
            $product->prepareDeliveryText();
        }

        $p->availability = $product->deliveryTimeText;

        $p->url = createScriptURL(['s' => 'product', 'IDproduct' => $product->id, 'TITLE' => $product->title, 'absolute' => true]);
        $p->imageUrl = ($product->image) ? $product->image['src_big'] : null;
        if (findModule(\Modules::COMPONENTS) && ($product->photoId > 0)) {
            $thumbnail = new Thumbnail($product->photoId, $product->photoDescr ?? '', $product->photoDateUpdate ?? '');
            $p->imageUrl = $this->imageLocator->getThumbnailUrl($thumbnail, 'product_large', 'desktop');
        }
        $p->imageUrl = $p->imageUrl ? $this->urlFinder->shopUrlAbsolute($p->imageUrl) : null;

        return $p;
    }

    protected function setProductPriceData(\stdClass $p, ProductPrice|PriceWrapper|null $priceField)
    {
        $p->price = $this->priceComputer->getPrice($priceField);
        $p->priceWithVat = $this->priceComputer->getPrice($priceField, true);
        $p->priceWithoutVat = $this->priceComputer->getPrice($priceField, false);
        $p->priceVat = $priceField ? $this->priceComputer->getPrice($priceField->getVatPrice(), false, false) : null;
        $p->priceWithoutDiscount = $priceField ? $this->priceComputer->getPrice($priceField->getPriceWithoutDiscount()) : null;
    }

    /**
     * @param $useGlobalProductStorage - pro komponenty, produkty se sbiraji a nakonci stranky se vyprdnou,
     *                                 GTM JS si je pak vyzobava z jednoho mista a nemusi tak byt kvuli ruznym eventam na strance Xkrat
     *
     * @return array
     */
    public function getProducts($products = [], ?View $view = null, $useGlobalProductStorage = false)
    {
        if ($products instanceof ProductCollection) {
            // clone collection so it can be modified without affecting the original collection
            $products = $products->clone();
        }

        $dbcfg = \Settings::getDefault();

        if ($view) {
            $templateData = $view->getTemplateData();
            $page = $templateData['body']['pager']->number ?? 1;
            $counter = (1 * (($page - 1) * $dbcfg->cat_show_products)) + 1;
        } else {
            $counter = 1;
        }

        $productsArray = [];
        if ($products) {
            $productsArray = $products;
        } elseif ($templateData['body']['productsList'] ?? false) {
            $productsArray = $templateData['body']['productsList'];
        } elseif ($templateData['body']['results']['products']['list'] ?? false) {
            $productsArray = $templateData['body']['results']['products']['list'];
        }

        $productsData = [];
        $entityType = \FilterParams::ENTITY_PRODUCT;
        $copy = $productsArray;
        foreach ($copy as $key => $_) {
            $product = &$productsArray[$key];
            try {
                if ($product instanceof ProductUnifiedWrapper) {
                    $idVariation = $product->getVariationId();
                    $product = $product->getObject()->getProduct();
                    $product->gtmIdVariation = $idVariation;
                } elseif ($product instanceof ProductWrapper) {
                    $product = $product->getObject();
                }
                unset($productsArray[$key]);
                $id = $product->id;
                if (!empty($product->variationId)) {
                    $id .= '_'.$product->variationId;
                    $entityType = \FilterParams::ENTITY_VARIATION;
                }
                if ($useGlobalProductStorage && array_key_exists($id, $this->gtmProductDataProvider->getProducts())) {
                    $productsData[$id] = "\{{$id}\}";
                } else {
                    $productsArray[$id] = $product;
                }
            } catch (\Exception $e) {
                $sentry = getRaven();
                $sentry->captureMessage('GTM product modify error', [], ['extra' => [
                    'page' => $view,
                    'error_message' => $e->getMessage(),
                ]]);
            }
        }

        if (!($productsArray instanceof ProductCollection) && !($productsArray instanceof ProductCollectionWrapper)) {
            $productsArray = (new ProductCollection($productsArray))->setEntityType($entityType);
        }

        if ($productsArray->isEmpty()) {
            return $productsData;
        }

        $this->fetchProductsData($productsArray);

        foreach ($productsArray as $productItem) {
            $p = $this->getData($productItem, $view);
            $p->position = $counter++;
            if (!empty($productItem->topProduct)) {
                $p->topProduct = true;
            }

            if ($useGlobalProductStorage) {
                $this->gtmProductDataProvider->addProduct($p);
                $productsData[$p->id] = "\{{$p->id}\}";
            } else {
                $productsData[] = $p;
            }
        }

        return $productsData;
    }

    public function fetchProductsData($products): void
    {
        $products->fetchVariations();
        $products->fetchSectionsDirectly();
        $products->fetchProducers();
        $products->fetchProductLabels('list');
    }

    public function getListType($view, $pageData = null)
    {
        if ($pageData['listType'] ?? false) {
            return $pageData['listType'];
        }

        if ($view instanceof \KupShop\ContentBundle\View\HomeView) {
            return 'homepage: /';
        } elseif ($view instanceof \KupShop\CatalogBundle\View\CategoryView) {
            if ($view->categoryId) {
                return 'category: '.$this->getRequest()->getPathInfo();
            } elseif ($view->producerId) {
                return 'brands: '.$view->producer['name'];
            }
        } elseif ($view instanceof \KupShop\ContentBundle\View\ProductView) {
            return 'detail :';
        } elseif ($view instanceof \KupShop\CatalogBundle\View\SearchView) {
            return 'search: '.$view->getTitle();
        } elseif ($view instanceof SectionView) {
            if ($view->getCategoryId()) {
                return 'category: '.$this->getRequest()->getPathInfo();
            } elseif ($view->getProducerId()) {
                return 'brands: '.$this->getRequest()->getPathInfo();
            }
        }

        return '';
    }

    public function getListId($view, $pageData = null)
    {
        if ($pageData['listId'] ?? false) {
            return $pageData['listId'];
        }

        if ($view instanceof SectionView) {
            return $view->getCategoryId() ?: $view->getProducerId();
        }

        return ($view->categoryId ?? null) ?: ($view->producerId ?? null) ?: null;
    }
}
