<?php
namespace Misuzu;

use RuntimeException;
use Misuzu\Comments\{CommentsCategoryInfo,CommentsPostInfo};

if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
    die('Script must be called through the Misuzu route dispatcher.');

$redirect = filter_input(INPUT_GET, 'return') ?? $_SERVER['HTTP_REFERER'] ?? $msz->urls->format('index');

if(!Tools::isLocalURL($redirect))
    Template::displayInfo('Possible request forgery detected.', 403);

if(!CSRF::validateRequest())
    Template::displayInfo("Couldn't verify this request, please refresh the page and try again.", 403);

if(!$msz->authInfo->loggedIn)
    Template::displayInfo('You must be logged in to manage comments.', 403);

if($msz->usersCtx->hasActiveBan($msz->authInfo->userInfo))
    Template::displayInfo('You have been banned, check your profile for more information.', 403);

$perms = $msz->authInfo->getPerms('global');

$commentId = (string)filter_input(INPUT_GET, 'c', FILTER_SANITIZE_NUMBER_INT);
$commentMode = (string)filter_input(INPUT_GET, 'm');
$commentVote = (int)filter_input(INPUT_GET, 'v', FILTER_SANITIZE_NUMBER_INT);

if(!empty($commentId)) {
    try {
        $commentInfo = $msz->comments->getPost($commentId);
    } catch(RuntimeException $ex) {
        Template::displayInfo('Post not found.', 404);
    }

    $categoryInfo = $msz->comments->getCategory(postInfo: $commentInfo);
}

if($commentMode !== 'create' && empty($commentInfo))
    Template::throwError(400);

