<?php
declare(strict_types=1);

/**
 * Точка входа плагина Shop.
 * Регистрирует:
 *   - маршруты фронта (/shop, /shop/{slug}, /cart, /checkout)
 *   - маршруты админки (/admin/shop/products, /admin/shop/orders)
 *   - async-блок корзины и витрины
 *   - inline-тег {price amount="..."}
 *   - хуки (создание заказа, смена статуса)
 */

use Celena\Core\Http\Router;
use Celena\Core\Kernel;
use Celena\Core\Template\BlockRegistry;
use Celena\Core\Template\TagRegistry;
use Celena\Plugin\Shop\Controllers\AccountController;
use Celena\Plugin\Shop\Controllers\CartController;
use Celena\Plugin\Shop\Controllers\CheckoutController;
use Celena\Plugin\Shop\Controllers\ReviewsController;
use Celena\Plugin\Shop\Controllers\ShopController;
use Celena\Plugin\Shop\Admin\AnalyticsAdminController;
use Celena\Plugin\Shop\Admin\AttributesAdminController;
use Celena\Plugin\Shop\Admin\CsvAdminController;
use Celena\Plugin\Shop\Admin\CustomersAdminController;
use Celena\Plugin\Shop\Admin\DashboardWidget;
use Celena\Plugin\Shop\Admin\ManufacturersAdminController;
use Celena\Plugin\Shop\Admin\OrdersAdminController;
use Celena\Plugin\Shop\Admin\PaymentsAdminController;
use Celena\Plugin\Shop\Admin\ProductsAdminController;
use Celena\Plugin\Shop\Admin\PromoCodesAdminController;
use Celena\Plugin\Shop\Admin\ReviewsAdminController;
use Celena\Plugin\Shop\Admin\SeoFiltersAdminController;
use Celena\Plugin\Shop\Admin\ShippingAdminController;
use Celena\Plugin\Shop\Admin\ShopSettingsAdminController;

$container = Kernel::container();

// Догоним пропущенные миграции плагина: раннер идемпотентен
// (проверяет celena_migrations), новые файлы применятся, существующие —
// пропустятся. Дешёвая операция, выполняется при каждом запросе админки.
try {
    $migrationsDir = __DIR__ . '/migrations';
    if (is_dir($migrationsDir)) {
        $runner = new \Celena\Core\Database\MigrationRunner(
            $container->make(\Celena\Core\Database\Connection::class),
            $container->make(\Celena\Core\Logger::class),
        );
        $runner->run($migrationsDir);
    }
} catch (\Throwable) {
}

/** @var Router $router */
$router = $container->make(Router::class);

// Фронт
$router->get('/shop',                              ShopController::class . '@index');
$router->get('/shop/category/{slug:[^/]+}',                          ShopController::class . '@index');
$router->get('/shop/category/{slug:[^/]+}/{seo_slug:[a-z0-9][a-z0-9-]*}', ShopController::class . '@index');
$router->get('/shop/product/{slug:[^/]+}',                           ShopController::class . '@product');
$router->get('/cart',                              CartController::class . '@show');
$router->get('/checkout',                          CheckoutController::class . '@show');
$router->post('/checkout',                         CheckoutController::class . '@submit');
$router->post('/checkout/promo-check',             CheckoutController::class . '@promoCheck');
$router->get('/checkout/thanks/{number:[A-Z0-9\-]+}', CheckoutController::class . '@thanks');

// Отзывы о товарах
$router->post('/shop/reviews/add',                 ReviewsController::class . '@add');

// Личный кабинет покупателя (/account/*): магазинные вкладки. Защищаем той же
// CustomerAuthMiddleware ядра, что и базовый кабинет (гость → /account/login).
// Базовый кабинет (профиль/пароль/выход) — в ядре; здесь только «магазинное».
$router->group(['prefix' => '/account', 'middleware' => [\Celena\Core\Http\Middleware\CustomerAuthMiddleware::class]], function (Router $r) {
    $r->get('/orders',                         AccountController::class . '@orders');
    $r->get('/orders/{number:[A-Za-z0-9\-]+}', AccountController::class . '@order');
    $r->get('/favorites',                      AccountController::class . '@favorites');
    $r->get('/favorites/items',                AccountController::class . '@favoritesItems');
    $r->get('/addresses',                      AccountController::class . '@addresses');
    $r->post('/addresses',                     AccountController::class . '@saveAddresses');
});
// Чиним мёртвую ссылку из шапки темы: /favorites → раздел кабинета.
$router->get('/favorites', fn () => \Celena\Core\Http\Response::redirect('/account/favorites'));

