<?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\AttributeFacets;
use Celena\Plugin\Shop\Support\AttributeOptions;
use Celena\Plugin\Shop\Support\SeoFilterMatcher;

/**
 * SEO-фильтры — конструктор правил подмены H1 и мета-тегов на витрине
 * для конкретной комбинации категории и значений атрибутов.
 */
final class SeoFiltersAdminController extends AdminController
{
    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_seo_filters')->count();
        $p = new Pagination($page, 25, $total);
        $rows = $this->conn->builder('shop_seo_filters')
            ->orderBy('sort_order', 'desc')->orderBy('id', 'desc')
            ->limit($p->perPage)->offset($p->offset)->get();

        // Подтянем имена категорий для отображения.
        $catTitles = [];
        foreach ($rows as $r) {
            if ($r['category_id'] !== null) {
                $catTitles[(int) $r['category_id']] = '';
            }
        }
        if ($catTitles !== []) {
            $cats = $this->conn->builder('celena_categories')
                ->whereIn('id', array_keys($catTitles))->get();
            foreach ($cats as $c) {
                $catTitles[(int) $c['id']] = (string) $c['title'];
            }
        }
        foreach ($rows as &$r) {
            $r['category_title'] = $r['category_id'] !== null ? ($catTitles[(int) $r['category_id']] ?? '—') : 'Любая';
            $conds = is_array($r['conditions'] ?? null) ? $r['conditions'] : json_decode((string) ($r['conditions'] ?? ''), true);
            $r['conditions_short'] = $this->shortConditions(is_array($conds) ? $conds : []);
        }
        unset($r);

