<?php
declare(strict_types=1);

namespace Celena\Plugin\Shop\Support;

use Celena\Core\Database\Connection;
use Celena\Module\CustomFields\FieldRepository;

/**
 * Helper для сборки characteristics товара из всех доступных источников:
 *   1. custom fields (celena_custom_field_values для entity_type='shop_product')
 *   2. shop_products.options  — вариации (Цвет/Размер)
 *   3. shop_products.attributes — плоский JSON ключ→значение (legacy)
 *   4. shop_attribute_values   — типизированные атрибуты с единицами и фильтруемостью
 *
 * Используется ShopController (страница категории) и ProductsContentSource
 * (тег [products] на главной/в виджетах). Helper, а не сервис, чтобы плагин
 * мог вызывать без DI.
 */
final class ProductSpecs
{
    /**
     * Подготовить мапу slug => [label, type] из custom fields для shop_product.
     * @return array<string, array{label:string, type:string}>
     */
    public static function preloadCfFields(FieldRepository $repo): array
    {
        $fields = $repo->fieldsFor('shop_product');
        $out = [];
        foreach ($fields as $f) {
            $out[(string) $f['slug']] = [
                'label' => (string) $f['label'],
                'type'  => (string) $f['type'],
            ];
        }
        return $out;
    }

    /**
     * Собрать список характеристик: максимум 8 пар [{label, value}].
     * Если передан Connection — подтягиваются значения из shop_attribute_values
     * (типизированные атрибуты — Бренд, Цвет, Объём и т.п.).
     *
     * @param array<string, mixed> $product
     * @param array<string, string> $cfValues   slug => raw value
     * @param array<string, array{label:string,type:string}> $fieldByLabel
     * @return list<array{label:string, value:string}>
     */
    public static function extract(array $product, array $cfValues = [], array $fieldByLabel = [], ?Connection $conn = null): array
    {
        $specs = [];
        $maxSpecs = 8;

        // 0) Типизированные атрибуты (приоритетный источник, если БД доступна).
        if ($conn !== null && !empty($product['id'])) {
            try {
                $sql = 'SELECT a.' . $conn->quoteId('title') . ' AS title, '
                    . 'a.' . $conn->quoteId('type') . ' AS type, '
                    . 'a.' . $conn->quoteId('unit') . ' AS unit, '
                    . 'av.' . $conn->quoteId('value') . ' AS value '
                    . 'FROM ' . $conn->table_q('shop_attribute_values') . ' av '
                    . 'INNER JOIN ' . $conn->table_q('shop_attributes') . ' a ON a.' . $conn->quoteId('id') . ' = av.' . $conn->quoteId('attribute_id') . ' '
                    . 'WHERE av.' . $conn->quoteId('product_id') . ' = ? '
                    . 'ORDER BY a.' . $conn->quoteId('sort_order') . ' ASC, a.' . $conn->quoteId('title') . ' ASC';
                $rows = $conn->run($sql, [(int) $product['id']])->fetchAll();
                foreach ($rows as $r) {
                    if (\count($specs) >= $maxSpecs) break;
                    $type = (string) ($r['type'] ?? 'text');
                    $raw  = (string) ($r['value'] ?? '');
                    if ($type === 'multiselect') {
                        $arr = json_decode($raw, true);
                        $val = \is_array($arr) ? implode(', ', $arr) : $raw;
                    } elseif ($type === 'boolean') {
                        $val = \in_array($raw, ['1','true','yes','on'], true) ? 'Да' : 'Нет';
                    } else {
                        $val = $raw;
                    }
                    $val = trim($val);
                    if ($val === '') continue;
                    if (!empty($r['unit'])) $val .= ' ' . $r['unit'];
                    $specs[] = ['label' => (string) $r['title'], 'value' => $val];
                }
            } catch (\Throwable) {}
        }

        // 1) Custom fields
        foreach ($cfValues as $slug => $raw) {
            if (\count($specs) >= $maxSpecs) break;
            if (!isset($fieldByLabel[$slug])) continue;
            $type = $fieldByLabel[$slug]['type'];
            if ($type === 'image') {
                // Одна картинка — value это URL; галерея — JSON-массив URL.
                $rawStr = trim((string) $raw);
                if ($rawStr === '') continue;
                $urls = ($rawStr !== '' && $rawStr[0] === '[')
                    ? (json_decode($rawStr, true) ?: [])
                    : [$rawStr];
                $images = [];
                foreach ($urls as $u) {
                    $u = trim((string) $u);
                    if ($u === '') continue;
                    $images[] = [
                        'thumb' => \Celena\Core\Support\ImageVariant::url($u, 'thumb'),
                        'full'  => $u,
                    ];
                }
                if ($images === []) continue;
                $specs[] = [
                    'label'  => $fieldByLabel[$slug]['label'],
                    'value'  => '',
                    'images' => $images,
                ];
                continue;
            }
            if ($type === 'multiselect') {
                $arr = json_decode((string) $raw, true);
                $val = \is_array($arr) ? implode(', ', $arr) : (string) $raw;
            } elseif ($type === 'checkbox') {
                $val = $raw === '1' ? 'Так' : 'Ні';
            } else {
                $val = (string) $raw;
            }
            $val = trim($val);
            if ($val === '') continue;
            $specs[] = ['label' => $fieldByLabel[$slug]['label'], 'value' => $val];
        }

        // 2) options (опции вариаций)
        if (\count($specs) < $maxSpecs && !empty($product['options'])) {
            $opts = \is_string($product['options'])
                ? json_decode($product['options'], true)
                : $product['options'];
            if (\is_array($opts)) {
                foreach ($opts as $opt) {
                    if (\count($specs) >= $maxSpecs) break;
                    if (!\is_array($opt)) continue;
                    $name = trim((string) ($opt['name'] ?? ''));
                    $vals = $opt['values'] ?? null;
                    $valsStr = \is_array($vals) ? implode(', ', array_map('strval', $vals)) : (string) $vals;
                    $valsStr = trim($valsStr);
                    if ($name === '' || $valsStr === '') continue;
                    $specs[] = ['label' => $name, 'value' => $valsStr];
                }
            }
        }

        // 3) attributes (плоский JSON)
        if (\count($specs) < $maxSpecs && !empty($product['attributes'])) {
            $attrs = \is_string($product['attributes'])
                ? json_decode($product['attributes'], true)
                : $product['attributes'];
            if (\is_array($attrs)) {
                foreach ($attrs as $key => $val) {
                    if (\count($specs) >= $maxSpecs) break;
                    $key = trim((string) $key);
                    $valStr = \is_array($val)
                        ? implode(', ', array_map('strval', $val))
                        : (string) $val;
                    $valStr = trim($valStr);
                    if ($key === '' || $valStr === '') continue;
                    $specs[] = ['label' => $key, 'value' => $valStr];
                }
            }
        }

        return $specs;
    }
}
