<?php

namespace wcf\data\multirank;

use wcf\data\AbstractDatabaseObjectAction;
use wcf\data\ISortableAction;
use wcf\data\user\rank\UserRankList;
use wcf\data\user\User;
use wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\WCF;
use wcf\util\StringUtil;

/**
 * @author        Olaf Braun
 * @copyright     2013-2023 Olaf Braun - Software Development
 * @license       WBB-Elite.de License <https://lizenz.wbb-elite.de/lizenz.html>
 * @package       de.wbb-elite.multirank
 * @category      Several rank graphics
 *
 * @method    MultirankEditor[]        getObjects()
 * @property MultirankEditor[] $objects
 * @method    MultirankEditor        getSingleObject()
 */
class MultirankAction extends AbstractDatabaseObjectAction implements ISortableAction {
	
	/**
	 * @inheritdoc
	 */
	public $permissionsDelete = ['admin.multirank.canMange'];
	/**
	 * @inheritdoc
	 */
	public $permissionsCreate = ['admin.multirank.canMange'];
	/**
	 * @inheritdoc
	 */
	public $permissionsUpdate = ['admin.multirank.canMange'];
	/**
	 * @inheritdoc
	 */
	public $allowGuestAccess = ['getMultirank'];
	/**
	 * @inheritdoc
	 */
	protected $className = MultirankEditor::class;
	
	/**
	 * Validate the get multirank function
	 */
	public function validateGetMultirank() {
		$parameters = $this->getParameters();
		if (!isset($parameters["multirankID"])) {
			throw new PermissionDeniedException();
		}
		$this->objectIDs = \array_values(\array_unique($this->objectIDs));
	}
	
	/**
	 * Return the multiranks for given users
	 *
	 * @return    array
	 */
	public function getMultirank() {
		$array = [];
		$settings = '';
		$parameters = $this->getParameters();
		$sql = "SELECT css,cssDiv, max
				FROM wcf" . WCF_N . "_multirank
				WHERE multirankID = ?";
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute([$parameters["multirankID"]]);
		$row = $statement->fetchArray();
		$max = 0;
		$cssDiv = 0;
		$zahl = 0;
		if ($row) {
			$settings = $row["css"];
			$cssDiv = $row["cssDiv"];
			$max = $row["max"];
		}
		if (\count($this->objectIDs) > 0) {
			$users = UserProfileRuntimeCache::getInstance()->getObjects($this->objectIDs);
			if (\count($users) > 0) {
				$userIDs = [];
				foreach ($users as $user) {
					if (!$user || !$user->userID) continue;
					$userIDs[] = $user->userID;
				}
				if (count($userIDs) > 0) {
					$objects = $this->getUserOptions($userIDs);
					$userRanks = $this->getRanks();
					foreach ($users as $user) {
						if (!$user || !$user->userID) continue;
						$count = 0;
						$string = '';
						if (isset($objects[$user->userID])) {
							$rankIDs = $objects[$user->userID];
							if (\is_array($rankIDs) && count($rankIDs) > 0) {
								
								foreach ($userRanks as $rank) {
									$zahl = ($zahl + 1);
									$DIV = '"userRank'.$zahl.'"';
									if ($max != 0 && $count >= $max) {
										break;
									}
									$rankID = $rank->rankID;
									if (\array_key_exists($rankID, $rankIDs)) {
										$count++;
										if (\mb_strlen($rank->rankImage) > 0) {
											$string .= '<div class='.$DIV.($cssDiv ? ' style="'.$cssDiv.'"' : '').'>' . $rank->getImage() . '</div>';
										} else {
											$string .= '<div class="userTitle" '.($cssDiv ? ' style="'.$cssDiv.'"' : '').'><span class="badge userTitleBadge ' . $rank->cssClassName . '">';
											if (!empty($rankIDs[$rankID])) {
												$string .= StringUtil::encodeHTML($rankIDs[$rankID]);
											} else {
												$string .= WCF::getLanguage()->get($rank->rankTitle);
											}
											$string .= '</span></div>';
										}
									}
								}
							}
						}
						$array[$user->userID][] = $string;
					}
				}
			}
		}
		
		return ['objects' => $array, 'settings' => $settings];
	}
	