// Админка (под AuthMiddleware защитой из ядра — роуты /admin/* фильтруются)
// Т.к. плагин регистрирует маршруты после bootstrap, AuthMiddleware применится автоматически только
// через группу в ядре. Для простоты явно проверим auth в контроллерах.
$router->get('/admin/shop',                                 ProductsAdminController::class . '@index');
$router->get('/admin/shop/products',                        ProductsAdminController::class . '@index');
$router->get('/admin/shop/products/create',                 ProductsAdminController::class . '@create');
$router->post('/admin/shop/products/create',                ProductsAdminController::class . '@store');
$router->get('/admin/shop/products/{id:\d+}/edit',          ProductsAdminController::class . '@edit');
$router->post('/admin/shop/products/{id:\d+}/update',       ProductsAdminController::class . '@update');
$router->post('/admin/shop/products/{id:\d+}/delete',       ProductsAdminController::class . '@delete');
$router->post('/admin/shop/products/{id:\d+}/toggle-featured', ProductsAdminController::class . '@toggleFeatured');
$router->get('/admin/shop/orders',                          OrdersAdminController::class . '@index');
$router->get('/admin/shop/orders/create',                   OrdersAdminController::class . '@create');
$router->post('/admin/shop/orders/create',                  OrdersAdminController::class . '@storeManual');
$router->get('/admin/shop/orders/search-products',          OrdersAdminController::class . '@searchProducts');
$router->get('/admin/shop/orders/search-customers',         OrdersAdminController::class . '@searchCustomers');
$router->get('/admin/shop/orders/{id:\d+}',                 OrdersAdminController::class . '@show');
$router->post('/admin/shop/orders/{id:\d+}/status',         OrdersAdminController::class . '@setStatus');
$router->post('/admin/shop/orders/{id:\d+}/payment-status', OrdersAdminController::class . '@setPaymentStatus');
$router->post('/admin/shop/orders/{id:\d+}/details',        OrdersAdminController::class . '@updateDetails');
$router->post('/admin/shop/orders/{id:\d+}/note',           OrdersAdminController::class . '@addNote');

// Клиенты магазина
$router->get('/admin/shop/customers',                       CustomersAdminController::class . '@index');
$router->get('/admin/shop/customers/{id:\d+}',              CustomersAdminController::class . '@show');
$router->post('/admin/shop/customers/{id:\d+}/update',      CustomersAdminController::class . '@update');
$router->post('/admin/shop/customers/{id:\d+}/delete',      CustomersAdminController::class . '@delete');

// Производители
$router->get('/admin/shop/manufacturers',                          ManufacturersAdminController::class . '@index');
$router->get('/admin/shop/manufacturers/create',                   ManufacturersAdminController::class . '@create');
$router->post('/admin/shop/manufacturers/create',                  ManufacturersAdminController::class . '@store');
$router->get('/admin/shop/manufacturers/{id:\d+}/edit',            ManufacturersAdminController::class . '@edit');
$router->post('/admin/shop/manufacturers/{id:\d+}/update',         ManufacturersAdminController::class . '@update');
$router->post('/admin/shop/manufacturers/{id:\d+}/delete',         ManufacturersAdminController::class . '@delete');

// Атрибуты
$router->get('/admin/shop/attributes',                             AttributesAdminController::class . '@index');
$router->get('/admin/shop/attributes/create',                      AttributesAdminController::class . '@create');
$router->post('/admin/shop/attributes/create',                     AttributesAdminController::class . '@store');
$router->get('/admin/shop/attributes/{id:\d+}/edit',               AttributesAdminController::class . '@edit');
$router->post('/admin/shop/attributes/{id:\d+}/update',            AttributesAdminController::class . '@update');
$router->post('/admin/shop/attributes/{id:\d+}/delete',            AttributesAdminController::class . '@delete');

// SEO-фильтры (конструктор подмены H1/мета-тегов на витрине)
$router->get('/admin/shop/seo-filters',                            SeoFiltersAdminController::class . '@index');
$router->get('/admin/shop/seo-filters/create',                     SeoFiltersAdminController::class . '@create');
$router->post('/admin/shop/seo-filters/create',                    SeoFiltersAdminController::class . '@store');
$router->get('/admin/shop/seo-filters/{id:\d+}/edit',              SeoFiltersAdminController::class . '@edit');
$router->post('/admin/shop/seo-filters/{id:\d+}/update',           SeoFiltersAdminController::class . '@update');
$router->post('/admin/shop/seo-filters/{id:\d+}/delete',           SeoFiltersAdminController::class . '@delete');

