<?php
declare(strict_types=1);

namespace Celena\Module\Plugins;

use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Kernel;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Csrf;
use Celena\Core\Security\Permission;
use Celena\Core\Template\Engine;
use Celena\Core\Template\TagRegistry;
use Celena\Core\Template\ThemeManager;
use Celena\Module\AdminBase\AdminController;
use Celena\Module\Settings\Options;

/**
 * Редактор файлов темы. Открывается по /admin/templates/{theme}/edit.
 *   GET  ?file=home.tpl — показывает редактор для файла
 *   POST /save — сохраняет файл (с проверкой пути и расширения)
 *   POST /api/preview — возвращает отрендеренный HTML для preview-фрейма
 */
final class TemplateEditorController extends AdminController
{
    private const ALLOWED_EXT = ['tpl', 'json', 'css', 'js', 'md'];

    public function __construct(
        Engine $engine,
        Auth $auth,
        Options $options,
        private readonly ThemeManager $themes,
        private readonly TagRegistry $tags,
    ) {
        parent::__construct($engine, $auth, $options);
    }

    public function edit(Request $request, array $params): Response
    {
        if (!Permission::can($this->auth->user(), 'templates.edit')) {
            return $this->redirect('/admin/templates', 'Доступ запрещён.', 'error');
        }
        $theme = (string) ($params['theme'] ?? '');
        if (!$this->themes->exists($theme)) {
            return $this->redirect('/admin/templates', 'Тема не найдена.', 'error');
        }
        $base = Kernel::rootPath() . '/templates/' . $theme;
        $files = $this->listFiles($base);
        $selected = (string) $request->query('file', $files[0] ?? '');
        $selected = $this->sanitizePath($selected);
        $abs = $base . '/' . $selected;
        $content = '';
        if ($selected !== '' && is_file($abs)) {
            $content = (string) file_get_contents($abs);
        }
        return $this->view('admin/templates-ui/editor', [
            'theme' => $theme,
            'files' => $files,
            'selected' => $selected,
            'content' => $content,
            'inline_tags' => $this->tags->inlineNames(),
            'block_tags' => $this->tags->blockNames(),
        ], 'templates', 'Редактор: ' . $theme);
    }

    public function save(Request $request, array $params): Response
    {
        if (!Permission::can($this->auth->user(), 'templates.edit')) {
            return $this->redirect('/admin/templates', 'Доступ запрещён.', 'error');
        }
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return $this->redirect('/admin/templates', 'CSRF.', 'error');
        }
        $theme = (string) ($params['theme'] ?? '');
        if (!$this->themes->exists($theme)) {
            return $this->redirect('/admin/templates', 'Тема не найдена.', 'error');
        }
        $file = $this->sanitizePath((string) $request->input('file', ''));
        if ($file === '' || !$this->extAllowed($file)) {
            return $this->redirect('/admin/templates/' . $theme . '/edit', 'Недопустимый файл.', 'error');
        }
        $abs = Kernel::rootPath() . '/templates/' . $theme . '/' . $file;
        if (!is_file($abs)) {
            return $this->redirect('/admin/templates/' . $theme . '/edit', 'Файл не существует.', 'error');
        }
        $content = (string) $request->input('content', '');
        file_put_contents($abs, $content, LOCK_EX);
        // Сбросить скомпилированный кеш этого шаблона
        $this->engine->flush();
        return $this->redirect('/admin/templates/' . $theme . '/edit?file=' . rawurlencode($file), 'Сохранено.');
    }

    public function preview(Request $request, array $params): Response
    {
        if (!Permission::can($this->auth->user(), 'templates.edit')) {
            return Response::json(['error' => 'forbidden'], 403);
        }
        $token = (string) ($request->header('x-csrf-token') ?? $request->input('_csrf'));
        if (!Csrf::validate($token)) {
            return Response::json(['error' => 'csrf'], 403);
        }
        $theme = (string) ($params['theme'] ?? '');
        if (!$this->themes->exists($theme)) {
            return Response::json(['error' => 'theme_not_found'], 404);
        }
        $file = $this->sanitizePath((string) $request->input('file', ''));
        if ($file === '' || !str_ends_with($file, '.tpl')) {
            return Response::json(['error' => 'not_tpl'], 400);
        }
        try {
            $this->engine->setTheme($theme);
            $source = (string) $request->input('content', '');
            $html = $this->engine->renderString($source, $this->sampleVars());
            return Response::html($html);
        } catch (\Throwable $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }

    /** @return string[] список файлов темы относительно корня темы */
    private function listFiles(string $base): array
    {
        $out = [];
        $it = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($base, \RecursiveDirectoryIterator::SKIP_DOTS)
        );
        foreach ($it as $f) {
            if (!$f->isFile()) continue;
            $rel = str_replace('\\', '/', substr($f->getPathname(), strlen($base) + 1));
            if ($this->extAllowed($rel)) {
                $out[] = $rel;
            }
        }
        sort($out);
        return $out;
    }

    private function sanitizePath(string $p): string
    {
        $p = str_replace(['\\', "\0"], ['/', ''], $p);
        $p = ltrim(preg_replace('#/+#', '/', $p) ?? '', '/');
        // запрещаем .. и абсолютные пути
        if (str_contains($p, '..')) {
            return '';
        }
        return $p;
    }

    private function extAllowed(string $rel): bool
    {
        $ext = strtolower(pathinfo($rel, PATHINFO_EXTENSION));
        return in_array($ext, self::ALLOWED_EXT, true);
    }

    private function sampleVars(): array
    {
        return [
            'site' => ['name' => 'Preview', 'url' => ''],
            'page' => ['title' => 'Превью', 'seo_title' => 'Превью', 'seo_description' => '', 'og_image' => ''],
            'user' => ['name' => 'User', 'email' => '', 'role' => 'admin'],
            'news' => [
                ['title' => 'Пример новости 1', 'url' => '#', 'date' => '2026-04-23', 'short' => 'Краткое описание.', 'cover' => '', 'views' => 42],
                ['title' => 'Пример новости 2', 'url' => '#', 'date' => '2026-04-22', 'short' => '', 'cover' => '', 'views' => 17],
            ],
            'content' => '<p>Пример контента страницы.</p>',
            'pagination' => ['current' => 1, 'total_pages' => 3, 'has_prev' => false, 'has_next' => true, 'prev_url' => '', 'next_url' => '?page=2'],
            'comments' => [],
            'comments_open' => '1',
            'comment_status' => '',
            'comment_error' => '',
        ];
    }
}