	/**
	 * Return for a list of userIDs the option value
	 *
	 * @param array $userIDs
	 *
	 * @return array
	 */
	private function getUserOptions(array $userIDs) {
		$result = [];
		$conditionBuilder = new PreparedStatementConditionBuilder();
		$conditionBuilder->add("userID IN(?)", [$userIDs]);
		$sql = "SELECT userID, userOption" . User::getUserOptionID("multirankIDs") . " as optionValue FROM wcf" . WCF_N . "_user_option_value " . $conditionBuilder;
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute($conditionBuilder->getParameters());
		while ($row = $statement->fetchArray()) {
			$tmp = @\unserialize($row["optionValue"]);
			if ($tmp === null) {
				$tmp = [];
				//database column can be null
				if($row["optionValue"] !== null) {
					//old value
					foreach (\explode("\n", $row["optionValue"]) as $item) {
						$tmp[$item] = null;
					}
				}
			}
			$result[$row["userID"]] = $tmp;
		}
		
		return $result;
	}
	
	/**
	 * Return all user ranks
	 *
	 * @return array
	 */
	public static function getRanks() {
		$ranks = new UserRankList();
		$ranks->sqlJoins = "LEFT JOIN	wcf" . WCF_N . "_user_group user_group
				ON		(user_group.groupID = user_rank.groupID)";
		$ranks->sqlOrderBy = "user_group.priority DESC, user_rank.requiredPoints DESC, user_rank.requiredGender DESC";
		$ranks->readObjects();
		
		return $ranks->getObjects();
	}
	
	/**
	 * @see    \wcf\data\ISortableAction::updatePosition()
	 */
	public function updatePosition() {
		WCF::getDB()->beginTransaction();
		foreach ($this->parameters['data']['structure'] as $parentID => $IDs) {
			$position = 1;
			foreach ($IDs as $ID) {
				$this->objects[$ID]->update([
					'parentID' => $parentID ? $this->objects[$parentID]->multirankID : null,
					'position' => $position++
				]);
			}
		}
		WCF::getDB()->commitTransaction();
	}
	
	/**
	 * @inheritdoc
	 */
	public function validateUpdatePosition() {
		// validate 'structure' parameter
		if (!isset($this->parameters['data']['structure']) || !\is_array($this->parameters['data']['structure'])) {
			throw new UserInputException('structure');
		}
		
		// validate given  ids
		foreach ($this->parameters['data']['structure'] as $parentID => $IDs) {
			if ($parentID) {
				// validate
				$multirank = new Multirank(\intval($parentID));
				if (!$multirank->multirankID ) {
					throw new UserInputException('structure');
				}
				$this->objects[$multirank->multirankID] = new $this->className($multirank);
			}
			
			foreach ($IDs as $ID) {
				// validate
				$multirank = new Multirank(\intval($ID));
				if (!$multirank->multirankID) {
					throw new UserInputException('structure');
				}
				$this->objects[$multirank->multirankID] = new $this->className($multirank);
			}
		}
		
	}
	
	
	/**
	 * @inheritdoc
	 */
	public function update() {
		// check if showOrder needs to be recalculated
		if (\count($this->objects) == 1 && isset($this->parameters['data']['parentID']) && isset($this->parameters['data']['position'])) {
			if ($this->objects[0]->parentCategoryID != $this->parameters['data']['parentID'] || $this->objects[0]->showOrder != $this->parameters['data']['position']) {
				$this->parameters['data']['position'] = $this->objects[0]->updateposition($this->parameters['data']['parentID'], $this->parameters['data']['position']);
			}
		}
		
		parent::update();
	}
}