// Промокоды
$router->get('/admin/shop/promocodes',                             PromoCodesAdminController::class . '@index');
$router->get('/admin/shop/promocodes/create',                      PromoCodesAdminController::class . '@create');
$router->post('/admin/shop/promocodes/create',                     PromoCodesAdminController::class . '@store');
$router->get('/admin/shop/promocodes/{id:\d+}/edit',               PromoCodesAdminController::class . '@edit');
$router->post('/admin/shop/promocodes/{id:\d+}/update',            PromoCodesAdminController::class . '@update');
$router->post('/admin/shop/promocodes/{id:\d+}/delete',            PromoCodesAdminController::class . '@delete');

// Доставка
$router->get('/admin/shop/shipping',                               ShippingAdminController::class . '@index');
$router->get('/admin/shop/shipping/create',                        ShippingAdminController::class . '@create');
$router->post('/admin/shop/shipping/create',                       ShippingAdminController::class . '@store');
$router->get('/admin/shop/shipping/{id:\d+}/edit',                 ShippingAdminController::class . '@edit');
$router->post('/admin/shop/shipping/{id:\d+}/update',              ShippingAdminController::class . '@update');
$router->post('/admin/shop/shipping/{id:\d+}/delete',              ShippingAdminController::class . '@delete');

// Оплата
$router->get('/admin/shop/payments',                               PaymentsAdminController::class . '@index');
$router->get('/admin/shop/payments/create',                        PaymentsAdminController::class . '@create');
$router->post('/admin/shop/payments/create',                       PaymentsAdminController::class . '@store');
$router->get('/admin/shop/payments/{id:\d+}/edit',                 PaymentsAdminController::class . '@edit');
$router->post('/admin/shop/payments/{id:\d+}/update',              PaymentsAdminController::class . '@update');
$router->post('/admin/shop/payments/{id:\d+}/delete',              PaymentsAdminController::class . '@delete');

// CSV: импорт/экспорт каталога
$router->get('/admin/shop/products/import',                        CsvAdminController::class . '@importForm');
$router->post('/admin/shop/products/import',                       CsvAdminController::class . '@importRun');
$router->get('/admin/shop/products/export',                        CsvAdminController::class . '@exportForm');
$router->post('/admin/shop/products/export',                       CsvAdminController::class . '@exportRun');

// Аналитика
$router->get('/admin/shop/analytics',                              AnalyticsAdminController::class . '@index');

// Отзывы
$router->get('/admin/shop/reviews',                                ReviewsAdminController::class . '@index');
$router->post('/admin/shop/reviews/{id:\d+}/approve',              ReviewsAdminController::class . '@approve');
$router->post('/admin/shop/reviews/{id:\d+}/delete',               ReviewsAdminController::class . '@delete');

// Настройки магазина
$router->get('/admin/shop/settings',                               ShopSettingsAdminController::class . '@index');
$router->post('/admin/shop/settings/save',                         ShopSettingsAdminController::class . '@save');

// Грейсфул-режим темы: при активном плагине магазина включаем флаг shop.enabled='1'.
// Тема Bunzo (и любая другая) использует [if {shop.enabled}="1"]...[/if] чтобы показывать
// пункт меню «Магазин», секцию товаров на главной и иконку корзины в шапке только когда
// плагин действительно активен.
\Celena\Core\Plugin\Hook::addFilter('template.globals', function (array $vars) use ($container): array {
    if (!isset($vars['shop']) || !is_array($vars['shop'])) {
        $vars['shop'] = [];
    }
    $vars['shop']['enabled'] = '1';
    // Открываем настройки магазина в шаблоны: {shop.currency_symbol}, {shop.store_name} и т.д.
    try {
        $shop = new \Celena\Plugin\Shop\Support\ShopSettings(
            $container->make(\Celena\Module\Settings\Options::class)
        );
        foreach ($shop->all() as $key => $value) {
            $short = substr($key, 5); // 'shop.' → ''
            $vars['shop'][$short] = $value;
        }
    } catch (\Throwable) {
    }
    return $vars;
}, 50);

