<?php
declare(strict_types=1);

namespace Celena\Module\CustomFields;

use Celena\Core\Database\Connection;

/**
 * Сервис для чтения описаний доп. полей и их значений для конкретной сущности.
 * Используется формами news/pages и рендером на фронте.
 */
final class FieldRepository
{
    public function __construct(private readonly Connection $conn)
    {
    }

    /** @return array<int, array<string, mixed>> */
    public function fieldsFor(string $entityType): array
    {
        return $this->conn->builder('celena_custom_fields')
            ->where('entity_type', '=', $entityType)
            ->orderBy('sort_order', 'asc')
            ->get();
    }

    /** @return array<string, string> slug => value */
    public function valuesFor(string $entityType, int $entityId): array
    {
        if ($entityId === 0) {
            return [];
        }
        $rows = $this->conn->run(
            'SELECT f.slug AS slug, v.value AS value FROM '
            . $this->conn->table_q('celena_custom_fields') . ' f '
            . 'JOIN ' . $this->conn->table_q('celena_custom_field_values') . ' v ON v.field_id = f.id '
            . 'WHERE v.entity_type = ? AND v.entity_id = ?',
            [$entityType, $entityId]
        )->fetchAll();
        $out = [];
        foreach ($rows as $r) {
            $out[(string) $r['slug']] = (string) ($r['value'] ?? '');
        }
        return $out;
    }

    /**
     * Загрузить значения полей для нескольких сущностей одним запросом.
     * Используется блок-тегами ([news], [products]), чтобы при выводе списка не делать
     * по запросу на каждую запись.
     *
     * @param int[] $entityIds
     * @return array<int, array<string, string>> entity_id => [slug => value]
     */
    public function valuesForMany(string $entityType, array $entityIds): array
    {
        $entityIds = array_values(array_unique(array_map('intval', $entityIds)));
        $entityIds = array_filter($entityIds, static fn (int $id): bool => $id > 0);
        if ($entityIds === []) {
            return [];
        }
        $placeholders = implode(',', array_fill(0, count($entityIds), '?'));
        $sql = 'SELECT f.slug AS slug, v.entity_id AS entity_id, v.value AS value FROM '
            . $this->conn->table_q('celena_custom_fields') . ' f '
            . 'JOIN ' . $this->conn->table_q('celena_custom_field_values') . ' v ON v.field_id = f.id '
            . 'WHERE v.entity_type = ? AND v.entity_id IN (' . $placeholders . ')';
        $rows = $this->conn->run($sql, array_merge([$entityType], $entityIds))->fetchAll();
        $out = [];
        foreach ($entityIds as $id) {
            $out[$id] = [];
        }
        foreach ($rows as $r) {
            $eid = (int) ($r['entity_id'] ?? 0);
            $out[$eid][(string) $r['slug']] = (string) ($r['value'] ?? '');
        }
        return $out;
    }

    /** Сохранить значения полей для сущности. $values — slug => value. */
    public function saveValues(string $entityType, int $entityId, array $values): void
    {
        $fields = $this->conn->builder('celena_custom_fields')
            ->where('entity_type', '=', $entityType)
            ->get();
        // Удаляем старые значения и пишем новые (upsert было бы лучше, но keep it simple).
        $this->conn->builder('celena_custom_field_values')
            ->where('entity_type', '=', $entityType)
            ->where('entity_id', '=', $entityId)
            ->delete();
        foreach ($fields as $field) {
            $slug = (string) $field['slug'];
            if (!array_key_exists($slug, $values)) {
                continue;
            }
            $value = $values[$slug];
            if (is_array($value)) {
                $value = json_encode(array_values($value), JSON_UNESCAPED_UNICODE);
            }
            $value = (string) $value;
            if ($value === '') {
                continue;
            }
            $this->conn->builder('celena_custom_field_values')->insert([
                'field_id' => (int) $field['id'],
                'entity_type' => $entityType,
                'entity_id' => $entityId,
                'value' => $value,
            ]);
        }
    }

    /** Декодировать multiselect-значение (JSON-массив). */
    public static function decodeValue(array $field, string $raw): mixed
    {
        if ($field['type'] === 'multiselect') {
            $decoded = json_decode($raw, true);
            return is_array($decoded) ? $decoded : [];
        }
        if ($field['type'] === 'checkbox') {
            return $raw === '1';
        }
        return $raw;
    }
}
