<?php
declare(strict_types=1);

namespace Celena\Plugin\Shop\Admin;

use Celena\Core\Database\Connection;
use Celena\Core\Http\Pagination;
use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Csrf;
use Celena\Core\Security\Filter;
use Celena\Core\Template\Engine;
use Celena\Module\AdminBase\AdminController;
use Celena\Module\Settings\Options;
use Celena\Plugin\Shop\Support\AttributeOptions;

/**
 * Атрибуты товаров — типизированные характеристики (бренд, цвет, объём…),
 * с участием в фасетных фильтрах витрины. В отличие от custom fields,
 * атрибуты несут ещё `unit`, `is_filterable`, типы color/multiselect.
 */
final class AttributesAdminController extends AdminController
{
    private function tr(): \Celena\Core\I18n\Translator
    {
        return \Celena\Core\Kernel::container()->make(\Celena\Core\I18n\Translator::class);
    }

    public function __construct(
        Engine $engine,
        Auth $auth,
        Options $options,
        private readonly Connection $conn,
    ) {
        parent::__construct($engine, $auth, $options);
    }

    public function index(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        $page = Filter::int($request->query('page', 1), 1);
        $total = $this->conn->builder('shop_attributes')->count();
        $p = new Pagination($page, 25, $total);
        $rows = $this->conn->builder('shop_attributes')
            ->orderBy('sort_order', 'asc')->orderBy('title', 'asc')
            ->limit($p->perPage)->offset($p->offset)->get();

        return $this->view('plugins/shop/admin/attributes_index', [
            'attributes' => $rows,
            'pagination' => $p->toArray('/admin/shop/attributes?page=:page'),
            'total' => $total,
        ], 'shop-attributes', $this->tr()->translate('shop.attributes_list.title'));
    }

    public function create(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        return $this->view('plugins/shop/admin/attributes_form', [
            'row' => $this->emptyRow(),
            'types' => $this->typeCards(),
            'values_json' => '[]',
            'form_action' => '/admin/shop/attributes/create',
        ], 'shop-attributes', $this->tr()->translate('shop.attributes_list.new'));
    }

    /**
     * Распарсить параллельные массивы opt_values[]/opt_colors[]/opt_images[]
     * из формы в нормализованный список вариантов и сразу сериализовать.
     * Возвращает JSON-строку либо null, если вариантов нет / тип не поддерживает options.
     */
    private function buildOptions(Request $request, string $type): ?string
    {
        if (!in_array($type, ['select', 'multiselect', 'color'], true)) {
            return null;
        }
        $labels = $request->input('opt_values', []);
        $colors = $request->input('opt_colors', []);
        $images = $request->input('opt_images', []);
        if (!is_array($labels)) return null;

        $rows = [];
        foreach ($labels as $i => $label) {
            $rows[] = [
                'label' => (string) $label,
                'color' => is_array($colors) ? (string) ($colors[$i] ?? '') : '',
                'image' => is_array($images) ? (string) ($images[$i] ?? '') : '',
            ];
        }
        return AttributeOptions::encode($rows, $type);
    }

    public function store(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/attributes/create', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $data = $this->extract($request);
        if ($data['title'] === '') {
            return $this->redirect('/admin/shop/attributes/create', $this->tr()->translate('shop.flash.title_required'), 'error');
        }
        if ($data['slug'] === '') $data['slug'] = Filter::slug($data['title']);
        if ($this->slugExists($data['slug'])) {
            return $this->redirect('/admin/shop/attributes/create', $this->tr()->translate('shop.flash.slug_taken_already'), 'error');
        }
        $now = date('Y-m-d H:i:s');
        $data['created_at'] = $now;
        $data['updated_at'] = $now;
        $this->conn->builder('shop_attributes')->insert($data);
        return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.attribute_added'));
    }

