<?php

use KupShop\AdminBundle\Util\AdminSectionTree;
use KupShop\CatalogBundle\Section\SectionFilter;
use KupShop\CatalogBundle\Util\FilterUtil;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use Query\Operator;

$main_class = 'ProductsVarLabels';

class ProductsVarLabels extends Window
{
    protected $tableName = 'products_variations_choices_labels';
    protected $nameField = 'label';
    protected $template = 'window/productsVarLabels.tpl';
    private AdminSectionTree $adminSectionTree;
    protected $uniques = ['code'];

    public function __construct()
    {
        $this->adminSectionTree = ServiceContainer::getService(AdminSectionTree::class);
    }

    public function get_vars()
    {
        $vars = parent::get_vars();

        $pageVars = getVal('body', $vars, []);

        $ID = getVal('ID');
        $pageVars['product_variations_rights'] = findModule('products_variations');

        $pageVars['productsVarLabels']['ID'] = $ID;

        $pageVars['tree'] = $this->adminSectionTree->getCategories();
        $pageVars['selected'] = $this->adminSectionTree->getSelected($this->getID(), 'products_variations_sections', 'id_label');
        $this->adminSectionTree->getOpened($pageVars['tree']);
        $pageVars['opened'] = $this->adminSectionTree->opened;

        if (getVal('valueId') != null) {
            $pageVars['valueId'] = getVal('valueId');
        }

        if ($this->getAction() == 'edit' && !empty($ID)) {
            $pageVars['SQL_row'] = [];

            $qbLabelValues = sqlQueryBuilder()
                ->select('*, COUNT(pvc.id_variation) AS noVariants')
                ->from('products_variations_choices_values', 'pvcv')
                ->leftJoin('pvcv', 'products_variations_combination', 'pvc', 'pvc.id_value = pvcv.id')
                ->where(\Query\Operator::equals(['pvcv.id_label' => $ID]))
                ->groupBy('pvcv.id')
                ->orderBy('sort');

            foreach ($qbLabelValues->execute() as $row) {
                $this->unserializeCustomData($row);
                $pageVars['SQL_row'][] = $row;
            }

            unset($row);
        }

        if ($this->getAction() == 'deleteValue' && isset($pageVars['valueId']) && is_numeric($pageVars['valueId'])) {
            $SQL = sqlQuery('SELECT id_label, value
			   FROM '.getTableName('products_variations_choices_values')."
			   WHERE id='{$pageVars['valueId']}'");
            $pageVars['Row'] = sqlFetchArray($SQL);
            $pageVars['Row']['value'] = htmlspecialchars($pageVars['Row']['value']);
            $pageVars['Row']['id_label'] = getVal('IDLabelSel', null, $pageVars['Row']['id_label']);
            unset($SQL, $row);

            $SQL = sqlQuery('SELECT id, value
			   FROM '.getTableName('products_variations_choices_values')."
			   WHERE id_label={$pageVars['Row']['id_label']} AND id!={$pageVars['valueId']}");
            while ($row = sqlFetchAssoc($SQL)) {
                $pageVars['SQL_variants'][] = $row;
            }
            unset($SQL, $row);

            $SQL = sqlQuery('SELECT pvcl.label, pvcl.id
			   FROM '.getTableName('products_variations_choices_labels').' pvcl');
            while ($row = sqlFetchAssoc($SQL)) {
                $pageVars['SQL_moves'][] = $row;
            }
            unset($SQL, $row);
            if (!empty($pageVars['Row']['id_label'])) {
                $this->ID = $pageVars['Row']['id_label'];
            }
            $pageVars['variations_count'] = returnSQLResult('SELECT COUNT(id_value) FROM products_variations_combination WHERE id_value=:id_value', ['id_value' => $pageVars['valueId']]);
            $pageVars['data'] = $this->getObject();
        }
        $pageVars['data']['searchTerm'] = getVal('searchTerm');
        $vars['body'] = $pageVars;
        unset($vars['type']);
        $vars['type'] = 'productsVarLabels';

        return $vars;
    }

    public function handle()
    {
        try {
            $ID = getVal('ID');
            $data = $this->getData();

            $pvls = getVal('prodLabels', $data, []);

            $sort_index = 0;
            foreach ($pvls as $key => $row) {
                if ($key > 0) {
                    $sort_index++;
                }
            }

            foreach ($pvls as $id => $pvl) {
                $pvl['id_label'] = $ID;
                if (!$pvl['code']) {
                    $pvl['code'] = null;
                }
                if (empty($pvl['value']) || !empty($pvl['delete']) || (empty($pvl['changed']) && $pvl['id'] > 0)) {
                    continue;
                }

                $this->serializeCustomData($pvl);

                if ($id < 0) {
                    $pvl['sort'] = $sort_index++;
                    $this->insertSQL('products_variations_choices_values', $pvl, ['changed']);
                } else {
                    $this->updateSQL('products_variations_choices_values', $pvl, ['id' => $pvl['id']], ['changed']);
                    Variations::updateTitle(null, $pvl['id']);
                }
            }
            if (findModule(Modules::INDEXED_FILTER)) {
                \KupShop\IndexedFilterBundle\Util\FilterUrlDefaultValue::upgrade_filter_url('products_variations_choices_values');
            }
        } catch (Doctrine\DBAL\DBALException $e) {
            switch (intval($e->getPrevious()->errorInfo[1])) {
                case 1062:
                    $this->returnError('Duplicitní kód!');
                    // no break
                default:
                    throw $e;
            }
        }
        parent::handle();
    }

    public function handleUpdate()
    {
        $sec = getVal('sec', null, []);
        $ID = $this->getID();

        if (findModule('products_variations')) {
            if (FilterUtil::useOrderableFilters()) {
                $existingIdsMap = sqlQueryBuilder()
                    ->select('sf.id_source_section', 'sf.id')
                    ->from('sections_filters', 'sf')
                    ->andWhere(Operator::equals(['sf.id_variation_label' => $ID]))
                    ->andWhere('sf.id_source_section IS NOT NULL')
                    ->execute()
                    ->fetchAllKeyValue();

                $relationsToDelete = sqlQueryBuilder()
                    ->select('pvs.id_section')
                    ->from('products_variations_sections', 'pvs')
                    ->andWhere(Operator::equals(['pvs.id_label' => $ID]));

                if (!empty($sec)) {
                    $relationsToDelete->andWhere(Operator::not(
                        Operator::inIntArray(array_keys($sec), 'pvs.id_section'),
                    ));
                }

                $sectionFilters = [];

                // delete
                $relationsToDelete = $relationsToDelete->execute()->fetchFirstColumn();
                foreach ($relationsToDelete as $sectionIdToDelete) {
                    $id = $existingIdsMap[$sectionIdToDelete] ?? null;

                    if ($id === null) {
                        continue;
                    }

                    $sectionFilters[] = SectionFilter::deleteVariation(
                        id: $id,
                        variationLabelId: (int) $ID,
                        sectionId: (int) $sectionIdToDelete,
                    );
                }

                // upsert
                foreach ($sec as $sectionId => $_) {
                    $id = $existingIdsMap[$sectionId] ?? null;

                    $sectionFilters[] = SectionFilter::variation(
                        id: $id,
                        variationLabelId: (int) $ID,
                        sectionId: (int) $sectionId,
                        enabled: true,
                        position: FilterUtil::POSITION_LAST,
                    );
                }

                if (!empty($sectionFilters)) {
                    $filterUtil = ServiceContainer::getService(FilterUtil::class);
                    $filterUtil->updateSectionFilters($sectionFilters);
                }
            } else {
                sqlQueryBuilder()->delete('products_variations_sections')
                    ->where(\Query\Operator::equals(['id_label' => $ID]))
                    ->andWhere(\Query\Operator::not(\Query\Operator::inIntArray(array_keys($sec), 'id_section')))
                    ->execute();

                foreach ($sec as $key => $value) {
                    if (!empty($key)) {
                        sqlQuery("INSERT IGNORE INTO products_variations_sections 
										SET id_label='{$ID}', id_section='{$key}' ");
                    }
                }
                unset($key, $value);
            }
        }
        $SQL = parent::handleUpdate();

        if (empty($ID)) {
            $this->setID(sqlInsertID());
        }

        return $SQL;
    }

    public function handleSubmitAll()
    {
        $items = getVal('items');
        if (!empty($items)) {
            sqlStartTransaction();

            $query = '';
            foreach ($items as $id => $item) {
                $SQL = sqlQuery('UPDATE '.getTableName('products_variations_choices_values').'
					SET '.queryCreate(['value' => $item['value'], 'code' => $item['code'], 'sort' => $item['sort']], true)."
					WHERE id='{$id}' ");
            }

            sqlFinishTransaction();
        }
    }

    public function handleSortAlphabet()
    {
        $ID = $this->getID();
        $query = 'UPDATE '.getTableName('products_variations_choices_values').' pvcv
			  LEFT JOIN (SELECT a.id, a.id_label, a.value, count(*) as rowNumber
			  FROM '.getTableName('products_variations_choices_values').' a
			  JOIN '.getTableName('products_variations_choices_values')." b ON a.id_label = b.id_label AND a.value >= b.value
			  WHERE a.id_label='{$ID}'
			  GROUP BY a.id_label, a.value) s ON pvcv.id=s.id
			  SET pvcv.sort=s.rowNumber
			  WHERE pvcv.id_label='{$ID}'";
        $SQL = sqlQuery($query);
        $this->returnOK();
        // redirect("launch.php?s=productsVarLabels.php&acn=edit&ID=".$ID."&ErrStr=".$ErrStr);
    }

    public function handleDeleteValue()
    {
        $IDvalSel = getVal('IDvalSel');
        $IDLabelSel = getVal('IDLabelSel');
        $valueId = getVal('valueId');

        $method = getVal('method');

        if (!empty($valueId) && !empty($method)) {
            $labelOld = returnSQLResult('SELECT id_label
                FROM products_variations_choices_values
                WHERE id=:value_id', ['value_id' => $valueId]);

            switch ($method) {
                case 'delete_values':
                    sqlQuery('DELETE pv FROM products_variations pv
                     JOIN products_variations_combination pvc ON pvc.id_variation = pv.id
                     WHERE id_value=:value_id', ['value_id' => $valueId]);

                    sqlQuery('DELETE FROM products_variations_choices_values	WHERE id=:value_id', ['value_id' => $valueId]);
                    break;

                case 'replace_values':
                    $IDLabelSel = $labelOld;
                    sqlQuery('INSERT INTO products_variations_choices_categorization
                         SELECT pvcc.id_product, :id_label_sel, pvcc.list_order+1
                         FROM products_variations_choices_categorization pvcc
                         WHERE id_label=:id_label_old AND (
                           SELECT COUNT(*)
                           FROM products_variations_choices_categorization pvcc2
                           WHERE pvcc2.id_label=:id_label_sel AND pvcc2.id_product=pvcc.id_product
                         ) = 0', ['id_label_old' => $labelOld, 'id_label_sel' => $IDLabelSel]);

                    sqlQuery('UPDATE IGNORE products_variations_combination SET id_value=:id_val_sel, id_label=:id_label_sel WHERE id_value=:value_id',
                        ['id_val_sel' => $IDvalSel, 'value_id' => $valueId, 'id_label_sel' => $IDLabelSel]);

                    sqlQuery('DELETE FROM products_variations_choices_values	WHERE id=:value_id',
                        ['value_id' => $valueId]);
                    break;

                case 'move_values':
                    try {
                        sqlGetConnection()->transactional(function () use ($labelOld, $IDLabelSel, $valueId) {
                            sqlQuery('
                                INSERT INTO products_variations_choices_categorization (id_product, id_label, list_order)
                                    SELECT pvcc.id_product, :id_label_sel, pvcc.list_order+1
                                    FROM products_variations_choices_categorization pvcc
                                    JOIN products_variations_combination pvc ON pvc.id_label=pvcc.id_label AND pvc.id_value=:id_value
                                    JOIN products_variations pv ON pv.id = pvc.id_variation AND pvcc.id_product=pv.id_product
                                    WHERE pvcc.id_label=:id_label_old AND (
                                       SELECT COUNT(*)
                                       FROM products_variations_choices_categorization pvcc2
                                       WHERE pvcc2.id_label=:id_label_sel AND pvcc2.id_product=pvcc.id_product
                                     ) = 0
                                    GROUP BY pvcc.id_product;
                        ', ['id_label_old' => $labelOld, 'id_label_sel' => $IDLabelSel, 'id_value' => $valueId]);

                            // check for value if exists in new label
                            $value = $this->selectSQL('products_variations_choices_values', ['id' => $valueId], ['value'])->fetchColumn();

                            if ($valueNew = $this->selectSQL('products_variations_choices_values', ['id_label' => $IDLabelSel, 'value' => $value], ['id'])->fetchColumn()) {
                                sqlQuery('UPDATE products_variations_combination SET id_label = :id_label_sel, id_value = :id_value_new WHERE id_value = :value_id',
                                    ['value_id' => $valueId, 'id_value_new' => $valueNew, 'id_label_sel' => $IDLabelSel]);
                                $this->deleteSQL('products_variations_choices_values', ['id' => $valueId]);
                            } else {
                                sqlQuery(
                                    'UPDATE products_variations_combination SET id_label=:id_label_sel WHERE id_value=:value_id',
                                    ['value_id' => $valueId, 'id_label_sel' => $IDLabelSel]
                                );
                                $position = returnSQLResult('SELECT MAX(pv.sort)+1 FROM products_variations_choices_values AS pv WHERE id_label=:id_label', ['id_label' => $IDLabelSel]);
                                sqlQuery(
                                    'UPDATE products_variations_choices_values SET id_label=:id_label_sel, sort=:position WHERE id=:value_id',
                                    ['value_id' => $valueId, 'position' => $position, 'id_label_sel' => $IDLabelSel]
                                );
                            }

                            sqlQuery('
                           DELETE pvcc from products_variations_choices_categorization pvcc
                            WHERE pvcc.id_product NOT IN (
                              SELECT pv.id_product
                              FROM products_variations_combination pvc
                              JOIN products_variations pv on pvc.id_variation = pv.id
                              WHERE pvc.id_label=pvcc.id_label
                            )');
                        });
                    } catch (Exception $e) {
                        switch (intval($e->getPrevious()->errorInfo[1])) {
                            case 1062:
                                $this->returnError('Hodnota jmenovky s daným kódem je již u cílové jmenovky přiřazena!', null, $labelOld);
                                // no break
                            default:
                        }
                    }
            }

            $_REQUEST['flap'] = 'flapVarLabel';
            $this->returnError(null, null, $labelOld);
        }
    }

    public function handleDelete()
    {
        if (sqlQueryBuilder()
            ->select('*')
            ->from('products_variations_combination')
            ->where(\Query\Operator::equals(['id_label' => $this->getID()]))
            ->execute()->fetch()) {
            $this->returnError('Jmenovku nelze smazat, má hodnoty! Nejprve odstraňte nebo přesuňte všechny její hodnoty.');
        }

        if (findModule(Modules::CONVERTORS)) {
            if (sqlQueryBuilder()
                ->select('*')
                ->from('convertors_definition')
                ->where(\Query\Operator::equals(['id_label' => $this->getID()]))
                ->execute()->fetchOne()) {
                $this->returnError('Jmenovku nelze smazat, používá se v převodníku!');
            }
        }

        parent::handleDelete();
    }
}
