<?php
namespace Misuzu;

use stdClass;
use RuntimeException;
use Index\DateTime;
use Misuzu\Forum\ForumTopicInfo;
use Misuzu\Parsers\Parser;

$authInfo = $msz->getAuthInfo();
if(!$authInfo->isLoggedIn())
    Template::throwError(401);

$forumCtx = $msz->getForumContext();
$forumCategories = $forumCtx->getCategories();
$forumTopics = $forumCtx->getTopics();
$forumPosts = $forumCtx->getPosts();
$usersCtx = $msz->getUsersContext();

$currentUser = $authInfo->getUserInfo();
$currentUserId = $currentUser->getId();
if($usersCtx->hasActiveBan($currentUser))
    Template::throwError(403);

$forumPostingModes = [
    'create', 'edit', 'quote', 'preview',
];

if(!empty($_POST)) {
    $mode = !empty($_POST['post']['mode']) && is_string($_POST['post']['mode']) ? $_POST['post']['mode'] : 'create';
    $postId = !empty($_POST['post']['id']) && is_string($_POST['post']['id']) ? (int)$_POST['post']['id'] : 0;
    $topicId = !empty($_POST['post']['topic']) && is_string($_POST['post']['topic']) ? (int)$_POST['post']['topic'] : 0;
    $forumId = !empty($_POST['post']['forum']) && is_string($_POST['post']['forum']) ? (int)$_POST['post']['forum'] : 0;
} else {
    $mode = !empty($_GET['m']) && is_string($_GET['m']) ? $_GET['m'] : 'create';
    $postId = !empty($_GET['p']) && is_string($_GET['p']) ? (int)$_GET['p'] : 0;
    $topicId = !empty($_GET['t']) && is_string($_GET['t']) ? (int)$_GET['t'] : 0;
    $forumId = !empty($_GET['f']) && is_string($_GET['f']) ? (int)$_GET['f'] : 0;
}

if(!in_array($mode, $forumPostingModes, true))
    Template::throwError(400);

if($mode === 'preview') {
    header('Content-Type: text/plain; charset=utf-8');

    $postText = (string)($_POST['post']['text']);
    $postParser = (int)($_POST['post']['parser']);

    if(!Parser::isValid($postParser)) {
        http_response_code(400);
        return;
    }

    http_response_code(200);
    echo Parser::instance($postParser)->parseText(htmlspecialchars($postText));
    return;
}

if(empty($postId) && empty($topicId) && empty($forumId))
    Template::throwError(404);

if(empty($postId)) {
    $hasPostInfo = false;
} else {
    try {
        $postInfo = $forumPosts->getPost(postId: $postId);
    } catch(RuntimeException $ex) {
        Template::throwError(404);
    }

    if($postInfo->isDeleted())
        Template::throwError(404);

    // should automatic cross-quoting be a thing? if so, check if $topicId is < 1 first <-- what did i mean by this?
    $topicId = $postInfo->getTopicId();
    $hasPostInfo = true;
}

if(empty($topicId)) {
    $hasTopicInfo = false;
} else {
    try {
        $topicInfo = $forumTopics->getTopic(topicId: $topicId);
    } catch(RuntimeException $ex) {
        Template::throwError(404);
    }

    if($topicInfo->isDeleted())
        Template::throwError(404);

    $forumId = $topicInfo->getCategoryId();
    $originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
    $hasTopicInfo = true;
}

if(empty($forumId)) {
    $hasCategoryInfo = false;
} else {
    try {
        $categoryInfo = $forumCategories->getCategory(categoryId: $forumId);
    } catch(RuntimeException $ex) {
        Template::throwError(404);
    }

    $hasCategoryInfo = true;
}

$perms = $authInfo->getPerms('forum', $categoryInfo);