    public function edit(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        $id = Filter::int($params['id'] ?? 0);
        $row = $this->conn->builder('shop_attributes')->where('id', '=', $id)->first();
        if ($row === null) return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.not_found'), 'error');
        // Нормализуем options к [{label,color,image},...] для JS-редактора —
        // совместимо со старым форматом (массив строк).
        $valuesJson = json_encode(AttributeOptions::decode($row['options'] ?? null), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return $this->view('plugins/shop/admin/attributes_form', [
            'row' => $row,
            'types' => $this->typeCards(),
            'values_json' => $valuesJson,
            'form_action' => '/admin/shop/attributes/' . $id . '/update',
        ], 'shop-attributes', 'Атрибут: ' . $row['title']);
    }

    public function update(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $existing = $this->conn->builder('shop_attributes')->where('id', '=', $id)->first();
        if ($existing === null) return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.not_found'), 'error');
        $data = $this->extract($request);
        if ($data['slug'] === '') $data['slug'] = Filter::slug($data['title']);
        if ($data['slug'] !== $existing['slug'] && $this->slugExists($data['slug'])) {
            return $this->redirect('/admin/shop/attributes/' . $id . '/edit', $this->tr()->translate('shop.flash.slug_taken'), 'error');
        }
        $data['updated_at'] = date('Y-m-d H:i:s');
        $this->conn->builder('shop_attributes')->where('id', '=', $id)->update($data);
        return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.saved'));
    }

    public function delete(Request $request, array $params): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.csrf'), 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $this->conn->builder('shop_attribute_values')->where('attribute_id', '=', $id)->delete();
        $this->conn->builder('shop_attributes')->where('id', '=', $id)->delete();
        return $this->redirect('/admin/shop/attributes', $this->tr()->translate('shop.flash.deleted'));
    }

    private function emptyRow(): array
    {
        return [
            'id' => 0, 'slug' => '', 'title' => '', 'type' => 'text', 'options' => '',
            'unit' => '', 'is_filterable' => true, 'is_required' => false, 'sort_order' => 0,
        ];
    }

    private function extract(Request $request): array
    {
        $type = (string) $request->input('type', 'text');
        if (!in_array($type, ['text', 'number', 'select', 'multiselect', 'boolean', 'color'], true)) {
            $type = 'text';
        }
        return [
            'title'         => Filter::string($request->input('title'), 200),
            'slug'          => Filter::urlSlug($request->input('slug', '')),
            'type'          => $type,
            'options'       => $this->buildOptions($request, $type),
            'unit'          => Filter::string($request->input('unit'), 20),
            'is_filterable' => Filter::bool($request->input('is_filterable')),
            'is_required'   => Filter::bool($request->input('is_required')),
            'sort_order'    => Filter::int($request->input('sort_order'), 0),
        ];
    }

    private function slugExists(string $slug): bool
    {
        return $this->conn->builder('shop_attributes')->where('slug', '=', $slug)->first() !== null;
    }

    /** @return array<int, array<string, string>> карточки типов для рендера. */
    private function typeCards(): array
    {
        $icon = new \Celena\Core\Template\Tags\IconTag();
        return [
            ['slug' => 'text',        'label' => 'Текст',
             'hint' => 'Свободный ввод. Подходит для произвольных значений (модель, артикул производителя).',
             'svg'  => $icon(['name' => 'edit', 'size' => 24])],
            ['slug' => 'number',      'label' => 'Число',
             'hint' => 'Числовое значение с единицей измерения (кг, см, Вт). Поддерживает дробные.',
             'svg'  => $icon(['name' => 'sliders', 'size' => 24])],
            ['slug' => 'select',      'label' => 'Один вариант',
             'hint' => 'Выпадающий список — у товара ровно одно значение из заданных вариантов.',
             'svg'  => $icon(['name' => 'list', 'size' => 24])],
            ['slug' => 'multiselect', 'label' => 'Несколько вариантов',
             'hint' => 'Чипы-чекбоксы — у товара может быть несколько значений сразу (например, теги).',
             'svg'  => $icon(['name' => 'tag', 'size' => 24])],
            ['slug' => 'boolean',     'label' => 'Да / Нет',
             'hint' => 'Простой переключатель. Удобно для «беспроводной», «водонепроницаемый», «новинка».',
             'svg'  => $icon(['name' => 'check', 'size' => 24])],
            ['slug' => 'color',       'label' => 'Цвет',
             'hint' => 'Подвид «один вариант» с прицелом на названия цветов. Совместим с фильтрами.',
             'svg'  => $icon(['name' => 'image', 'size' => 24])],
        ];
    }
}