// Async-блок корзины — статичная болванка; shop.js наполняет её из localStorage
$container->make(BlockRegistry::class)->register('shop_cart_widget', function ($c) {
    return [
        'template' => 'plugins/shop/async/cart_widget',
        'vars' => [],
    ];
});

// Inline-тег {price amount="1234.5"} → форматирование по настройкам магазина
// (символ валюты, позиция, разделители, число знаков после запятой).
// Параметры тега имеют приоритет над дефолтами из настроек.
$container->make(TagRegistry::class)->registerInline('price', function (array $params) use ($container) {
    $amount = (float) ($params['amount'] ?? 0);
    try {
        $shop = new \Celena\Plugin\Shop\Support\ShopSettings(
            $container->make(\Celena\Module\Settings\Options::class)
        );
    } catch (\Throwable) {
        return number_format($amount, 0, '.', ' ');
    }
    if (isset($params['currency']) && $params['currency'] !== '') {
        $decimals = isset($params['decimals']) ? (int) $params['decimals'] : $shop->int('shop.price_decimals', 0);
        $thousands = $shop->get('shop.thousands_sep') ?: ' ';
        $decSep = $shop->get('shop.decimal_sep') ?: '.';
        $num = number_format($amount, $decimals, $decSep, $thousands);
        return $num . ' ' . htmlspecialchars((string) $params['currency'], ENT_QUOTES, 'UTF-8');
    }
    return htmlspecialchars($shop->formatPrice($amount), ENT_QUOTES, 'UTF-8');
});

// Inline-тег {currency} → символ валюты из настроек ('$', '€', '₴', …).
// Удобно для подписей форм: «Цена от, {currency}».
$container->make(TagRegistry::class)->registerInline('currency', function (array $params) use ($container) {
    try {
        $shop = new \Celena\Plugin\Shop\Support\ShopSettings(
            $container->make(\Celena\Module\Settings\Options::class)
        );
        return htmlspecialchars($shop->currencySymbol(), ENT_QUOTES, 'UTF-8');
    } catch (\Throwable) {
        return '';
    }
});

// Блок-тег [products category="..." limit="..."] ... [/products]
// Подключает универсальный ContentListTag с источником ProductsContentSource.
// FieldRepository передаётся вторым параметром, чтобы тег [products]
// возвращал ещё и характеристики из custom fields (как и страница категории).
$container->make(TagRegistry::class)->registerBlock('products', new \Celena\Core\Template\Tags\ContentListTag(
    function (array $params) use ($container): array {
        $conn = $container->make(\Celena\Core\Database\Connection::class);
        return (new \Celena\Plugin\Shop\Sources\ProductsContentSource(
            $conn,
            new \Celena\Module\CustomFields\FieldRepository($conn)
        ))->fetch($params);
    },
    ['limit' => 12, 'sort' => 'id', 'order' => 'desc'],
));

// Пункт сайдбара админки с подменю: Магазин → Товары / Заказы / …
// Все тексты — через Translator (shop.title, shop.menu.*).
// Иконки — SVG (одноцветные), не эмодзи.
\Celena\Core\Plugin\Hook::addFilter('admin.sidebar', function (array $items) use ($container) {
    $icon = new \Celena\Core\Template\Tags\IconTag();
    /** @var \Celena\Core\I18n\Translator $tr */
    $tr = $container->make(\Celena\Core\I18n\Translator::class);
    $items[] = [
        'svg'   => $icon(['name' => 'cart', 'size' => 22, 'class' => 'sb-ico']),
        'label' => $tr->translate('shop.title'),
        'url'   => '/admin/shop/products',
        'slug'  => 'shop',
        'active_slugs' => [
            'shop', 'shop-orders', 'shop-customers', 'shop-manufacturers', 'shop-attributes',
            'shop-seo-filters', 'shop-promocodes', 'shop-shipping', 'shop-payments',
            'shop-csv', 'shop-analytics', 'shop-reviews', 'shop-settings',
            'cities',
        ],
        'children' => [
            ['url' => '/admin/shop/products',        'label' => $tr->translate('shop.menu.products'),      'slug' => 'shop'],
            ['url' => '/admin/shop/manufacturers',   'label' => $tr->translate('shop.menu.manufacturers'), 'slug' => 'shop-manufacturers'],
            ['url' => '/admin/shop/attributes',      'label' => $tr->translate('shop.menu.attributes'),    'slug' => 'shop-attributes'],
            ['url' => '/admin/shop/seo-filters',     'label' => 'SEO-фильтры',                              'slug' => 'shop-seo-filters'],
            ['url' => '/admin/shop/orders',          'label' => $tr->translate('shop.menu.orders'),        'slug' => 'shop-orders'],
            ['url' => '/admin/shop/customers',       'label' => $tr->translate('shop.menu.customers'),     'slug' => 'shop-customers'],
            ['url' => '/admin/shop/shipping',        'label' => $tr->translate('shop.menu.shipping'),      'slug' => 'shop-shipping'],
            ['url' => '/admin/cities',               'label' => $tr->translate('shop.menu.cities'),        'slug' => 'cities'],
            ['url' => '/admin/shop/payments',        'label' => $tr->translate('shop.menu.payments'),      'slug' => 'shop-payments'],
            ['url' => '/admin/shop/promocodes',      'label' => $tr->translate('shop.menu.promocodes'),    'slug' => 'shop-promocodes'],
            ['url' => '/admin/shop/reviews',         'label' => $tr->translate('shop.menu.reviews'),       'slug' => 'shop-reviews'],
            ['url' => '/admin/shop/analytics',       'label' => $tr->translate('shop.menu.analytics'),     'slug' => 'shop-analytics'],
            ['url' => '/admin/shop/products/import', 'label' => $tr->translate('shop.menu.csv_import'),    'slug' => 'shop-csv'],
            ['url' => '/admin/shop/settings',        'label' => $tr->translate('shop.menu.settings'),      'slug' => 'shop-settings'],
        ],
    ];
    return $items;
});

