<?php

declare(strict_types=1);

namespace KupShop\SellerBundle\Utils;

use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\ContentBundle\Util\Block;
use KupShop\ContentBundle\Util\ImageLocator;
use Query\Operator;
use Query\Product;

class SellerMultiFetch
{
    protected ImageLocator $imageLocator;
    protected ProductList $productList;
    protected Block $block;

    public function __construct(ImageLocator $imageLocator, Block $block, ProductList $productList)
    {
        $this->imageLocator = $imageLocator;
        $this->block = $block;
        $this->productList = $productList;
    }

    /**
     * Multifetch of sellers blocks.
     */
    public function fetchSellersBlocks(array &$sellers): void
    {
        $blockIds = array_filter(array_map(fn ($x) => $x['id_block'], $sellers));
        // neni co fetchovat
        if (empty($blockIds)) {
            return;
        }

        $qb = sqlQueryBuilder()
            ->select('b.*', 'GROUP_CONCAT(pb.id_photo ORDER BY pb.position) as photos')
            ->from('blocks', 'b')
            ->leftJoin('b', 'photos_blocks_relation', 'pb', 'pb.id_block = b.id')
            ->where(Operator::inIntArray($blockIds, 'b.id_root'))
            ->groupBy('b.id')
            ->orderBy('position');

        if (!isAdministration()) {
            $qb->andWhere(
                \Query\Translation::coalesceTranslatedFields(
                    \KupShop\I18nBundle\Translations\BlocksTranslation::class
                )
            );
        }

        $blocksByRootId = [];
        foreach ($qb->execute() as $item) {
            $blocksByRootId[$item['id_root']][] = $item;
        }

        foreach ($sellers as &$seller) {
            $seller['blocks'] = ($blocksByRootId[$seller['id_block']] ?? false) ? $this->block->buildBlockHierarchy($blocksByRootId[$seller['id_block']],
                (int) $seller['id_block']) : [];
        }
    }

    /**
     * Multifetch of sellers photos.
     */
    public function fetchSellersPhotos(array &$sellers): void
    {
        $qb = sqlQueryBuilder()
            ->select('psr.id_seller, ph.*')
            ->from('photos_sellers_relation', 'psr')
            ->join('psr', 'photos', 'ph', 'ph.id = psr.id_photo')
            ->where(Operator::inIntArray(array_keys($sellers), 'psr.id_seller'))
            ->orderBy('psr.position');

        foreach ($qb->execute() as $item) {
            if ($sellers[$item['id_seller']] ?? false) {
                $sellers[$item['id_seller']]['photos'][$item['id']] = $this->imageLocator->getImage($item);
            }
        }
    }

    /**
     * Multifetch pro nafetchovani celkoveho počtu kusu skladem na prodejně podle zadaných produktů.
     */
    public function fetchSellersInStore(array &$sellers, array $products): void
    {
        $productList = clone $this->productList;
        $productList->setVariationsAsResult(true);
        $productList->andSpec(Product::productsAndVariationsIds($products));
        $products = $productList->getProducts();

        $products->fetchStoresInStore();

        $sellerStores = array_filter(array_map(fn ($x) => $x['id_store'], $sellers));

        foreach ($sellers as &$seller) {
            // k prodejne si ulozim celkove pocty kusu skladem podle typu
            $seller['in_store'] = 0;
            $seller['in_store_main'] = 0;
            $seller['in_store_other'] = 0;
            foreach ($products as $key => $product) {
                $inStoreSeller = (float) ($product->storesInStore[$seller['id_store']]['in_store'] ?? 0);

                // celkove mnozstvi skladem pro danou prodejnu
                $seller['in_store'] = $seller['in_store'] + $inStoreSeller;
                // sklad jednotlivych produktu na dane prodejne
                $seller['products'][$key]['in_store'] = $inStoreSeller;

                // sklad jednotlivych produktu na hlavnich skladech
                $seller['products'][$key]['in_store_main'] = 0;
                // sklad jednotlivych produktu na ostatnich prodejnach
                $seller['products'][$key]['in_store_other'] = 0;

                foreach ($product->storesInStore ?? [] as $storeId => $item) {
                    if (!in_array($storeId, $sellerStores)) {
                        $seller['products'][$key]['in_store_main'] += (float) $item['in_store'];
                        $seller['in_store_main'] += (float) $item['in_store'];
                    } elseif ($seller['id_store'] !== $storeId) {
                        $seller['products'][$key]['in_store_other'] += (float) $item['in_store'];
                        $seller['in_store_other'] += (float) $item['in_store'];
                    }
                }
            }

            // minimum ze vsech produktu na dane prodejne
            $sellersInStore = array_map(fn ($x) => $x['in_store'], $seller['products'] ?? []);
            $seller['min_in_store'] = 0;
            if (!empty($sellersInStore)) {
                $seller['min_in_store'] = min($sellersInStore) ?: 0;
            }
        }
    }
}
