<?php

namespace XF\Repository;

use XF\Mvc\Entity\ArrayCollection;
use XF\Mvc\Entity\Finder;
use XF\Mvc\Entity\Repository;

use function count;

abstract class AbstractPrompt extends Repository
{
	abstract protected function getClassIdentifier();

	public function getDefaultGroup()
	{
		$promptGroup = $this->em->create($this->getClassIdentifier() . 'Group');
		$promptGroup->setTrusted('prompt_group_id', 0);
		$promptGroup->setTrusted('display_order', 0);
		$promptGroup->setReadOnly(true);

		return $promptGroup;
	}

	/**
	 * @param bool $getDefault
	 *
	 * @return Finder|ArrayCollection
	 */
	public function findPromptGroups($getDefault = false)
	{
		$groups = $this->finder($this->getClassIdentifier() . 'Group')
			->order('display_order');

		if ($getDefault)
		{
			$groups = $groups->fetch();

			$defaultGroup = $this->getDefaultGroup();
			$promptGroups = $groups->toArray();
			$promptGroups = $promptGroups + [$defaultGroup];
			$groups = $this->em->getBasicCollection($promptGroups);
		}

		return $groups;
	}

	public function getPromptListData()
	{
		$prompts = $this->findPromptsForList()->fetch();
		$promptGroups = $this->findPromptGroups(true);

		return [
			'promptGroups' => $promptGroups,
			'promptsGrouped' => $prompts->groupBy('prompt_group_id'),
			'promptTotal' => count($prompts),
		];
	}

	/**
	 * @return Finder
	 */
	public function findPromptsForList()
	{
		return $this->finder($this->getClassIdentifier())
			->order(['materialized_order']);
	}

	/**
	 * Rebuilds the 'materialized_order' field in the prompt table,
	 * based on the canonical display_order data in the prompt and prompt_group tables.
	 */
	public function rebuildPromptMaterializedOrder()
	{
		$prompts = $this->finder($this->getClassIdentifier())
			->with('PromptGroup')
			->order([
				'PromptGroup.display_order',
				'display_order',
			]);

		$db = $this->db();
		$ungroupedPrompts = [];
		$updates = [];
		$i = 0;

		foreach ($prompts AS $promptId => $prompt)
		{
			if ($prompt->prompt_group_id)
			{
				if (++$i != $prompt->materialized_order)
				{
					$updates[$promptId] = 'WHEN ' . $db->quote($promptId) . ' THEN ' . $db->quote($i);
				}
			}
			else
			{
				$ungroupedPrompts[$promptId] = $prompt;
			}
		}

		foreach ($ungroupedPrompts AS $promptId => $prompt)
		{
			if (++$i != $prompt->materialized_order)
			{
				$updates[$promptId] = 'WHEN ' . $db->quote($promptId) . ' THEN ' . $db->quote($i);
			}
		}

		if (!empty($updates))
		{
			$structure = $this->em->getEntityStructure($this->getClassIdentifier());
			$table = $structure->table;

			$db->query('
				UPDATE `' . $table . '` SET materialized_order = CASE prompt_id
				' . implode(' ', $updates) . '
				END
				WHERE prompt_id IN(' . $db->quote(array_keys($updates)) . ')
			');
		}
	}
}