// Регистрируем сущность «Товары» для модуля доп. полей.
// Пользователь сможет создать поле (цена, вес, бренд) и привязать его к товарам.
\Celena\Core\Plugin\Hook::addFilter('customfields.entities', function (array $entities): array {
    $entities[] = ['slug' => 'shop_product', 'label' => 'Товары (магазин)'];
    return $entities;
});

// И сущность «Товары» в общей системе категорий: создавая категорию в админке,
// её можно привязать к новостям, страницам или товарам магазина.
\Celena\Core\Plugin\Hook::addFilter('categories.entities', function (array $entities): array {
    $entities[] = ['slug' => 'shop_product', 'label' => 'Товары (магазин)'];
    return $entities;
});

// При удалении категории — отвязать товары.
\Celena\Core\Plugin\Hook::on('category.deleted', function (array $cat) use ($container): void {
    if (($cat['entity_type'] ?? '') !== 'shop_product') return;
    try {
        $conn = $container->make(\Celena\Core\Database\Connection::class);
        $conn->builder('shop_products')->where('category_id', '=', (int) ($cat['id'] ?? 0))->update(['category_id' => null]);
    } catch (\Throwable) {
    }
});

// Интеграция в общий поиск (/search?q=...). Плагин подписывается на фильтр
// 'search.sources' — каждый плагин может добавить свои элементы в общий результат.
\Celena\Core\Plugin\Hook::addFilter('search.sources', function (array $rows, string $q) use ($container): array {
    $q = trim($q);
    if (mb_strlen($q, 'UTF-8') < 2) return $rows;
    try {
        $conn = $container->make(\Celena\Core\Database\Connection::class);
        $pattern = '%' . mb_strtolower($q, 'UTF-8') . '%';
        $sql = 'SELECT id, slug, title, short, body, price, old_price, cover, sku, stock, created_at FROM '
            . $conn->table_q('shop_products')
            . ' WHERE is_active = ? AND ('
            . 'LOWER(' . $conn->quoteId('title') . ') LIKE ? OR '
            . 'LOWER(' . $conn->quoteId('short') . ') LIKE ? OR '
            . 'LOWER(' . $conn->quoteId('sku')   . ') LIKE ? OR '
            . 'LOWER(' . $conn->quoteId('body')  . ') LIKE ?)'
            . ' LIMIT 100';
        $products = $conn->run($sql, [true, $pattern, $pattern, $pattern, $pattern])->fetchAll();
        foreach ($products as $p) {
            $rows[] = [
                'id'         => (int) $p['id'],
                'slug'       => (string) $p['slug'],
                'title'      => (string) $p['title'],
                'snippet'    => (string) ($p['short'] ?? ''),
                'date'       => (string) ($p['created_at'] ?? ''),
                'kind'       => 'product',
                'kind_label' => 'Товар',
                'url'        => '/shop/product/' . (string) $p['slug'],
                'cover'      => (string) ($p['cover'] ?? ''),
                'sku'        => (string) ($p['sku'] ?? ''),
                'stock'      => (int) ($p['stock'] ?? 0),
                'price'      => (float) ($p['price'] ?? 0),
                'price_fmt'  => number_format((float) ($p['price'] ?? 0), 2, '.', ' '),
                'old_price'  => $p['old_price'] !== null ? (float) $p['old_price'] : null,
                'old_price_fmt' => !empty($p['old_price'])
                    ? number_format((float) $p['old_price'], 2, '.', ' ') : '',
            ];
        }
    } catch (\Throwable $e) {
    }
    return $rows;
}, 20);