        return $this->view('plugins/shop/admin/seo_filters_index', [
            'rules' => $rows,
            'pagination' => $p->toArray('/admin/shop/seo-filters?page=:page'),
            'total' => $total,
        ], 'shop-seo-filters', 'SEO-фильтры магазина');
    }

    public function create(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');
        return $this->renderForm($this->emptyRow(), '/admin/shop/seo-filters/create', 'Новое правило SEO-фильтра');
    }

    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/seo-filters/create', 'CSRF-ошибка', 'error');
        }
        $data = $this->extract($request);
        if ($data['title'] === '') {
            return $this->redirect('/admin/shop/seo-filters/create', 'Укажите название правила.', 'error');
        }
        $now = date('Y-m-d H:i:s');
        $data['created_at'] = $now;
        $data['updated_at'] = $now;
        $this->conn->builder('shop_seo_filters')->insert($data);
        return $this->redirect('/admin/shop/seo-filters', 'Правило добавлено.');
    }

    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_seo_filters')->where('id', '=', $id)->first();
        if ($row === null) {
            return $this->redirect('/admin/shop/seo-filters', 'Правило не найдено.', 'error');
        }
        return $this->renderForm($row, '/admin/shop/seo-filters/' . $id . '/update', 'Правило: ' . $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/seo-filters', 'CSRF-ошибка', 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        if ($this->conn->builder('shop_seo_filters')->where('id', '=', $id)->first() === null) {
            return $this->redirect('/admin/shop/seo-filters', 'Правило не найдено.', 'error');
        }
        $data = $this->extract($request, $id);
        $data['updated_at'] = date('Y-m-d H:i:s');
        $this->conn->builder('shop_seo_filters')->where('id', '=', $id)->update($data);
        return $this->redirect('/admin/shop/seo-filters', 'Правило сохранено.');
    }

    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/seo-filters', 'CSRF-ошибка', 'error');
        }
        $id = Filter::int($params['id'] ?? 0);
        $this->conn->builder('shop_seo_filters')->where('id', '=', $id)->delete();
        return $this->redirect('/admin/shop/seo-filters', 'Правило удалено.');
    }

    private function renderForm(array $row, string $action, string $title): Response
    {
        // Категории магазина для селекта (с обязательным «любая» в начале).
        $categories = $this->conn->builder('celena_categories')
            ->where('entity_type', '=', 'shop_product')
            ->orderBy('sort_order', 'asc')->orderBy('title', 'asc')
            ->get();

        // Доступные для условий атрибуты + их значения.
        $attrRows = AttributeFacets::loadFilterable($this->conn);
        $attrs = [];
        foreach ($attrRows as $a) {
            $opts = AttributeOptions::decode($a['options'] ?? null);
            $values = array_map(static fn ($o): string => $o['label'], $opts);
            $attrs[] = [
                'slug'   => (string) $a['slug'],
                'title'  => (string) $a['title'],
                'type'   => (string) $a['type'],
                'values' => $values,
            ];
        }

        // Текущие условия в JSON для JS-рендера.
        $rawConds = $row['conditions'] ?? null;
        $conds = is_array($rawConds) ? $rawConds : json_decode((string) $rawConds, true);
        if (!is_array($conds)) $conds = [];

        return $this->view('plugins/shop/admin/seo_filters_form', [
            'row'            => $row,
            'categories'     => $categories,
            'attributes'     => $attrs,
            'attributes_json'=> json_encode($attrs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            'conditions_json'=> json_encode($conds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            'form_action'    => $action,
        ], 'shop-seo-filters', $title);
    }

    /**
     * @return array<string, mixed>
     */
    private function emptyRow(): array
    {
        return [
            'id' => 0, 'title' => '', 'category_id' => null, 'conditions' => '[]',
            'url_slug' => '',
            'h1' => '', 'meta_title' => '', 'meta_description' => '',
            'meta_keywords' => '', 'intro_text' => '',
            'is_active' => true, 'sort_order' => 0,
        ];
    }

    /**
     * @param int $excludeId При update — id текущего правила, чтобы исключить его при проверке уникальности slug.
     * @return array<string, mixed>
     */
    private function extract(Request $request, int $excludeId = 0): array
    {
        // conditions передаётся одним hidden'ом conditions_json (JSON-строка).
        $rawConds = (string) $request->input('conditions_json', '[]');
        $decoded = json_decode($rawConds, true);
        $clean = [];
        if (is_array($decoded)) {
            foreach ($decoded as $cond) {
                if (!is_array($cond)) continue;
                $slug = trim((string) ($cond['attr_slug'] ?? ''));
                $vals = $cond['values'] ?? [];
                if ($slug === '' || !is_array($vals) || $vals === []) continue;
                $vals = array_values(array_unique(array_filter(array_map(
                    static fn ($v): string => trim((string) $v),
                    $vals
                ), static fn (string $v): bool => $v !== '')));
                if ($vals === []) continue;
                $clean[] = ['attr_slug' => $slug, 'values' => $vals];
            }
        }
        $catId = $request->input('category_id', '');
        $catId = ($catId === '' || $catId === null) ? null : Filter::int($catId, 0);
        if ($catId === 0) $catId = null;

        // ── url_slug: если поле пустое — авто-генерация из условий, иначе чистим
        // как обычный URL-slug. ЧПУ возможно только для правила с категорией.
        $urlSlug = Filter::urlSlug($request->input('url_slug', ''), 120);
        if ($urlSlug === '' && $catId !== null && $clean !== []) {
            $urlSlug = SeoFilterMatcher::suggestUrlSlug($clean);
        }
        if ($catId === null) {
            // Без категории ЧПУ не делаем — иначе нет роутинга.
            $urlSlug = '';
        }
        if ($urlSlug !== '') {
            $urlSlug = $this->ensureUniqueUrlSlug($urlSlug, $excludeId);
        }

        return [
            'title'            => Filter::string($request->input('title'), 200),
            'category_id'      => $catId,
            'conditions'       => json_encode($clean, JSON_UNESCAPED_UNICODE),
            'url_slug'         => $urlSlug !== '' ? $urlSlug : null,
            'h1'               => trim((string) $request->input('h1', '')),
            'meta_title'       => trim((string) $request->input('meta_title', '')),
            'meta_description' => trim((string) $request->input('meta_description', '')),
            'meta_keywords'    => trim((string) $request->input('meta_keywords', '')),
            'intro_text'       => (string) $request->input('intro_text', ''),
            'is_active'        => Filter::bool($request->input('is_active')),
            'sort_order'       => Filter::int($request->input('sort_order'), 0),
        ];
    }

    /**
     * Если url_slug занят другим правилом — добавляет суффикс -2/-3/...
     */
    private function ensureUniqueUrlSlug(string $slug, int $excludeId): string
    {
        $base = $slug;
        $i = 1;
        while (true) {
            $candidate = $i === 1 ? $base : ($base . '-' . $i);
            $q = $this->conn->builder('shop_seo_filters')->where('url_slug', '=', $candidate);
            if ($excludeId > 0) $q->where('id', '!=', $excludeId);
            $row = $q->first();
            if ($row === null) return $candidate;
            $i++;
            if ($i > 50) return $candidate . '-' . substr(sha1((string) microtime(true)), 0, 6);
        }
    }

    private function shortConditions(array $conds): string
    {
        if ($conds === []) return '—';
        $parts = [];
        foreach ($conds as $c) {
            $slug = (string) ($c['attr_slug'] ?? '');
            $vals = is_array($c['values'] ?? null) ? $c['values'] : [];
            if ($slug === '' || $vals === []) continue;
            $parts[] = $slug . ': ' . implode(', ', array_map('strval', $vals));
        }
        return $parts === [] ? '—' : implode(' · ', $parts);
    }
}
