<?php

namespace Main\Controllers\Forum;

use Main\Core\Controller;
use Main\Core\Jobs\JobDispatcher;
use Main\Jobs\SendDiscordWebhook;
use Main\Services\AvatarService;
use Main\Services\SeoService;
use Main\Services\UserService;
use PDO;

class ThreadController extends Controller
{
		protected string $route_type = 'forum';
	
    public function show($id, $slug)
    {
        $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
				if (!$thread) abort_404();
	    
		    $author = db()->prepare("SELECT * FROM Accounts WHERE id = ?");
		    $author->execute(array($thread["accountID"]));
		    $author = $author->fetch();
				$thread["user"] = [
					'id' => $author['id'],
					'username' => $author['username'],
					'displayName' => $author['realname'],
					'avatar' => AvatarService::get($author['id'], $author['realname']),
				];
			   
		    if (!$author) abort_404();
	    
	      $thread["user"]["roles"] = UserService::getRoles($author["id"]);
		    $thread["user"]["primaryRole"] = $thread["user"]["roles"][0];
				
				$category = db()->prepare("SELECT * FROM ForumCategories WHERE id = ?");
				$category->execute(array($thread["categoryID"]));
				$category = $category->fetch();
				$thread["category"] = $category;
				
				if (!$category) abort_404();
	    
		    if (!forum()->user()->can($thread["categoryID"], "VIEW_FORUM")) abort_404();
	    
		    SeoService::set('forum.threads.show', [
			    'thread_title' => $thread["title"],
		    ]);
				
				// Content
	      $thread["content"] = markdown()->convertToHtml($thread["content"]);
				
				// Permissions
	      $visitorID = auth()->check() ? auth()->user()->id() : 0;
	      $thread["permissions"] = [
					'EDIT_THREAD' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM") || $thread['accountID'] == $visitorID,
		      'DELETE_THREAD' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM") || $thread['accountID'] == $visitorID,
		      'PIN_THREAD' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM"),
		      'LOCK_THREAD' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM") || $thread['accountID'] == $visitorID,
		      'CREATE_REPLIES' => forum()->user()->can($thread["categoryID"], "CREATE_REPLIES"),
		      'MODERATE_FORUM' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM")
	      ];
				
		    if (isset($_GET["page"])) {
			    if (!is_numeric($_GET["page"])) {
				    $_GET["page"] = 1;
			    }
			    $page = intval($_GET["page"]);
		    } else {
			    $page = 1;
		    }
		    
		    $replyLimit = 20;
		    $itemsCount = db()->prepare("SELECT count(id) from ForumReplies WHERE threadID = ?");
		    $itemsCount->execute(array($thread["id"]));
		    $itemsCount = $itemsCount->fetchColumn();
				
		    $pageCount = ceil($itemsCount / $replyLimit);
		    if ($page > $pageCount) {
			    $page = 1;
		    }
		    $visibleItemsCount = $page * $replyLimit - $replyLimit;
		    
		    $replies = db()->prepare("SELECT * FROM ForumReplies WHERE threadID = ? ORDER BY id ASC LIMIT $visibleItemsCount, $replyLimit");
		    $replies->execute(array($thread["id"]));
		    $replies = array_map(function($reply) use ($thread, $visitorID) {
					$author = db()->prepare("SELECT * FROM Accounts WHERE id = ?");
					$author->execute(array($reply["accountID"]));
					$author = $author->fetch();
					$reply["user"] = [
						'id' => $author['id'],
						'username' => $author['username'],
						'displayName' => $author['realname'],
						'avatar' => AvatarService::get($author['id'], $author['realname']),
					];
					$reply["user"]["roles"] = UserService::getRoles($author["id"]);
			    $reply["user"]["primaryRole"] = $reply["user"]["roles"][0];
					
			    $reply["message"] = markdown()->convertToHtml($reply["message"]);
			    $reply["permissions"] = [
				    'MANAGE_REPLY' => forum()->user()->can($thread["categoryID"], "MODERATE_FORUM") || $reply['accountID'] == $visitorID,
			    ];
					
			    return $reply;
		    }, $replies->fetchAll(PDO::FETCH_ASSOC));
		    
		    if (!cookies()->has('threadID')) {
			    $updateThread = db()->prepare("UPDATE ForumThreads SET views = views + 1 WHERE id = ?");
			    $updateThread->execute(array($thread["id"]));
			    setcookie("threadID", $thread["id"]);
		    }
				

        return $this->view('forum.threads.show', compact('thread', 'replies', 'page', 'pageCount'));
    }

    public function create()
    {
        $category = db()->prepare("SELECT * FROM ForumCategories WHERE id = ?");
        $category->execute(array(get("category")));
        $category = $category->fetch();
				
				if (!$category) abort_404();
				
				SeoService::set('forum.threads.create');
	    
		    if (!forum()->user()->can($category["id"], "CREATE_TOPICS")) abort_404();

        return $this->view('forum.threads.create', compact('category'));
    }

