<?php

namespace App\Livewire;

use App\Enums\UserRole;
use App\Models\Episode;
use App\Models\ModLog;
use App\Models\User;
use App\Notifications\CommentNotification;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Livewire\Component;
use Maize\Markable\Models\Like;

class Comment extends Component
{
    use AuthorizesRequests;

    public $comment;

    public $isReplying = false;

    public $likeCount = 0;

    public $liked = false;

    public $replyState = [
        'body' => '',
    ];

    public $isEditing = false;

    public $editState = [
        'body' => '',
    ];

    protected $listeners = [
        'refresh' => '$refresh',
    ];

    protected $validationAttributes = [
        'replyState.body' => 'reply',
    ];

    public function updatedIsEditing(bool $isEditing)
    {
        if (! $isEditing) {
            return;
        }

        $this->editState = [
            'body' => $this->comment->body,
        ];
    }

    public function editComment()
    {
        $this->authorize('update', $this->comment);

        $this->comment->update($this->editState);

        $this->isEditing = false;
    }

    public function deleteComment()
    {
        $this->authorize('destroy', $this->comment);

        $user = Auth::user();
        
        if ($user->hasRole(UserRole::ADMINISTRATOR) ||  $user->hasRole(UserRole::MODERATOR)) {
            // Log to ModLog
            ModLog::create([
                'moderator' => $user->name,
                'data' => "Deleted comment {$this->comment->id} written by {$this->comment->user->id} with contents: {$this->comment->body}",
            ]);

            $this->comment->deleted_by_moderator_id = $user->id;
            $this->comment->save();
            $this->dispatch('refresh');
            return;
        }

        $this->comment->delete();

        $this->dispatch('refresh');
    }

    public function restoreComment()
    {
        $this->authorize('restore', $this->comment);

        $user = Auth::user();

        if ($user->hasRole(UserRole::ADMINISTRATOR) ||  $user->hasRole(UserRole::MODERATOR)) {
            // Log to ModLog
            ModLog::create([
                'moderator' => $user->name,
                'data' => "Restored comment {$this->comment->id} written by {$this->comment->user->id} with contents: {$this->comment->body}",
            ]);

            $this->comment->deleted_by_moderator_id = null;
            $this->comment->save();
            $this->dispatch('refresh');
        }
    }

    public function postReply()
    {
        if (! ($this->comment->depth() < 2)) {
            $this->addError('replyState.body', 'Too many sub comments.');

            return;
        }

        $user = auth()->user();
        $rateLimitKey = "send-comment:{$user->id}";
        $rateLimitMinutes = 60 * 5; // 5 minutes

        if (RateLimiter::tooManyAttempts($rateLimitKey, 1)) {
            $seconds = RateLimiter::availableIn($rateLimitKey);

            $this->addError('replyState.body', "Too many comments. Try again in {$seconds} seconds.");

            return;
        }

        RateLimiter::hit($rateLimitKey, $rateLimitMinutes);

        $this->validate([
            'replyState.body' => 'required',
        ]);

        $reply = $this->comment->children()->make($this->replyState);
        $reply->user()->associate($user);
        $reply->commentable()->associate($this->comment->commentable);

        $reply->save();

        // Notify if Episode and if not the same user
        if ($reply->commentable_type == Episode::class && $user->id !== $reply->parent->user->id) {
            $episode = Episode::where('id', $reply->commentable_id)
                ->firstOrFail();

            $url = route('hentai.index', ['title' => $episode->slug]);

            $reply->parent->user->notify(
                new CommentNotification(
                    "{$user->name} replied to your comment.",
                    Str::limit($reply->body, 50),
                    "{$url}#comment-{$reply->id}"
                )
            );
        }

        $this->replyState = [
            'body' => '',
        ];

        $this->isReplying = false;

        $this->dispatch('refresh')->self();
    }

    public function like()
    {
        if (! Auth::check()) {
            return;
        }

        Like::toggle($this->comment, User::where('id', Auth::user()->id)->firstOrFail());

        Cache::forget('commentLikes'.$this->comment->id);

        if ($this->liked) {
            $this->liked = false;
            $this->likeCount--;

            return;
        }

        $this->liked = true;
        $this->likeCount++;
    }

    public function mount()
    {
        if (Auth::check()) {
            $this->likeCount = $this->comment->likeCount();
            $this->liked = Like::has($this->comment, User::where('id', Auth::user()->id)->firstOrFail());
        }
    }

    public function render()
    {
        return view('livewire.comment');
    }
}
