<?php

namespace XF\ActivitySummary;

use XF\Entity\Post;
use XF\Finder\PostFinder;
use XF\Http\Request;
use XF\Mvc\Entity\AbstractCollection;
use XF\Mvc\Entity\Finder;
use XF\Repository\NodeRepository;

use function in_array;

class LatestPostsSection extends AbstractSection
{
	protected $defaultOptions = [
		'limit' => 5,
		'node_ids' => [0],
		'min_reaction_score' => null,
		'order' => '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(PostFinder::class)
			->with(['Thread', 'Thread.Forum', 'User', 'User.PermissionCombination'])
			->setDefaultOrder($this->options['order'], $this->options['direction']);
	}

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

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

		$postFinder
			->where('message_state', 'visible')
			->where('Thread.discussion_state', 'visible')
			->limit(max($limit * 5, 25));

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

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

		$postFinder->where('post_date', '>', $this->getActivityCutOff());

		return $postFinder;
	}

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

		$nodeIds = $posts->pluck(
			function (Post $post)
			{
				return $post->Thread ? [$post->post_id, $post->Thread->node_id] : null;
			},
			false
		);
		$instance->getUser()->cacheNodePermissions(array_unique($nodeIds));

		foreach ($posts AS $postId => $post)
		{
			if (!$post->canView() || $post->isIgnored())
			{
				unset($posts[$postId]);
				continue;
			}

			if ($instance->hasSeen('post', $postId))
			{
				unset($posts[$postId]);
				continue;
			}

			if ($post->isFirstPost() && $instance->hasSeen('thread', $post->thread_id))
			{
				unset($posts[$postId]);
				continue;
			}
		}

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

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

		foreach ($posts AS $post)
		{
			$instance->addSeen('post', $post->post_id);

			if ($post->isFirstPost())
			{
				$instance->addSeen('thread', $post->thread_id);
			}
		}

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

	protected function getDefaultOrderOptions()
	{
		return [
			'post_date' => \XF::phrase('post_date'),
			'reaction_score' => \XF::phrase('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',
			'min_reaction_score' => '?int',
			'order' => 'str',
			'direction' => 'str',
		]);

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

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

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

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

		return true;
	}
}