// Виджет «Витрина магазина» в главный дашборд админки.
// Подписываемся на универсальный фильтр секций — ядро не знает о магазине.
\Celena\Core\Plugin\Hook::addFilter('admin.dashboard.sections', function (array $sections) use ($container): array {
    try {
        $widget = new DashboardWidget(
            $container->make(\Celena\Core\Template\Engine::class),
            $container->make(\Celena\Core\Database\Connection::class),
            $container->make(\Celena\Module\Settings\Options::class),
        );
        $sections[] = [
            'id'       => 'shop',
            'html'     => $widget->render(),
            'position' => 'top',
            'sort'     => 10,
        ];
    } catch (\Throwable) {
    }
    return $sections;
});

// Уведомления в колокольчике: новые заказы (status = 'new')
\Celena\Core\Plugin\Hook::addFilter('admin.notifications', function (array $items) use ($container): array {
    try {
        $conn = $container->make(\Celena\Core\Database\Connection::class);
        $rows = $conn->builder('shop_orders')
            ->where('status', '=', 'new')
            ->orderBy('created_at', 'desc')
            ->limit(10)
            ->get();
        foreach ($rows as $o) {
            $items[] = [
                'title' => 'Новый заказ ' . (string) $o['number'],
                'text'  => (string) ($o['customer_name'] ?? '') . ' — '
                           . number_format((float) $o['total'], 2, '.', ' ') . ' ' . (string) ($o['currency'] ?? ''),
                'url'   => '/admin/shop/orders/' . (int) $o['id'],
                'time'  => (string) ($o['created_at'] ?? ''),
            ];
        }
    } catch (\Throwable $e) {
    }
    return $items;
});

// ───────── Личный кабинет покупателя: вкладки + привязка гостевых заказов ─────────
// Ядро рендерит навигацию кабинета из фильтра account.tabs — магазин добавляет свои
// разделы, не трогая ядро.
\Celena\Core\Plugin\Hook::addFilter('account.tabs', function (array $tabs, $user): array {
    $tabs[] = ['slug' => 'orders',    'label' => 'Мои заказы', 'url' => '/account/orders',    'icon' => 'cart',  'sort' => 30];
    $tabs[] = ['slug' => 'favorites', 'label' => 'Избранное',  'url' => '/account/favorites', 'icon' => 'heart', 'sort' => 40];
    $tabs[] = ['slug' => 'addresses', 'label' => 'Адреса',     'url' => '/account/addresses', 'icon' => 'pages', 'sort' => 50];
    return $tabs;
});

// При входе/регистрации (ядровый экшен account.authenticated) — привязываем к user_id
// гостевые заказы и карточку клиента, оформленные тем же email до регистрации.
\Celena\Core\Plugin\Hook::on('account.authenticated', function ($user) use ($container): void {
    if (!is_array($user) || empty($user['id']) || empty($user['email'])) {
        return;
    }
    try {
        $conn = $container->make(\Celena\Core\Database\Connection::class);
        $uid = (int) $user['id'];
        $email = mb_strtolower(trim((string) $user['email']), 'UTF-8');
        $conn->run(
            'UPDATE ' . $conn->table_q('shop_orders')
            . ' SET ' . $conn->quoteId('user_id') . ' = ?'
            . ' WHERE LOWER(' . $conn->quoteId('customer_email') . ') = ?'
            . ' AND (' . $conn->quoteId('user_id') . ' IS NULL OR ' . $conn->quoteId('user_id') . ' = 0)',
            [$uid, $email]
        );
        $cust = $conn->builder('shop_customers')->where('email', '=', $email)->first();
        if ($cust !== null && empty($cust['user_id'])) {
            $conn->builder('shop_customers')->where('id', '=', (int) $cust['id'])->update(['user_id' => $uid]);
        }
    } catch (\Throwable) {
    }
});
