<?php

namespace XF\ThreadType;

use XF\Api\Result\EntityResult;
use XF\Entity\Forum;
use XF\Entity\Thread;
use XF\Http\Request;
use XF\Mvc\Entity\Entity;
use XF\Repository\ContentVoteRepository;

class SuggestionHandler extends AbstractHandler
{
	public function getTypeIconClass(): string
	{
		return 'fa-lightbulb-on';
	}

	public function getThreadViewAndTemplate(Thread $thread): array
	{
		return ['XF:Thread\ViewTypeSuggestion', 'thread_view_type_suggestion'];
	}

	public function getThreadViewTemplateOverrides(Thread $thread, array $extra = []): array
	{
		return [
			'pinned_first_post_macro' => 'post_suggestion_macros::suggestion',
		];
	}

	public function adjustThreadViewParams(Thread $thread, array $viewParams, Request $request): array
	{
		$suggestionInfo = [
			'implemented' => false,
			'closed' => false,
		];

		$forum = $this->getForumIfSuggestionType($thread);
		if ($forum && $thread->prefix_id)
		{
			$prefixId = $thread->prefix_id;
			$forumTypeConfig = $forum->type_config;

			$suggestionInfo['implemented'] = isset($forumTypeConfig['implemented_prefix_ids'][$prefixId]);
			$suggestionInfo['closed'] = isset($forumTypeConfig['closed_prefix_ids'][$prefixId]);
		}

		$viewParams['suggestionInfo'] = $suggestionInfo;

		return $viewParams;
	}

	public function isFirstPostPinned(Thread $thread): bool
	{
		return true;
	}

	public function isThreadVotingSupported(Thread $thread): bool
	{
		if ($thread->type_data['allow_voting'] === 'no')
		{
			return false;
		}

		return true;
	}

	public function isThreadDownvoteSupported(Thread $thread): bool
	{
		$forum = $this->getForumIfSuggestionType($thread);
		if (!$forum)
		{
			return true;
		}

		return $forum->type_config['allow_downvote'];
	}

	public function canVoteOnThread(Thread $thread, &$error = null): bool
	{
		if ($thread->type_data['allow_voting'] !== 'yes')
		{
			return false;
		}

		if (!\XF::visitor()->hasNodePermission($thread->node_id, 'contentVote'))
		{
			return false;
		}

		$forum = $this->getForumIfSuggestionType($thread);
		if ($forum && $thread->prefix_id)
		{
			// only apply these limits to suggestions in suggestion forums
			$prefixId = $thread->prefix_id;
			$forumTypeConfig = $forum->type_config;

			if (
				isset($forumTypeConfig['implemented_prefix_ids'][$prefixId])
				|| isset($forumTypeConfig['closed_prefix_ids'][$prefixId])
			)
			{
				// can't vote on implemented or closed suggestions
				return false;
			}
		}

		if (!$thread->discussion_open && !$thread->canLockUnlock())
		{
			$error = \XF::phraseDeferred('you_may_not_perform_this_action_because_discussion_is_closed');
			return false;
		}

		return true;
	}

	/**
	 * Only returns the containing forum if it's a suggestion forum. This is primarily used to make
	 * it easier to switch on behavior that relies on the suggestion forum's type config.
	 *
	 * @param Thread $thread
	 *
	 * @return Forum|null
	 */
	protected function getForumIfSuggestionType(Thread $thread)
	{
		return $this->getForumIfType($thread, \XF\ForumType\SuggestionHandler::class);
	}

	public function getDefaultTypeData(): array
	{
		return [
			'allow_voting' => 'yes',
		];
	}

	protected function getTypeDataColumnDefinitions(): array
	{
		return [
			'allow_voting' => ['type' => Entity::STR, 'allowedValues' => ['yes', 'no', 'paused']],
		];
	}

	protected function renderExtraDataEditInternal(
		Thread $thread,
		array $typeData,
		string $context,
		string $subContext,
		array $options = []
	): string
	{
		$params = [
			'handler' => $this,
			'thread' => $thread,
			'typeData' => $typeData,
			'typeDataDefinitions' => $this->getTypeDataColumnDefinitions(),
			'context' => $context,
			'subContext' => $subContext,
			'draft' => $options['draft'] ?? [],
		];

		return \XF::app()->templater()->renderTemplate('public:thread_type_fields_suggestion', $params);
	}

	public function processExtraDataSimple(
		Thread $thread,
		string $context,
		Request $request,
		&$errors = [],
		array $options = []
	)
	{
		$validator = $this->getTypeDataValidator($thread);

		if ($thread->canEditModeratorFields())
		{
			$validator->allow_voting = $request->filter('suggestion.allow_voting', 'str');
		}

		return $validator;
	}

	public function processExtraDataForApiSimple(
		Thread $thread,
		string $context,
		Request $request,
		&$errors = [],
		array $options = []
	)
	{
		$validator = $this->getTypeDataValidator($thread);

		if ($thread->canEditModeratorFields() || \XF::isApiBypassingPermissions())
		{
			$allowVoting = $request->filter('suggestion.allow_voting', '?str');
			if ($allowVoting !== null)
			{
				$validator->allow_voting = $allowVoting;
			}
		}

		return $validator;
	}

	public function addTypeDataToApiResult(
		Thread $thread,
		EntityResult $result,
		int $verbosity = Entity::VERBOSITY_NORMAL,
		array $options = []
	)
	{
		$result->suggestion = [
			'allow_voting' => $thread->type_data['allow_voting'],
		];
	}

	public function onThreadLeaveType(Thread $thread, array $typeData, bool $isDelete)
	{
		if (!$isDelete)
		{
			// these will be cleaned up on delete already so don't need to do that
			\XF::repository(ContentVoteRepository::class)->fastDeleteVotesForContent('thread', $thread->thread_id);

			$thread->fastUpdate([
				'vote_score' => 0,
				'vote_count' => 0,
			]);

			\XF::db()->update(
				'xf_content_activity_log',
				[
					'vote_count' => 0,
					'vote_score' => 0,
				],
				'content_type = ? AND content_id = ?',
				['thread', $thread->thread_id]
			);
		}
	}
}