    public function store()
    {
        validate([
            "title" => "required",
            "message" => "required"
        ]);
		    
		    if (recaptcha()->isEnabled('post_thread') && !recaptcha()->verify()) {
			    return back()->flash('error', t__('Spam detected!'));
		    }
				
        $category = db()->prepare("SELECT * FROM ForumCategories WHERE id = ?");
        $category->execute(array(get("category")));
        $category = $category->fetch();
	    
		    if (!$category) abort_404();
		    
		    if (!forum()->user()->can($category["id"], "CREATE_TOPICS")) abort_404();
	    
	      $title = sanitize(input("title"));
		    $slug = slugify(input("title"));

        $insertThread = db()->prepare("INSERT INTO ForumThreads (title, slug, content, categoryID, accountID, views, creationDate, updatedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
        $insertThread->execute(array($title, $slug, input("message"), $category["id"], auth()->user()->id(), 0, datetime(), datetime()));
        $threadID = db()->lastInsertId();
        $threadUrl = url('forum.threads.show', ['id' => $threadID, 'slug' => $slug]);
	    
		    JobDispatcher::dispatch((new SendDiscordWebhook('forum.thread.posted', [
			    "username" => auth()->user()->displayName(),
			    "title" => input("title"),
			    "url" => website_url($threadUrl),
		    ])));

        redirect($threadUrl);
    }

    public function edit($id)
    {
        $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
		    if (!$thread) abort_404();
	    
		    $canModerate = forum()->user()->can($thread["categoryID"], "MODERATE_FORUM");
		    if (!$canModerate && $thread['accountID'] != auth()->user()->id()) {
			    abort_404();
		    }
				
				$category = db()->prepare("SELECT * FROM ForumCategories WHERE id = ?");
				$category->execute(array($thread["categoryID"]));
				$category = $category->fetch();
				$thread["category"] = $category;
	    
	      SeoService::set('forum.threads.edit', [
					'thread_title' => $thread["title"],
	      ]);

        return $this->view('forum.threads.edit', compact('thread'));
    }

    public function update($id)
    {
        validate([
            "title" => "required",
            "message" => "required"
        ]);

        $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
		    if (!$thread) abort_404();
		    
		    $canModerate = forum()->user()->can($thread["categoryID"], "MODERATE_FORUM");
		    if (!$canModerate && $thread['accountID'] != auth()->user()->id()) {
			    abort_404();
		    }
	    
	      $title = sanitize(input("title"));
		    if (input("title") != $thread["title"]) {
			    $slug = slugify(input("title"));
		    } else {
			    $slug = $thread["slug"];
		    }

        $updateThread = db()->prepare("UPDATE ForumThreads SET title = ?, slug = ?, content = ?, updatedDate = ? WHERE id = ?");
        $updateThread->execute(array($title, $slug, input("message"), datetime(), $thread["id"]));

        redirect(url('forum.threads.show', ['id' => $thread["id"], 'slug' => $thread["slug"]]));
    }

    public function destroy($id)
    {
        $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
		    if (!$thread) abort_404();
		    
		    $canModerate = forum()->user()->can($thread["categoryID"], "MODERATE_FORUM");
		    if (!$canModerate && $thread['accountID'] != auth()->user()->id()) {
			    abort_404();
		    }
	    
		    $deleteThread = db()->prepare("DELETE FROM ForumThreads WHERE id = ?");
		    $deleteThread->execute(array($id));
		    
		    redirect(url('forum.index'));
    }

    public function pin($id)
    {
 			  $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
		    if (!$thread) abort_404();
		    
		    $canModerate = forum()->user()->can($thread["categoryID"], "MODERATE_FORUM");
		    if (!$canModerate) {
			    abort_404();
		    }
	    
		    $pinThread = db()->prepare("UPDATE ForumThreads SET isPinned = ? WHERE id = ?");
		    $pinThread->execute(array($thread["isPinned"] ? "0" : "1", $id));
				
				return back()->flash("success", t__("The thread has been successfully pinned."));
    }

    public function lock($id)
    {
        $thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
        $thread->execute(array($id));
        $thread = $thread->fetch();
				
		    if (!$thread) abort_404();
		    
		    $canModerate = forum()->user()->can($thread["categoryID"], "MODERATE_FORUM");
		    if (!$canModerate && $thread['accountID'] != auth()->user()->id()) {
			    abort_404();
		    }
	    
		    $lockThread = db()->prepare("UPDATE ForumThreads SET isLocked = ? WHERE id = ?");
		    $lockThread->execute(array($thread["isLocked"] ? "0" : "1", $id));
		    
				return back()->flash("success", t__("The thread has been successfully locked."));
    }
	
		public function reply($id)
		{
			validate([
				"message" => "required"
			]);
			
			if (recaptcha()->isEnabled('reply_thread') && !recaptcha()->verify()) {
				return back()->flash('error', t__('Spam detected!'));
			}
			
			$thread = db()->prepare("SELECT * FROM ForumThreads WHERE id = ?");
			$thread->execute(array($id));
			$thread = $thread->fetch();
			
			if (!$thread) abort_404();
			
			// check if the user has permission to reply (can moderate or create replies)
			$canReply = forum()->user()->can($thread["categoryID"], "CREATE_REPLIES");
			if (!$canReply && $thread['isLocked'] == 1) {
				abort_404();
			}
			
			$insertReply = db()->prepare("INSERT INTO ForumReplies (message, accountID, threadID, creationDate, updatedDate) VALUES (?, ?, ?, ?, ?)");
			$insertReply->execute(array(input("message"), auth()->user()->id(), $thread["id"], datetime(), datetime()));
			
			$updateThread = db()->prepare("UPDATE ForumThreads SET updatedDate = ? WHERE id = ?");
			$updateThread->execute(array(datetime(), $thread["id"]));
			
			return back()->flash("success", t__("Your reply has been successfully sent."));
		}
}