if($categoryInfo->isArchived()
    || (isset($topicInfo) && $topicInfo->isLocked() && !$perms->check(Perm::F_TOPIC_LOCK))
    || !$perms->check(Perm::F_CATEGORY_VIEW)
    || !$perms->check(Perm::F_POST_CREATE)
    || (!isset($topicInfo) && !$perms->check(Perm::F_TOPIC_CREATE)))
    Template::throwError(403);

if(!$categoryInfo->mayHaveTopics())
    Template::throwError(400);

$topicTypes = [];

if($mode === 'create' || $mode === 'edit') {
    $topicTypes['discussion'] = 'Normal discussion';

    if($perms->check(Perm::F_TOPIC_STICKY))
        $topicTypes['sticky'] = 'Sticky topic';
    if($perms->check(Perm::F_TOPIC_ANNOUNCE_LOCAL))
        $topicTypes['announce'] = 'Announcement';
    if($perms->check(Perm::F_TOPIC_ANNOUNCE_GLOBAL))
        $topicTypes['global'] = 'Global Announcement';
}

// edit mode stuff
if($mode === 'edit' && !$perms->check($postInfo->getUserId() === $currentUserId ? Perm::F_POST_EDIT_OWN : Perm::F_POST_EDIT_ANY))
    Template::throwError(403);

$notices = [];

if(!empty($_POST)) {
    $topicTitle = $_POST['post']['title'] ?? '';
    $postText = $_POST['post']['text'] ?? '';
    $postParser = (int)($_POST['post']['parser'] ?? Parser::BBCODE);
    $topicType = isset($_POST['post']['type']) ? $_POST['post']['type'] : null;
    $postSignature = isset($_POST['post']['signature']);

    if(!CSRF::validateRequest()) {
        $notices[] = 'Could not verify request.';
    } else {
        $isEditingTopic = empty($topicInfo) || ($mode === 'edit' && $originalPostInfo->getId() == $postInfo->getId());

        if($mode === 'create') {
            $postTimeout = $cfg->getInteger('forum.posting.timeout', 5);
            if($postTimeout > 0) {
                $postTimeoutThreshold = DateTime::now()->modify(sprintf('-%d seconds', $postTimeout));
                $lastPostCreatedAt = $forumPosts->getUserLastPostCreatedAt($currentUser);

                if($lastPostCreatedAt->isMoreThan($postTimeoutThreshold)) {
                    $waitSeconds = $postTimeout + ($lastPostCreatedAt->getUnixTimeSeconds() - time());

                    $notices[] = sprintf("You're posting too quickly! Please wait %s seconds before posting again.", number_format($waitSeconds));
                    $notices[] = "It's possible that your post went through successfully and you pressed the submit button twice by accident.";
                }
            }
        }

        if($isEditingTopic) {
            $originalTopicTitle = $topicInfo?->getTitle() ?? null;
            $topicTitleChanged = $topicTitle !== $originalTopicTitle;
            $originalTopicType = $topicInfo?->getTypeString() ?? 'discussion';
            $topicTypeChanged = $topicType !== null && $topicType !== $originalTopicType;

            $topicTitleLengths = $cfg->getValues([
                ['forum.topic.minLength:i', 3],
                ['forum.topic.maxLength:i', 100],
            ]);

            $topicTitleLength = mb_strlen(trim($topicTitle));
            if($topicTitleLength < $topicTitleLengths['forum.topic.minLength'])
                $notices[] = 'Topic title was too short.';
            elseif($topicTitleLength > $topicTitleLengths['forum.topic.maxLength'])
                $notices[] = 'Topic title was too long.';

            if($mode === 'create' && $topicType === null) {
                $topicType = array_key_first($topicTypes);
            } elseif(!array_key_exists($topicType, $topicTypes) && $topicTypeChanged) {
                $notices[] = 'You are not allowed to set this topic type.';
            }
        }

        if(!Parser::isValid($postParser))
            $notices[] = 'Invalid parser selected.';

        $postTextLengths = $cfg->getValues([
            ['forum.post.minLength:i', 1],
            ['forum.post.maxLength:i', 60000],
        ]);

        $postTextLength = mb_strlen(trim($postText));
        if($postTextLength < $postTextLengths['forum.post.minLength'])
            $notices[] = 'Post content was too short.';
        elseif($postTextLength > $postTextLengths['forum.post.maxLength'])
            $notices[] = 'Post content was too long.';

        if(empty($notices)) {
            switch($mode) {
                case 'create':
                    if(empty($topicInfo)) {
                        $topicInfo = $forumTopics->createTopic(
                            $categoryInfo,
                            $currentUser,
                            $topicTitle,
                            $topicType
                        );

                        $topicId = $topicInfo->getId();
                        $forumCategories->incrementCategoryTopics($categoryInfo);
                    } else
                        $forumTopics->bumpTopic($topicInfo);

                    $postInfo = $forumPosts->createPost(
                        $topicId,
                        $currentUser,
                        $_SERVER['REMOTE_ADDR'],
                        $postText,
                        $postParser,
                        $postSignature,
                        $categoryInfo
                    );

                    $postId = $postInfo->getId();
                    $forumCategories->incrementCategoryPosts($categoryInfo);
                    break;

                case 'edit':
                    $markUpdated = $postInfo->getUserId() === $currentUserId
                        && $postInfo->shouldMarkAsEdited()
                        && $postText !== $postInfo->getBody();

                    $forumPosts->updatePost(
                        $postId,
                        remoteAddr: $_SERVER['REMOTE_ADDR'],
                        body: $postText,
                        bodyParser: $postParser,
                        displaySignature: $postSignature,
                        bumpEdited: $markUpdated
                    );

                    if($isEditingTopic && ($topicTitleChanged || $topicTypeChanged))
                        $forumTopics->updateTopic(
                            $topicId,
                            title: $topicTitle,
                            type: $topicType
                        );
                    break;
            }

            if(empty($notices)) {
                // does this ternary ever return forum-topic?
                $redirect = $msz->getURLs()->format(empty($topicInfo) ? 'forum-topic' : 'forum-post', [
                    'topic' => $topicId ?? 0,
                    'post' => $postId ?? 0,
                ]);
                Tools::redirect($redirect);
                return;
            }
        }
    }
}

