<?php

/**
 * The FAQ Controller
 *
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at https://mozilla.org/MPL/2.0/.
 *
 * @package   phpMyFAQ
 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
 * @copyright 2024-2026 phpMyFAQ Team
 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link      https://www.phpmyfaq.de
 * @since     2024-03-03
 */

declare(strict_types=1);

namespace phpMyFAQ\Controller\Frontend;

use phpMyFAQ\Category;
use phpMyFAQ\Category\Permission as CategoryPermission;
use phpMyFAQ\Controller\AbstractController;
use phpMyFAQ\Core\Exception;
use phpMyFAQ\Entity\FaqEntity;
use phpMyFAQ\Enums\PermissionType;
use phpMyFAQ\Faq\MetaData;
use phpMyFAQ\Faq\Permission as FaqPermission;
use phpMyFAQ\Filter;
use phpMyFAQ\Translation;
use phpMyFAQ\User\CurrentUser;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

final class FaqController extends AbstractController
{
    /**
     * @throws Exception|\JsonException|\Exception
     */
    public function create(Request $request): JsonResponse
    {
        $faq = $this->container->get(id: 'phpmyfaq.faq');
        $faqHelper = $this->container->get(id: 'phpmyfaq.helper.faq');
        $question = $this->container->get(id: 'phpmyfaq.question');
        $stopWords = $this->container->get(id: 'phpmyfaq.stop-words');
        $session = $this->container->get(id: 'phpmyfaq.user.session');
        $session->setCurrentUser($this->currentUser);

        $categoryPermission = new CategoryPermission($this->configuration);
        $faqPermission = new FaqPermission($this->configuration);

        $language = $this->container->get(id: 'phpmyfaq.language');
        $languageCode = $this->configuration->get(item: 'main.languageDetection')
            ? $language->setLanguageWithDetection($this->configuration->get(item: 'main.language'))
            : $language->setLanguageFromConfiguration($this->configuration->get(item: 'main.language'));

        if (!$this->isAddingFaqsAllowed($this->currentUser)) {
            return $this->json(['error' => Translation::get(key: 'ad_msg_noauth')], Response::HTTP_FORBIDDEN);
        }

        $data = json_decode($request->getContent(), false, 512, JSON_THROW_ON_ERROR);

        $author = trim((string) Filter::filterVar($data->name, FILTER_SANITIZE_SPECIAL_CHARS));
        $email = trim((string) Filter::filterVar($data->email, FILTER_VALIDATE_EMAIL));
        $email = Filter::filterVar($email, FILTER_SANITIZE_SPECIAL_CHARS);
        $questionText = Filter::filterVar($data->question, FILTER_SANITIZE_SPECIAL_CHARS);
        $questionText = trim(strip_tags((string) $questionText));

        if ($this->configuration->get(item: 'main.enableWysiwygEditorFrontend')) {
            $answer = Filter::filterVar($data->answer, FILTER_SANITIZE_SPECIAL_CHARS);
            $answer = trim(html_entity_decode((string) $answer));
        } else {
            $answer = Filter::filterVar($data->answer, FILTER_SANITIZE_SPECIAL_CHARS);
            $answer = strip_tags((string) $answer);
            $answer = trim(nl2br($answer));
        }

        $category = new Category($this->configuration);
        $keywords = Filter::filterVar($data->keywords, FILTER_SANITIZE_SPECIAL_CHARS);
        if (isset($data->rubrik)) {
            if (is_string($data->rubrik)) {
                $data->rubrik = [$data->rubrik];
            }

            $categories = Filter::filterArray($data->rubrik);
        } else {
            $categories = [$category->getAllCategoryIds()[0]];
        }

        if (!$this->captchaCodeIsValid($request)) {
            return $this->json(['error' => Translation::get(key: 'msgCaptcha')], Response::HTTP_BAD_REQUEST);
        }

        if (
            $author !== ''
            && $author !== '0'
            && $email !== ''
            && $email !== '0'
            && $questionText !== ''
            && $questionText !== '0'
            && $stopWords->checkBannedWord(strip_tags($questionText))
        ) {
            if ($answer !== '' && $answer !== '0') {
                $stopWords->checkBannedWord(strip_tags($answer));
            } else {
                $answer = '';
            }

            $session->userTracking('save_new_entry', 0);

            $autoActivate = $this->configuration->get(item: 'records.defaultActivation');

            $faqEntity = new FaqEntity();
            $faqEntity
                ->setLanguage($languageCode)
                ->setQuestion($questionText)
                ->setActive($autoActivate)
                ->setSticky(false)
                ->setAnswer($answer)
                ->setKeywords($keywords)
                ->setAuthor($author)
                ->setEmail($email)
                ->setComment(true)
                ->setNotes('');

            $faq->create($faqEntity);
            $recordId = $faqEntity->getId();

            // The FAQ has been stored. Everything below is post-processing (metadata,
            // permissions, notification mail, …) and must never prevent the user from
            // receiving the confirmation. A failure here is logged but swallowed so the
            // success response is always returned, closes #4282.
            $link = [];

            try {
                $openQuestionId = Filter::filterVar($data->openQuestionID, FILTER_VALIDATE_INT);
                if ($openQuestionId) {
                    if ($this->configuration->get(item: 'records.enableDeleteQuestion')) {
                        $question->delete($openQuestionId);
                    } else { // adds this faq record id to the related open question
                        $question->updateQuestionAnswer((int) $openQuestionId, (int) $recordId, (int) $categories[0]);
                    }
                }

                $faqMetaData = new MetaData($this->configuration);
                $faqMetaData
                    ->setFaqId($recordId)
                    ->setFaqLanguage($faqEntity->getLanguage())
                    ->setCategories($categories)
                    ->save();

                // Let the admin and the category owners to be informed by email of this new entry
                $categoryHelper = $this->container->get(id: 'phpmyfaq.helper.category-helper');
                $categoryHelper->setCategory($category)->setConfiguration($this->configuration);

                $moderators = $categoryHelper->getModerators($categories);

                // Add user and group permissions
                $permissions = $categoryPermission->getAll($categories);
                foreach ($categories as $category) {
                    $faqPermission->add(FaqPermission::USER, $recordId, $permissions[$category]['user']);
                    if ($this->configuration->get(item: 'security.permLevel') !== 'basic') {
                        $faqPermission->add(FaqPermission::GROUP, $recordId, $permissions[$category]['group']);
                    }
                }

                $notification = $this->container->get(id: 'phpmyfaq.notification');
                $notification->sendNewFaqAdded($moderators, $faqEntity);

                if ($this->configuration->get(item: 'records.defaultActivation')) {
                    $link = [
                        'link' => $faqHelper->createFaqUrl($faqEntity, $categories[0]),
                        'info' => Translation::get(key: 'msgRedirect'),
                    ];
                }
            } catch (\Throwable $e) {
                $this->configuration->getLogger()->info('Post-processing after FAQ creation failed: ', [$e->getMessage()]);
            }

            return $this->json([
                'success' => Translation::get(key: 'msgNewContentThanks'),
                ...$link,
            ], Response::HTTP_OK);
        }

        return $this->json(['error' => Translation::get(key: 'errSaveEntries')], Response::HTTP_BAD_REQUEST);
    }

    /**
     * @throws \Exception
     */
    private function isAddingFaqsAllowed(CurrentUser $currentUser): bool
    {
        return !(
            !$this->configuration->get(item: 'records.allowNewFaqsForGuests')
            && !$currentUser->perm->hasPermission($currentUser->getUserId(), PermissionType::FAQ_ADD->value)
        );
    }
}
