<?php

/*
 * Smarty plugin
 * -------------------------------------------------------------
 * Type:     function
 * Name:     get_templates
 * Purpose:  returns templates
 * -------------------------------------------------------------
 */

use Doctrine\DBAL\Connection;
use KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper;
use KupShop\ContentBundle\Entity\Placeholder;
use KupShop\ContentBundle\Util\Block;
use KupShop\ContentBundle\Util\InlineEdit;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use Query\Operator;
use Query\Translation;

function smarty_function_get_templates($params, &$smarty)
{
    $include = [];
    $exclude = [];
    $label = [];
    $id = [];

    $product = null;
    $productId = null;

    $assign = null;

    extract($params);

    $product = ProductWrapper::unwrap($product);

    if ($product instanceof \Product) {
        $productId = $product->id;
    } elseif (is_numeric($product)) {
        $productId = $product;
        $product = null;
    }

    if (empty($params['assign'])) {
        trigger_error("Chybějící parametr 'assign'");
    }

    if (!is_array($label)) {
        $label = [$label];
    }

    if (!is_array($include)) {
        $include = [$include];
    }

    if (!is_array($exclude)) {
        $exclude = [$exclude];
    }

    if (!is_array($id)) {
        $id = [$id];
    }

    $qb = sqlQueryBuilder()
        ->select('t.id_category, t.id, t.name, tc.name as category, tc.product_detail_position, t.id_block, t.data, t.figure')
        ->from('templates', 't')
        ->leftJoin('t', 'templates_categories', 'tc', 't.id_category = tc.id')
        ->orderBy('tc.position')
        ->addOrderBy('t.position')
        ->addOrderBy('t.name');

    if ($productId) {
        $qb->leftJoin('t', 'templates_products', 'tp', 't.id = tp.id_template')
            ->andWhere(Operator::equals(['tp.id_product' => $productId]));
    }
    if ($label) {
        $qb->andWhere(Operator::findInSet($label, 'tc.label', 'OR'));
    }

    if ($include) {
        $qb->andWhere(Operator::inIntArray($include, 'tc.id'));
    }

    if ($exclude) {
        $qb->andWhere(Operator::not(Operator::inIntArray($exclude, 'tc.id')));
    }

    if ($id) {
        $qb->andWhere(Operator::inIntArray($id, 't.id'));
    }

    if ($product && ($labels = $product->labels) && ($labelTemplateIds = array_column($labels, 'id_template'))) {
        $qb->setParameter('labelsIntArray', array_keys($labels), Connection::PARAM_INT_ARRAY);
        $qb->orWhere(Operator::inIntArray($labelTemplateIds, 't.id'))
            ->leftJoin('t', 'labels', 'l', 'l.id_template = t.id AND l.id IN (:labelsIntArray)')
            ->addSelect('l.id AS from_label');
        $productLabelUtil = ServiceContainer::getService(\KupShop\LabelsBundle\Util\ProductLabelUtil::class);
    }

    $qb->andWhere(Translation::coalesceTranslatedFields(\KupShop\I18nBundle\Translations\TemplatesTranslation::class));
    $qb->andWhere(Translation::coalesceTranslatedFields(\KupShop\I18nBundle\Translations\TemplatesCategoriesTranslation::class, ['name' => 'category']));
    $qb->having('figure!="N"');

    $result = $qb->execute();

    $blockUtils = ServiceContainer::getService(Block::class);
    $inlineEdit = ServiceContainer::getService(InlineEdit::class);

    $ret = [];
    foreach ($result as $row) {
        $key = $row['id_category'];

        if (!isset($ret[$key])) {
            $ret[$key] = [
                'id' => $row['id_category'],
                'title' => $row['category'],
                'position' => $row['product_detail_position'],
                'values' => [],
            ];
        }

        $row['data'] = json_decode($row['data'] ?? '', true) ?? [];

        $placeholders = $placeholders ?? [];

        if ($placeholders) {
            foreach ($placeholders as &$placeholder) {
                if ($placeholder instanceof Placeholder) {
                    continue;
                }
                $placeholder = new Placeholder(
                    key($placeholder), '', function () use ($placeholder) {
                        return array_pop($placeholder);
                    });
            }
        }

        // Label templates
        if ($row['from_label']) {
            $labelPlaceholders = $productLabelUtil->getLabelPlaceholders($product, $row['from_label']);

            if (empty($labelPlaceholders[0]?->getValue())) {
                continue;
            }

            // add labelPlaceholders to existing placeholders
            array_push($placeholders, ...$labelPlaceholders);
        }

        if ($blockID = $row['id_block']) {
            $blockList = $blockUtils->getBlocks($blockID);

            if ($placeholders) {
                $blockUtils->replacePlaceholders($blockList, [], $placeholders);
            }

            $object_info = json_encode([
                'type' => 'templates',
                'id' => $row['id'],
                'name' => (translate('objects', 'blocks', false, true)['template'] ?? 'template').': '.$row['name'],
                'placeholders' => $placeholders,
            ]);

            $row['blocks'] = [];
            foreach ($blockList as $block) {
                $block['object_info'] = $object_info;
                $row['blocks'][] = $inlineEdit->wrapBlock($block);
            }

            $row['text'] = join('', array_column($row['blocks'], 'content'));
        } else {
            $row['blocks'] = [];
            $row['text'] = '';
        }

        // Label templates
        if ($row['from_label'] && empty($placeholders)) {
            $unwrapped_content = join('', array_column($row['blocks'], 'unwrapped_content')) ?: $row['text'];
            $hasPlaceholders = preg_match('/{(.+?)}/', $unwrapped_content);
            if ($hasPlaceholders) {
                // label template text contains placeholders that were not replaced,
                // because getLabelPlaceholders returned an empty array,
                // meaning that none of the selected discounts could be applied
                // in this case we don't want to display the template at all
                continue;
            }
        }

        $valueKey = $row['id'];
        if ($row['from_label']) {
            $valueKey .= "-{$row['from_label']}";
        }
        $ret[$key]['values'][$valueKey] = $row;

        if ($position = $row['product_detail_position'] ?? null) {
            if (empty($ret[$position])) {
                $ret[$position] = [];
            }

            $ret[$position][$key] = &$ret[$key];
        }
    }

    $smarty->assign($params['assign'], $ret);
}