if(!empty($topicInfo))
    Template::set('posting_topic', $topicInfo);

if($mode === 'edit') { // $post is pretty much sure to be populated at this point
    $post = new stdClass;
    $post->info = $postInfo;

    if($postInfo->hasUserId()) {
        $post->user = $usersCtx->getUserInfo($postInfo->getUserId());
        $post->colour = $usersCtx->getUserColour($post->user);
        $post->postsCount = $forumCtx->countTotalUserPosts($post->user);
    }

    $post->isOriginalPost = $originalPostInfo->getId() == $postInfo->getId();
    $post->isOriginalPoster = $originalPostInfo->hasUserId() && $postInfo->hasUserId()
        && $originalPostInfo->getUserId() === $postInfo->getUserId();

    Template::set('posting_post', $post);
}

try {
    $lastPostInfo = $forumPosts->getPost(userInfo: $currentUser, getLast: true, deleted: false);
    $selectedParser = $lastPostInfo->getParser();
} catch(RuntimeException $ex) {
    $selectedParser = Parser::BBCODE;
}

Template::render('forum.posting', [
    'posting_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo),
    'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
    'posting_user' => $currentUser,
    'posting_user_colour' => $usersCtx->getUserColour($currentUser),
    'posting_user_posts_count' => $forumCtx->countTotalUserPosts($currentUser),
    'posting_user_preferred_parser' => $selectedParser,
    'posting_forum' => $categoryInfo,
    'posting_notices' => $notices,
    'posting_mode' => $mode,
    'posting_types' => $topicTypes,
    'posting_defaults' => [
        'title' => $topicTitle ?? null,
        'type' => $topicType ?? null,
        'text' => $postText ?? null,
        'parser' => $postParser ?? null,
        'signature' => $postSignature ?? null,
    ],
]);
