<?php

namespace XF\ActivitySummary;

use XF\Entity\Thread;
use XF\Finder\ThreadFinder;
use XF\Http\Request;
use XF\Mvc\Entity\AbstractCollection;
use XF\Mvc\Entity\Finder;
use XF\Repository\NodeRepository;

use function in_array;

class LatestThreadsSection extends AbstractSection
{
	protected $defaultOptions = [
		'limit' => 5,
		'node_ids' => [0],
		'condition' => 'last_post_date',
		'min_replies' => null,
		'min_reaction_score' => null,
		'order' => 'last_post_date',
		'direction' => 'DESC',
	];

	protected function getDefaultTemplateParams($context)
	{
		$params = parent::getDefaultTemplateParams($context);
		if ($context == 'options')
		{
			$nodeRepo = $this->repository(NodeRepository::class);
			$params['nodeTree'] = $nodeRepo->createNodeTree($nodeRepo->getFullNodeList());

			$params['sortOrders'] = $this->getDefaultOrderOptions();
		}
		return $params;
	}

	protected function getBaseFinderForFetch(): Finder
	{
		return $this->finder(ThreadFinder::class)
			->with(['FirstPost', 'Forum', 'User', 'User.PermissionCombination'])
			->setDefaultOrder($this->options['order'], $this->options['direction']);
	}

	protected function findDataForFetch(Finder $threadFinder): Finder
	{
		$options = $this->options;

		$limit = $options['limit'];
		$nodeIds = $options['node_ids'];
		$condition = $options['condition'];
		$minReplies = $options['min_replies'];
		$minReactionScore = $options['min_reaction_score'];

		$threadFinder
			->where('discussion_state', 'visible')
			->where('discussion_type', '<>', 'redirect')
			->limit(max($limit * 5, 25));

		if ($nodeIds && !in_array(0, $nodeIds))
		{
			$threadFinder->where('node_id', $nodeIds);
		}
		else
		{
			$threadFinder->where('Forum.find_new', true);
		}

		$threadFinder->where($condition, '>', $this->getActivityCutOff());

		if ($minReplies !== null)
		{
			$threadFinder->where('reply_count', '>=', $minReplies);
		}

		if ($minReactionScore !== null)
		{
			$threadFinder->where('first_post_reaction_score', '>=', $minReactionScore);
		}

		return $threadFinder;
	}

	protected function renderInternal(Instance $instance): string
	{
		/** @var AbstractCollection<Thread> $threads */
		$threads = $this->fetchData();

		$nodeIds = $threads->pluckNamed('node_id');
		$instance->getUser()->cacheNodePermissions(array_unique($nodeIds));

		foreach ($threads AS $threadId => $thread)
		{
			if (!$thread->canView() || $thread->isIgnored())
			{
				unset($threads[$threadId]);
				continue;
			}

			if ($instance->hasSeen('thread', $threadId))
			{
				unset($threads[$threadId]);
				continue;
			}

			if ($instance->hasSeen('post', $thread->first_post_id))
			{
				unset($threads[$threadId]);
				continue;
			}
		}

		if (!$threads->count())
		{
			return '';
		}

		$threads = $threads->slice(0, $this->options['limit']);

		foreach ($threads AS $thread)
		{
			$instance->addSeen('thread', $thread->thread_id);
			$instance->addSeen('post', $thread->first_post_id);
		}

		$viewParams = [
			'threads' => $threads,
		];
		return $this->renderSectionTemplate($instance, 'activity_summary_latest_threads', $viewParams);
	}

	protected function getDefaultOrderOptions()
	{
		return [
			'last_post_date' => \XF::phrase('last_message'),
			'post_date' => \XF::phrase('start_date'),
			'reply_count' => \XF::phrase('replies'),
			'view_count' => \XF::phrase('views'),
			'first_post_reaction_score' => \XF::phrase('first_message_reaction_score'),
			'vote_score' => \XF::phrase('vote_score'),
		];
	}

	public function verifyOptions(Request $request, array &$options, &$error = null)
	{
		$options = $request->filter([
			'limit' => 'uint',
			'node_ids' => 'array-uint',
			'condition' => 'str',
			'min_replies' => '?uint',
			'min_reaction_score' => '?int',
			'min_last_reply_days' => '?uint',
			'order' => 'str',
			'direction' => 'str',
		]);

		if (in_array(0, $options['node_ids']))
		{
			$options['node_ids'] = [0];
		}

		if ($options['limit'] < 1)
		{
			$options['limit'] = 1;
		}

		if (!in_array($options['condition'], ['post_date', 'last_post_date']))
		{
			$options['condition'] = 'last_post_date';
		}

		$orders = $this->getDefaultOrderOptions();
		if (!isset($orders[$options['order']]))
		{
			$options['order'] = 'last_post_date';
		}

		$options['direction'] = strtoupper($options['direction']);
		if (!in_array($options['direction'], ['ASC', 'DESC']))
		{
			$options['direction'] = 'DESC';
		}

		return true;
	}
}
