<?php
declare(strict_types=1);

namespace Celena\Module\Comments;

use Celena\Core\Database\Connection;
use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Plugin\Hook;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Csrf;
use Celena\Core\Security\Filter;
use Celena\Core\Security\RateLimiter;
use Celena\Module\Settings\Options;

/**
 * POST /news/{slug}/comments — добавить комментарий к новости.
 * Antispam через honeypot ('website') и rate-limit по IP.
 */
final class PublicCommentsController
{
    public function __construct(
        private readonly Connection $conn,
        private readonly Options $options,
        private readonly Auth $auth,
        private readonly RateLimiter $limiter,
    ) {
    }

    public function submit(Request $request, array $params): Response
    {
        if ((string) $this->options->get('comments_open', '1') !== '1') {
            return Response::redirect('/news/' . Filter::urlSlug($params['slug'] ?? ''));
        }
        if (!Csrf::validate((string) $request->input('_csrf'))) {
            return Response::redirect('/news/' . Filter::urlSlug($params['slug'] ?? '') . '?err=csrf');
        }
        // Honeypot: настоящие пользователи поле оставляют пустым.
        if ((string) $request->input('website', '') !== '') {
            return Response::redirect('/news/' . Filter::urlSlug($params['slug'] ?? '') . '?err=spam');
        }
        $slug = Filter::urlSlug($params['slug'] ?? '');
        $news = $this->conn->builder('celena_news')->where('slug', '=', $slug)->first();
        if ($news === null || $news['status'] !== 'published') {
            return Response::notFound();
        }

        $key = 'comment:' . $request->ip();
        if (!$this->limiter->attempt($key, 5, 3600)) {
            return Response::redirect('/news/' . $slug . '?err=rate');
        }

        $user = $this->auth->user();
        $name = $user !== null ? (string) $user['name'] : Filter::string($request->input('author_name'), 100);
        $email = $user !== null ? (string) $user['email'] : (Filter::email($request->input('author_email')) ?? '');
        $body = Filter::string($request->input('body'), 5000);

        if ($name === '' || $body === '' || mb_strlen($body) < 3) {
            return Response::redirect('/news/' . $slug . '?err=invalid');
        }
        // Простой фильтр: запретить ссылки > 2
        if (substr_count(strtolower($body), 'http') > 2) {
            return Response::redirect('/news/' . $slug . '?err=spam');
        }

        $moderate = (string) $this->options->get('comments_moderate', '1') === '1';
        $status = $moderate ? 'pending' : 'approved';
        $now = date('Y-m-d H:i:s');

        $id = $this->conn->builder('celena_comments')->insert([
            'entity_type' => 'news',
            'entity_id' => (int) $news['id'],
            'parent_id' => null,
            'user_id' => $user !== null ? (int) $user['id'] : null,
            'author_name' => $name,
            'author_email' => $email,
            'body' => $body,
            'status' => $status,
            'ip' => $request->ip(),
            'created_at' => $now,
            'updated_at' => $now,
        ]);

        if ($status === 'approved') {
            $this->conn->builder('celena_news')
                ->where('id', '=', $news['id'])
                ->update(['comments_count' => (int) $news['comments_count'] + 1]);
        }
        Hook::action('comment.created', ['id' => (int) $id, 'news_id' => (int) $news['id'], 'status' => $status]);

        return Response::redirect('/news/' . $slug . '?c=' . ($moderate ? 'pending' : 'ok') . '#comments');
    }
}
