<?php

declare(strict_types=1);

namespace App\Services\News;

use App\Services\ContentSanitizer;
use App\Models\NewsArticleComment;
use App\Models\User;
use Illuminate\Validation\ValidationException;
use cPad\Plugins\News\Models\NewsArticle;

final class NewsArticleCommentService
{
    public function __construct(private readonly NewsService $news)
    {
    }

    public function create(NewsArticle $article, User $actor, string $body, ?NewsArticleComment $parent = null): NewsArticleComment
    {
        if (! $article->commentsAreEnabled()) {
            throw ValidationException::withMessages([
                'body' => 'Comments are disabled for this article.',
            ]);
        }

        $trimmedBody = trim($body);
        $errors = ContentSanitizer::validate($trimmedBody);

        if ($errors !== []) {
            throw ValidationException::withMessages([
                'body' => $errors,
            ]);
        }

        $comment = NewsArticleComment::query()->create([
            'article_id' => (int) $article->id,
            'user_id' => (int) $actor->id,
            'parent_id' => $parent?->id,
            'author_name' => trim((string) ($actor->name ?: $actor->username)),
            'body' => $trimmedBody,
            'rendered_body' => ContentSanitizer::sanitizeRenderedHtml(
                ContentSanitizer::render($trimmedBody),
                $this->actorCanPublishLinks($actor)
            ),
            'status' => 'visible',
        ]);

        $this->news->invalidatePublicCache();

        return $comment->fresh(['user.profile', 'replies.user.profile']);
    }

    public function delete(NewsArticleComment $comment, User $actor): void
    {
        $article = $comment->article()->with('author')->first();

        if (! $article || ! $this->canDelete($comment, $article, $actor)) {
            throw ValidationException::withMessages([
                'comment' => 'You are not allowed to remove this comment.',
            ]);
        }

        if ($comment->trashed()) {
            return;
        }

        $comment->delete();

        $this->news->invalidatePublicCache();
    }

    private function canDelete(NewsArticleComment $comment, NewsArticle $article, User $actor): bool
    {
        return (int) $comment->user_id === (int) $actor->id
            || (int) $article->author_id === (int) $actor->id
            || $actor->isAdmin()
            || $actor->isModerator();
    }

    private function actorCanPublishLinks(User $actor): bool
    {
        $level = (int) ($actor->level ?? 1);
        $rank = strtolower((string) ($actor->rank ?? 'Newbie'));

        return $level > 1 && $rank !== 'newbie';
    }
}