<?php

declare(strict_types=1);

namespace External\ZNZBundle\Util\Product;

use External\ZNZBundle\Util\ZNZUtil;
use KupShop\CatalogBundle\ProductList\ProductCollection;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Util\Contexts;
use Query\Operator;
use Query\Product;
use Symfony\Contracts\Service\Attribute\Required;

class ZNZProductUtil
{
    #[Required]
    public ZNZUtil $znzUtil;

    public function updateProductsDefaultPrice(): void
    {
        $defaultPriceListId = sqlQueryBuilder()
            ->select('zpl.id_pricelist')
            ->from('znz_pricelists', 'zpl')
            ->join('zpl', 'pricelists', 'pl', 'pl.id = zpl.id_pricelist')
            ->andWhere(Operator::equals(['is_default' => 1]))
            ->andWhere(Operator::equals(['pl.currency' => Contexts::get(CurrencyContext::class)->getDefaultId()]))
            ->execute()->fetchOne();

        if (!$defaultPriceListId) {
            return;
        }

        // aktualizovat vychozi cenu u produktu podle vychoziho ceniku
        sqlQueryBuilder()
            ->update('products', 'p')
            ->join('p', 'pricelists_products', 'plp', 'plp.id_product = p.id AND plp.id_variation IS NULL AND plp.id_pricelist = :priceListId')
            ->set('p.price', 'plp.price')
            ->where('plp.price IS NOT NULL')
            ->setParameter('priceListId', $defaultPriceListId)
            ->execute();

        // aktualizovat vychozi cenu u varianty podle vychoziho ceniku
        sqlQueryBuilder()
            ->update('products_variations', 'pv')
            ->join('pv', 'pricelists_products', 'plp', 'plp.id_variation = pv.id AND plp.id_pricelist = :priceListId')
            ->set('pv.price', 'plp.price')
            ->where('plp.price IS NOT NULL')
            ->setParameter('priceListId', $defaultPriceListId)
            ->execute();
    }

    public function fetchZNZSuppliersInfo(ProductCollection $products): void
    {
        if (isset($products->_fetch_znz_suppliers_info)) {
            return;
        }

        if ($products->isEmpty()) {
            return;
        }

        $filterProducts = $this->collectProductsForFilter($products);

        $qb = sqlQueryBuilder()
            ->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, si.id_store, zsi.data')
            ->from('products', 'p')
            ->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
            ->leftJoin('pv', 'stores_items', 'si', 'si.id_product = p.id AND si.id_variation <=> pv.id')
            ->leftJoin('si', 'znz_stores_items', 'zsi', 'zsi.id_stores_item = si.id')
            ->join('zsi', 'stores', 's', 's.id = si.id_store')
            ->andWhere(Product::productsAndVariationsIds($filterProducts))
            ->andWhere(Operator::equals(['s.figure' => 'Y']))
            ->groupBy('p.id, pv.id');

        if ($storeIds = $this->znzUtil->getActiveStoreIds()) {
            $qb->andWhere(Operator::inIntArray($storeIds, 'si.id_store'));
        }

        $data = [];
        foreach ($qb->execute() as $item) {
            $data[$item['id']][$item['id_store']] = json_decode($item['data'] ?: '', true)['supplier'] ?? [];
        }

        foreach ($products as $key => $product) {
            $product->znz_suppliers_info = $data[$key] ?? [];
        }

        $products->_fetch_znz_suppliers_info = true;
    }

    public function fetchZNZMaxCartQuantity(ProductCollection $products): void
    {
        if (isset($products->_fetch_znz_max_cart_quantity)) {
            return;
        }

        if ($products->isEmpty()) {
            return;
        }

        $filterProducts = $this->collectProductsForFilter($products);

        $qb = sqlQueryBuilder()
            ->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, zpw.max_cart_quantity')
            ->from('products', 'p')
            ->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
            ->leftJoin('pv', 'znz_products', 'zp', 'zp.id_product = p.id AND zp.id_variation <=> pv.id')
            ->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz')
            ->andWhere(Product::productsAndVariationsIds($filterProducts))
            ->andWhere(Operator::equals(['zpw.id_website' => $this->znzUtil->getCurrentWebsite()]))
            ->groupBy('p.id, pv.id');

        foreach ($qb->execute() as $item) {
            if (isset($products[$item['id']])) {
                $products[$item['id']]->znz_max_cart_quantity = $item['max_cart_quantity'] ? (int) $item['max_cart_quantity'] : null;
            }
        }

        $products->_fetch_znz_max_cart_quantity = true;
    }

    public function fetchZNZVisibility(ProductCollection $products): void
    {
        if (isset($products->_fetch_znz_visibility)) {
            return;
        }

        if ($products->isEmpty()) {
            return;
        }

        $filterProducts = $this->collectProductsForFilter($products);

        $qb = sqlQueryBuilder()
            ->select('IF(pv.id, CONCAT(p.id, "/", pv.id), p.id) as id, JSON_VALUE(zp.data, "$.znzFigure") as znz_figure, GROUP_CONCAT(zpw.id_website) as znz_websites')
            ->from('products', 'p')
            ->leftJoin('p', 'products_variations', 'pv', 'pv.id_product = p.id')
            ->leftJoin('pv', 'znz_products', 'zp', 'zp.id_product = p.id AND zp.id_variation <=> pv.id')
            ->leftJoin('zp', 'znz_products_website', 'zpw', 'zpw.id_znz = zp.id_znz')
            ->andWhere(Product::productsAndVariationsIds($filterProducts))
            ->groupBy('p.id, pv.id');

        $website = $this->znzUtil->getCurrentWebsite();

        foreach ($qb->execute() as $item) {
            $websites = explode(',', $item['znz_websites'] ?: '');
            $visibility = 'N';
            if ($item['znz_figure'] === 'Y' && in_array($website, $websites)) {
                $visibility = 'Y';
            }

            if (isset($products[$item['id']])) {
                $products[$item['id']]->znz_visibility = $visibility;
            }
        }

        $products->_fetch_znz_visibility = true;
    }

    private function collectProductsForFilter(ProductCollection $products): array
    {
        $filterProducts = [];
        foreach ($products as $product) {
            $filterProducts[$product->id] = $filterProducts[$product->id] ?? null;
            if ($product->variationId ?? false) {
                $filterProducts[$product->id][] = $product->variationId;
            }
        }

        return $filterProducts;
    }
}
