<?php

declare(strict_types=1);

namespace External\CykloSpecialityBundle\Resources\script;

use KupShop\AdminBundle\Util\Script\Script;
use KupShop\KupShopBundle\Util\StringUtil;
use Query\Operator;

class VariationLabelsMigrationScript extends Script
{
    protected static $defaultParameters = [
        // oldLabelId => newLabelid
        'mergeLabels' => [
            //             19 => 17,
        ],
        'changeProductsLabel' => [
            //            'products' => [351,140,31,34,37,33,35,36,216,219,217,221,226,218,225,222,223,224,227,350,352,209,232,233,231,230,234,240,169,170,206,208,191,193,192,205,189,188,190,207,213,214,215,220],
            //            'oldLabelId' => 17,
            //            'newLabelId' => 20,
        ],
    ];

    protected function run(array $arguments)
    {
        if (!empty($arguments['mergeLabels'])) {
            $this->log('Processing "mergeLabels"...');
            foreach ($arguments['mergeLabels'] as $oldLabelId => $newLabelId) {
                $this->mergeVariationLabel($oldLabelId, $newLabelId);
            }
            $this->log('Done');
        }

        if (!empty($arguments['changeProductsLabel'])) {
            $this->log('Processing "changeProductsLabel"...');
            $this->changeProductsLabel($arguments['changeProductsLabel']['oldLabelId'], $arguments['changeProductsLabel']['newLabelId'], $arguments['changeProductsLabel']['products']);
            $this->log('Done');
        }

        \Variations::updateTitle();
    }

    private function changeProductsLabel(int $oldLabelId, int $newLabelId, array $products): void
    {
        sqlGetConnection()->transactional(function () use ($oldLabelId, $newLabelId, $products) {
            $qb = sqlQueryBuilder()
                ->select('pvc.*, pvcv.value, pvcv.code, pvcv.sort, pvcv.filter_url, pvcv.title, pvcv.data')
                ->from('products_variations_combination', 'pvc')
                ->join('pvc', 'products_variations_choices_values', 'pvcv', 'pvc.id_value = pvcv.id')
                ->join('pvc', 'products_variations', 'pv', 'pv.id = pvc.id_variation')
                ->andWhere(Operator::inIntArray($products, 'pv.id_product'))
                ->andWhere(Operator::equals(['pvc.id_label' => $oldLabelId]));

            foreach ($qb->execute() as $item) {
                $newValueId = $this->getLabelValueId($newLabelId, [
                    'value' => $item['value'],
                    'code' => $item['code'],
                    'filter_url' => $item['filter_url'],
                    'title' => $item['title'],
                    'data' => $item['data'],
                ]);

                sqlQueryBuilder()
                    ->update('products_variations_combination')
                    ->directValues(['id_label' => $newLabelId, 'id_value' => $newValueId])
                    ->andWhere(Operator::equals(['id_variation' => $item['id_variation']]))
                    ->execute();
            }

            sqlQueryBuilder()
                ->update('products_variations_choices_categorization')
                ->directValues(['id_label' => $newLabelId])
                ->andWhere(Operator::inIntArray($products, 'id_product'))
                ->andWhere(Operator::equals(['id_label' => $oldLabelId]))
                ->execute();
        });
    }

    private function mergeVariationLabel(int $oldLabelId, int $newLabelId): void
    {
        sqlGetConnection()->transactional(function () use ($oldLabelId, $newLabelId) {
            $qb = sqlQueryBuilder()
                ->select('*')
                ->from('products_variations_choices_values')
                ->where(Operator::equals(['id_label' => $oldLabelId]));

            foreach ($qb->execute() as $item) {
                $newValueId = $this->getLabelValueId($newLabelId, $item);

                sqlQueryBuilder()
                    ->update('products_variations_combination')
                    ->directValues(['id_label' => $newLabelId, 'id_value' => $newValueId])
                    ->andWhere(Operator::equals(['id_label' => $item['id_label'], 'id_value' => $item['id']]))
                    ->execute();
            }

            sqlQueryBuilder()
                ->update('products_variations_choices_categorization')
                ->directValues(['id_label' => $newLabelId])
                ->where(Operator::equals(['id_label' => $oldLabelId]))
                ->execute();

            sqlQueryBuilder()
                ->delete('products_variations_choices_labels')
                ->where(Operator::equals(['id' => $oldLabelId]))
                ->execute();
        });
    }

    private function getLabelValueId(int $labelId, array $value): int
    {
        static $valuesCache = [];

        $key = StringUtil::slugify($value['value']);

        if ($valuesCache[$labelId][$key] ?? false) {
            return $valuesCache[$labelId][$key];
        }

        $valueId = sqlQueryBuilder()
            ->select('id')
            ->from('products_variations_choices_values')
            ->where(Operator::equals(['id_label' => $labelId, 'value' => $value['value']]))
            ->execute()->fetchOne();

        if (!$valueId) {
            $valueId = sqlGetConnection()->transactional(function () use ($labelId, $value) {
                $insert = $value;
                unset($insert['id']);
                $insert['id_label'] = $labelId;

                sqlQueryBuilder()
                    ->insert('products_variations_choices_values')
                    ->directValues($insert)
                    ->execute();

                return (int) sqlInsertId();
            });
        }

        return $valuesCache[$labelId][$key] = $valueId;
    }
}

return VariationLabelsMigrationScript::class;