switch($commentMode) {
    case 'pin':
    case 'unpin':
        if(!isset($categoryInfo) || !($categoryInfo instanceof CommentsCategoryInfo))
            Template::displayInfo('Comment category not found.', 404);
        if(!$perms->check(Perm::G_COMMENTS_PIN) && !$categoryInfo->isOwner($msz->authInfo->userInfo))
            Template::displayInfo("You're not allowed to pin comments.", 403);
        if(!isset($commentInfo) || !($commentInfo instanceof CommentsPostInfo) || $commentInfo->deleted)
            Template::displayInfo("This comment doesn't exist!", 400);
        if($commentInfo->isReply)
            Template::displayInfo("You can't pin replies!", 400);

        $isPinning = $commentMode === 'pin';

        if($isPinning) {
            if($commentInfo->pinned)
                Template::displayInfo('This comment is already pinned.', 400);

            $msz->comments->pinPost($commentInfo);
        } else {
            if(!$commentInfo->pinned)
                Template::displayInfo("This comment isn't pinned yet.", 400);

            $msz->comments->unpinPost($commentInfo);
        }

        Tools::redirect($redirect . '#comment-' . $commentInfo->id);
        break;

    case 'vote':
        if(!isset($categoryInfo) || !($categoryInfo instanceof CommentsCategoryInfo))
            Template::displayInfo('Comment category not found.', 404);
        if(!$perms->check(Perm::G_COMMENTS_VOTE) && !$categoryInfo->isOwner($msz->authInfo->userInfo))
            Template::displayInfo("You're not allowed to vote on comments.", 403);
        if(!isset($commentInfo) || !($commentInfo instanceof CommentsPostInfo) || $commentInfo->deleted)
            Template::displayInfo("This comment doesn't exist!", 400);

        if($commentVote > 0)
            $msz->comments->addPostPositiveVote($commentInfo, $msz->authInfo->userInfo);
        elseif($commentVote < 0)
            $msz->comments->addPostNegativeVote($commentInfo, $msz->authInfo->userInfo);
        else
            $msz->comments->removePostVote($commentInfo, $msz->authInfo->userInfo);

        Tools::redirect($redirect . '#comment-' . $commentInfo->id);
        break;

    case 'delete':
        if(!isset($categoryInfo) || !($categoryInfo instanceof CommentsCategoryInfo))
            Template::displayInfo('Comment category not found.', 404);

        $canDelete = $perms->check(Perm::G_COMMENTS_DELETE_OWN | Perm::G_COMMENTS_DELETE_ANY);
        if(!$canDelete && !$categoryInfo->isOwner($msz->authInfo->userInfo))
            Template::displayInfo("You're not allowed to delete comments.", 403);

        $canDeleteAny = $perms->check(Perm::G_COMMENTS_DELETE_ANY);
        if(!isset($commentInfo) || !($commentInfo instanceof CommentsPostInfo) || $commentInfo->deleted)
            Template::displayInfo(
                $canDeleteAny ? 'This comment is already marked for deletion.' : "This comment doesn't exist.",
                400
            );

        $isOwnComment = $commentInfo->userId === $msz->authInfo->userInfo->id;
        $isModAction  = $canDeleteAny && !$isOwnComment;

        if(!$isModAction && !$isOwnComment)
            Template::displayInfo("You're not allowed to delete comments made by others.", 403);

        $msz->comments->deletePost($commentInfo);

        if($isModAction) {
            $msz->createAuditLog('COMMENT_ENTRY_DELETE_MOD', [
                $commentInfo->id,
                $commentUserId = $commentInfo->userId,
                '<username>',
            ]);
        } else {
            $msz->createAuditLog('COMMENT_ENTRY_DELETE', [$commentInfo->id]);
        }

        Tools::redirect($redirect);
        break;

    case 'restore':
        if(!$perms->check(Perm::G_COMMENTS_DELETE_ANY))
            Template::displayInfo("You're not allowed to restore deleted comments.", 403);

        if(!isset($commentInfo) || !($commentInfo instanceof CommentsPostInfo))
            Template::displayInfo("This comment is probably nuked already.", 404);
        if(!$commentInfo->deleted)
            Template::displayInfo("This comment isn't in a deleted state.", 400);

        $msz->comments->restorePost($commentInfo);

        $msz->createAuditLog('COMMENT_ENTRY_RESTORE', [
            $commentInfo->id,
            $commentUserId = $commentInfo->userId,
            '<username>',
        ]);

        Tools::redirect($redirect . '#comment-' . $commentInfo->id);
        break;

    case 'create':
        if(!isset($categoryInfo) || !($categoryInfo instanceof CommentsCategoryInfo))
            Template::displayInfo('Comment category not found.', 404);
        if(!$perms->check(Perm::G_COMMENTS_CREATE) && !$categoryInfo->isOwner($msz->authInfo->userInfo))
            Template::displayInfo("You're not allowed to post comments.", 403);
        if(empty($_POST['comment']) || !is_array($_POST['comment']))
            Template::displayInfo('Missing data.', 400);

        try {
            $categoryId = isset($_POST['comment']['category']) && is_string($_POST['comment']['category'])
                ? (int)$_POST['comment']['category']
                : 0;
            $categoryInfo = $msz->comments->getCategory(categoryId: (string)$categoryId);
        } catch(RuntimeException $ex) {
            Template::displayInfo("This comment category doesn't exist.", 404);
        }

        $canLock = $perms->check(Perm::G_COMMENTS_LOCK);
        if($categoryInfo->locked && !$canLock)
            Template::displayInfo('This comment category has been locked.', 403);

        $commentText = !empty($_POST['comment']['text'])  && is_string($_POST['comment']['text']) ? $_POST['comment']['text'] : '';
        $commentReply = (string)(!empty($_POST['comment']['reply']) && is_string($_POST['comment']['reply']) ? (int)$_POST['comment']['reply'] : 0);
        $commentLock = !empty($_POST['comment']['lock']) && $canLock;
        $commentPin = !empty($_POST['comment']['pin']) && $perms->check(Perm::G_COMMENTS_PIN);

        if($commentLock) {
            if($categoryInfo->locked)
                $msz->comments->unlockCategory($categoryInfo);
            else
                $msz->comments->lockCategory($categoryInfo);
        }

        if(strlen($commentText) > 0) {
            $commentText = preg_replace("/[\r\n]{2,}/", "\n", $commentText);
        } else {
            if($canLock)
                Template::displayInfo('The action has been processed.', 400);
            else
                Template::displayInfo('Your comment is too short.', 400);
        }

        if(mb_strlen($commentText) > 5000)
            Template::displayInfo('Your comment is too long.', 400);

        if($commentReply > 0) {
            try {
                $parentInfo = $msz->comments->getPost($commentReply);
            } catch(RuntimeException $ex) {}

            if(!isset($parentInfo) || !($parentInfo instanceof CommentsPostInfo) || $parentInfo->deleted)
                Template::displayInfo('The comment you tried to reply to does not exist.', 404);
        }

        $commentInfo = $msz->comments->createPost(
            $categoryInfo,
            $parentInfo ?? null,
            $msz->authInfo->userInfo,
            $commentText,
            $commentPin
        );

        Tools::redirect($redirect . '#comment-' . $commentInfo->id);
        break;

    default:
        Template::displayInfo('Not found.', 404);
}