<?php
declare(strict_types = 1);

require_once(__DIR__ . '/Admin.class.php');

/**
 * Gestion des utilisateurs.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class AdminUsers extends Admin
{
	/**
	 * Actions sur la sélection d'utilisateurs.
	 *
	 * @return void
	 */
	public static function actions(): void
	{
		if (isset($_POST['cancel']) || !isset($_POST['selection']))
		{
			return;
		}
		switch (self::_getSelectedIds($selected_ids))
		{
			case 'activate' :
				$r = User::changeStatus($selected_ids, 1);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucun utilisateur n\'a été activé.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s utilisateurs ont été activés.'), $r)
						: __('1 utilisateur a été activé.'));
				}
				break;

			case 'change_group' :
				$r = User::changeGroup($selected_ids, (int) $_POST['group_id'] ?? 0);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucun utilisateur n\'a changé de groupe.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s utilisateurs ont changés de groupe.'), $r)
						: __('1 utilisateur a changé de groupe.'));
				}
				break;

			case 'deactivate' :
				$r = User::changeStatus($selected_ids, 0);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucun utilisateur n\'a été désactivé.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s utilisateurs ont été désactivés.'), $r)
						: __('1 utilisateur a été désactivé.'));
				}
				break;

			case 'delete' :
				$r = User::delete($selected_ids);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucun utilisateur n\'a été supprimé.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s utilisateurs ont été supprimés.'), $r)
						: __('1 utilisateur a été supprimé.'));
				}
				break;

			case 'sendmail' :
				if ($selected_ids)
				{
					App::redirect('users-sendmail/' . implode(',', $selected_ids));
				}
				break;
		}
	}

	/**
	 * Création d'un nouvel utilisateur.
	 *
	 * @return bool
	 */
	public static function addUser(): bool
	{
		Template::set('field_error', '');

		self::_tplStatus();

		if (!isset($_POST['user_add']))
		{
			return TRUE;
		}

		// Paramètres.
		$params = ['group_id' => [], 'login' => [], 'password' => [], 'status' => [],];

		// Création du profil.
		$r = User::create($_POST, $params);
		if ($r === FALSE)
		{
			Report::error();
		}
		else if (is_array($r))
		{
			Report::warning($r['message']);
			Template::set('field_error', $r['param']);
		}
		else if ($r === NULL)
		{
			return TRUE;
		}
		else
		{
			Report::success(__('L\'utilisateur a été créé.'));
			return TRUE;
		}

		// Si l'opération a échouée.
		Template::set('new_user',
		[
			'login' => $_POST['login'] ?? '',
			'password' => $_POST['password'] ?? ''
		]);
		return FALSE;
	}

	/**
	 * Modification d'un profil utilisateur.
	 *
	 * @return void
	 */
	public static function changeProfile(): void
	{
		Template::set('field_error', '');

		if (!$_POST)
		{
			return;
		}

		Report::noChange();

		App::checkboxes($_POST);

		// État.
		if (array_key_exists('status', $_POST))
		{
			$r = User::changeStatus((int) $_GET['user_id'], (int) $_POST['status']);
			if ($r === -1)
			{
				Report::error();
			}
			else if ($r === 1)
			{
				Report::success();
			}
		}

		// Confirmation du mot de passe.
		if ($_POST['password_confirm'] != $_POST['password'])
		{
			Report::warning(L10N::getText('password_confirm_error'));
			Template::set('field_error', 'password_confirm');
			return;
		}

		// Paramètres.
		$params = Config::$params['users_profile_params'];
		$params['password']['required'] = 0;
		$params['group_id']['required'] = 1;
		$params['login']['required'] = 1;
		$params['status']['required'] = 0;

		$r = User::edit($_GET['user_id'], $_POST, $params);
		if ($r === FALSE)
		{
			Report::error();
		}
		else if (is_array($r))
		{
			Report::warning($r['message']);
			Template::set('field_error', $r['param']);
		}
		else if ($r === TRUE)
		{
			Report::success();

			$_POST['password_confirm'] = $_POST['password'] = '';

			// Nouveau login de l'utilisateur connecté.
			if ($_GET['user_id'] == Auth::$id
			&& (isset($_POST['login']) || isset($_POST['nickname'])))
			{
				Template::set('auth',
				[
					'nickname' => User::getNickname(
						$_POST['login'] ?? '', $_POST['nickname'] ?? NULL
					)
				]);
			}
		}
		else
		{
			$_POST['password_confirm'] = $_POST['password'] = '';
		}
	}

	/**
	 * Supprime un utilisateur.
	 *
	 * @return void
	 */
	public static function deleteUser(): void
	{
		$user_id = (int) $_GET['user_id'];

		// Permission de suppression.
		if (!User::isPermChange($user_id))
		{
			App::redirect('user/' . $user_id);
			return;
		}

		if (isset($_POST['delete']))
		{
			$r = User::delete($user_id);
			if ($r == -1)
			{
				Report::error();
			}
			else if ($r > 0)
			{
				App::redirect('users');
			}
		}
	}

	/**
	 * Modification de l'avatar.
	 *
	 * @return void
	 */
	public static function editAvatar(): void
	{
		if (!Upload::contentLength())
		{
			return;
		}

		if (isset($_POST['change']))
		{
			if ($temp_dir_path = App::getTempDirSys())
			{
				$filepath = Upload::filepath($_FILES['file'], $temp_dir_path);
				if (is_array($filepath))
				{
					Report::warning($filepath['text']);
					return;
				}

				// Vérifications du fichier.
				$r = Avatar::check($filepath);
				if ($r['code'] > 0)
				{
					Report::warning($r['message']);
					return;
				}

				if (Avatar::change($_GET['user_id'], $filepath))
				{
					$user_avatar = TRUE;
					Report::success(__('L\'avatar a été changé.'));
					goto end;
				}
			}
			Report::error();
			return;
		}

		if (isset($_POST['delete']))
		{
			if (Avatar::delete($_GET['user_id']))
			{
				$user_avatar = FALSE;
				Report::success(__('L\'avatar a été supprimé.'));
			}
		}

		end:
		// Nouvel avatar de l'utilisateur connecté.
		if (isset($user_avatar) && $_GET['user_id'] == Auth::$id)
		{
			Template::$data['auth']['avatar']['thumb']['url']
				= Avatar::getURL(Auth::$id, $user_avatar);
		}
	}

	/**
	 * Formate les informations d'un utilisateur.
	 *
	 * @param array $i
	 *   Informations brutes de l'utilisateur.
	 *
	 * @return array
	 */
	public static function getFormatedInfos(array &$i): array
	{
		static $config_users;
		if ($config_users === NULL)
		{
			$config_users = Config::$params['users'];
		}

		return
		[
			'gallery_link' => $config_users && $i['user_status'] == 1
				? App::getURLGallery('user/' . $i['user_id'])
				: NULL,

			// Permissions.
			'perm_delete' => User::isPermChange((int) $i['user_id']),

			// Utilisateur.
			'id' => $i['user_id'],
			'login' => $i['user_login'],
			'nickname' => User::getNickname($i['user_login'], (string) $i['user_nickname']),

			// Langue.
			'lang' => $i['user_lang'],

			// Avatar.
			'avatar' => $i['user_avatar'],
			'avatar_src' => Avatar::getURL(
				(int) $i['user_id'], (bool) $i['user_avatar'], FALSE
			),
			'avatar_thumb_src' => Avatar::getURL(
				(int) $i['user_id'], (bool) $i['user_avatar'], TRUE
			),

			// État.
			'activated' => $i['user_status'] == 1,
			'deactivated' => $i['user_status'] == 0,
			'pending' => $i['user_status'] == -1,
			'status' => $i['user_status'],
			'status_text' => L10N::getTextStatus((int) $i['user_status']),

			// Groupe.
			'group_id' => $i['group_id'],
			'group_name' => L10N::getTextGroupName((int) $i['group_id'], $i['group_name']),
			'admin' => $i['group_admin'],
			'superadmin' => $i['user_id'] == 1,

			// Informations personnelles.
			'birthdate' => $i['user_birthdate'],
			'description' => $i['user_description'],
			'email' => $i['user_email'],
			'firstname' => $i['user_firstname'],
			'gender' => L10N::getTextUserGender($i['user_gender']),
			'location' => $i['user_location'],
			'name' => $i['user_name'],
			'custom_1' => $i['user_custom_1'],
			'custom_2' => $i['user_custom_2'],
			'custom_3' => $i['user_custom_3'],
			'custom_4' => $i['user_custom_4'],
			'custom_5' => $i['user_custom_5'],
			'website' => $i['user_website'],

			// Statistiques.
			'albums' => L10N::formatNumber((int) $i['albums']),
			'crtdt' => L10N::dt(__('%A %d %B %Y à %H:%M:%S'), $i['user_crtdt']),
			'crtip' => $i['user_crtip'],
			'lastvstdt' => $i['user_lastvstdt']
				? L10N::dt(__('%A %d %B %Y à %H:%M:%S'), $i['user_lastvstdt'])
				: '',
			'lastvstip' => $i['user_lastvstip'],
			'comments' => L10N::formatNumber((int) $i['comments']),
			'favorites' => L10N::formatNumber((int) $i['favorites']),
			'items' => L10N::formatNumber((int) ($i['items'])),
			'votes' => L10N::formatNumber((int) $i['votes']),

			// Textes localisés.
			'text_avatar_login' => sprintf(__('Avatar de %s'), $i['user_login'])
		];
	}

	/**
	 * Récupération des langues disponibles.
	 *
	 * @return void
	 */
	public static function getLangs(): void
	{
		$params = Config::$params['lang_params'];
		$langs = [];
		foreach ($params['langs'] as $code => &$name)
		{
			$langs[] = [
				'code' => $code,
				'name' => $name,
				'selected' => ($_POST['lang'] ?? Template::$data['user']['lang']) == $code
			];
		}
		Template::set('langs', $langs);
	}

	/**
	 * Récupération des informations de l'utilisateur courant.
	 *
	 * @return void
	 */
	public static function getUser(): void
	{
		self::_tplProfile();

		$sql_stats = self::_sqlUserStats();
		$sql = "SELECT u.*, g.*,
				  $sql_stats
				  FROM {users} AS u
			 LEFT JOIN {groups} AS g USING (group_id)
				 WHERE user_id = ?
				   AND g.group_id != 2
				   AND user_status != '-2'";
		if (!DB::execute($sql, $_GET['user_id']) || !isset(($i = DB::fetchRow())['user_id']))
		{
			App::redirect('users');
			return;
		}

		// Envoi de courriel.
		Template::set('user_sendmail', ($i['user_id'] != Auth::$id) && $i['user_email']);

		// Permission de suppression.
		if (!($perm_delete = User::isPermChange((int) $i['user_id']))
		&& $_GET['section'] == 'user-delete')
		{
			App::redirect('user/' . $i['user_id']);
			return;
		}
		Template::set('user_delete', $perm_delete);

		// Données de template : infos utilisateur.
		Template::set('user', self::getFormatedInfos($i));

		// Données de template : infos de profil.
		Template::set('profile', User::getProfileEdit($i, $_POST));

		// Récupération des groupes.
		self::_getUsersGroups((int) $i['group_id']);

		// États.
		self::_tplStatus($i['user_status']);

		// Liens.
		Template::set('links',
		[
			'group' => App::getURL('group/' . $i['group_id']),
			'user' => App::getURL('user/' . $i['user_id']),
			'user_avatar' => App::getURL('user-avatar/' . $i['user_id']),
			'user_delete' => App::getURL('user-delete/' . $i['user_id']),
			'user_sendmail' => App::getURL('users-sendmail/' . $i['user_id'])
		]);
	}

	/**
	 * Récupération des informations des utilisateurs de la page courante.
	 *
	 * @return void
	 */
	public static function getUsers(): void
	{
		self::_tplProfile();

		// Nombre d'utilisateurs par page.
		$nb_per_page = Auth::$infos['user_prefs']['users']['nb_per_page'];

		// Clause WHERE.
		$where = self::_sqlWhere();
		$sql_where = $where['sql'];
		$params = $where['params'];

		// Groupe.
		if (isset($_GET['group_id']))
		{
			$sql_where .= ' AND u.group_id = :group_id';
			$params['group_id'] = $_GET['group_id'];
		}

		// Nombre d'utilisateurs.
		if (!DB::execute("SELECT COUNT(*) FROM {users} AS u WHERE $sql_where", $params))
		{
			return;
		}
		Template::set('objects_count', $nb_users = DB::fetchVal());

		// Nombre de pages.
		Template::set('nb_pages', ceil($nb_users / $nb_per_page));
		$sql_limit_start = $nb_per_page * ($_GET['page'] - 1);

		// Critère de tri.
		$column = Auth::$infos['user_prefs']['users']['order_by_column'];
		$sql_order_by = ($column == 'login' ? "LOWER(user_$column)" : "user_$column") . ' '
			. ($sql_order_by_order = Auth::$infos['user_prefs']['users']['order_by_order']);
		SQL::nicknameOrderBy($sql_nickname, $sql_order_by);

		// Récupération de la liste des groupes.
		self::_getUsersGroups();

		// Récupération des utilisateurs.
		$sql_stats = self::_sqlUserStats();
		$sql = "SELECT u.*,
					   $sql_nickname,
					   g.*,
					   $sql_stats
				  FROM {users} AS u
			 LEFT JOIN {groups} AS g USING (group_id)
				 WHERE $sql_where
			  ORDER BY $sql_order_by, user_id $sql_order_by_order
			     LIMIT $sql_limit_start,$nb_per_page";
		if (!DB::execute($sql, $params))
		{
			return;
		}
		$db_users = DB::fetchAll('user_id');
		if (!self::_objectsNoResult(count($db_users)))
		{
			return;
		}

		// Données de template.
		$users = [];
		foreach ($db_users as &$i)
		{
			$users[] = self::getFormatedInfos($i);
		}
		Template::set('users', $users);
	}

	/**
	 * Récupère une liste de tous les utilisateurs à l'exception
	 * de ceux en attente de validation par courriel.
	 *
	 * @return void
	 */
	public static function getUsersList(): void
	{
		$sql_order_by = 'LOWER(user_login) ASC';
		SQL::nicknameOrderBy($sql_nickname, $sql_order_by);

		$sql = "SELECT user_id AS id,
					   user_login,
					   user_nickname,
					   $sql_nickname
				  FROM {users}
				 WHERE user_status != '-2'
				   AND user_id != 2
			  ORDER BY $sql_order_by";
		if (DB::execute($sql))
		{
			foreach ($users = DB::fetchAll() as &$i)
			{
				$i['nickname'] = User::getNickname($i['user_login'], $i['user_nickname']);
			}
			Template::set('users', $users);
		}
	}

	/**
	 * Modification des options.
	 *
	 * @return void
	 */
	public static function options(): void
	{
		// Informations de profil.
		if ($_POST)
		{
			$_POST['config']['users_profile_params'] = Config::$params['users_profile_params'];
			foreach ($_POST['config']['users_profile_params'] as $p => &$i)
			{
				if (!isset($_POST['profile']))
				{
					break;
				}

				// Paramètres non concernés.
				if (in_array($p, ['group_id', 'login', 'password', 'status']))
				{
					continue;
				}

				// Activer ?
				if (isset($_POST['profile'][$p]['activated']) && $i['activated'] == 0)
				{
					$i['activated'] = 1;
				}
				else if (!isset($_POST['profile'][$p]['activated']) && $i['activated'] == 1)
				{
					$i['activated'] = 0;
				}

				// Obligatoire ?
				if (isset($_POST['profile'][$p]['required']) && $i['required'] == 0)
				{
					$i['required'] = 1;
				}
				else if (!isset($_POST['profile'][$p]['required']) && $i['required'] == 1)
				{
					$i['required'] = 0;
				}

				// Nom des champs personnalisés.
				if (isset($i['name']) && isset($_POST['profile'][$p]['name'])
				&& $_POST['profile'][$p]['name'] != $i['name']
				&& mb_strlen($_POST['profile'][$p]['name']) <= 64)
				{
					$i['name'] = $_POST['profile'][$p]['name'];
				}
			}
		}

		require_once(__DIR__ . '/AdminSettings.class.php');
		AdminSettings::config();

		// Informations de profil.
		self::_tplProfile();
	}

	/**
	 * Envoi d'un courriel à des membres.
	 *
	 * @return void
	 */
	public static function sendmail(): void
	{
		Template::set('field_error', '');

		// Récupération des membres.
		$sql = 'SELECT user_id,
					   user_login,
					   user_email,
					   user_nickname,
					   group_id
				  FROM {users}
				 WHERE user_status != "-2"
				   AND user_id NOT IN (2, ?)
				   AND user_email IS NOT NULL
			  ORDER BY LOWER(user_login) ASC';
		$users = DB::execute($sql, Auth::$id) ? DB::fetchAll() : [];

		// Récupération des groupes.
		$groups = [];
		if ($users)
		{
			$groups_id = array_unique(array_column($users, 'group_id'));
			$sql = 'SELECT group_id,
						   group_name
					  FROM {groups}
					 WHERE group_id > 2
					   AND group_id IN (' . DB::inInt($groups_id) . ')
				  ORDER BY LOWER(group_name) ASC';
			$groups = DB::execute($sql) ? DB::fetchAll() : [];
		}

		// Message de confirmation.
		if (substr($_GET['q'], -7) == 'confirm')
		{
			Report::success(__('Votre message a été envoyé.'));
			goto tpl;
		}

		// Envoi du formulaire.
		if (empty($_POST['name']) || empty($_POST['email'])
		 && empty($_POST['subject']) || empty($_POST['message']))
		{
			goto tpl;
		}

		// Vérifications des champs.
		foreach (Mail::FIELDS_MAXLENGTH as $name => &$maxlength)
		{
			$_POST[$name] = Utility::trimAll((string) $_POST[$name]);
			if (Utility::isEmpty($_POST[$name]))
			{
				Report::warning(L10N::getText('required_fields'));
				Template::set('field_error', $name);
				goto tpl;
			}
			if (mb_strlen($_POST[$name]) > $maxlength)
			{
				if ($name == 'message')
				{
					Report::warning(sprintf(L10N::getText('message_maxlength'), $maxlength));
					Template::set('field_error', $name);
				}
				goto tpl;
			}
		}

		// Vérification du format de l'adresse de courriel.
		if (($r = User::checkEmailFormat($_POST['email'])) !== TRUE)
		{
			Report::warning($r);
			Template::set('field_error', 'email');
			goto tpl;
		}

		// Destinataire(s).
		$sql_where = [];

		// Les groupes sélectionnés.
		if (isset($_POST['groups_select']) && isset($_POST['groups_list'])
		&& is_array($_POST['groups_list']) && !empty($_POST['groups_list']))
		{
			foreach ($_POST['groups_list'] as $k => &$id)
			{
				if (!in_array((int) $id, array_column($groups, 'group_id')))
				{
					unset($_POST['groups_list'][$k]);
				}
			}
			if ($_POST['groups_list'])
			{
				$sql_where[] = 'group_id IN (' . DB::inInt($_POST['groups_list']) . ')';
			}
		}

		// Les utilisateurs sélectionnés.
		if (isset($_POST['users_select']) && isset($_POST['users_list'])
		&& is_array($_POST['users_list']) && !empty($_POST['users_list']))
		{
			foreach ($_POST['users_list'] as $k => &$id)
			{
				if (!in_array((int) $id, array_column($users, 'user_id')))
				{
					unset($_POST['users_list'][$k]);
				}
			}
			if ($_POST['users_list'])
			{
				$sql_where[] = 'user_id IN (' . DB::inInt($_POST['users_list']) . ')';
			}
		}

		// Tous les utilisateurs activés.
		if (isset($_POST['users_activated']))
		{
			$sql_where[] = 'user_status = "1"';
		}

		// Tous les utilisateurs désactivés.
		if (isset($_POST['users_deactivated']))
		{
			$sql_where[] = 'user_status = "0"';
		}

		// Tous les utilisateurs en attente de validation.
		if (isset($_POST['users_pending']))
		{
			$sql_where[] = 'user_status = "-1"';
		}

		// Tous les utilisateurs.
		if (isset($_POST['users_all']))
		{
			$sql_where = ['1=1'];
		}

		// On récupère l'adresse de courriel des utilisateurs sélectionnés.
		$emails = [];
		if ($sql_where)
		{
			$sql = 'SELECT user_email
					  FROM {users}
					 WHERE user_status != "-2"
					   AND user_id NOT IN (2, ?)
					   AND user_email IS NOT NULL
					   AND (' . implode(' OR ', $sql_where) . ')';
			if (!DB::execute($sql, Auth::$id))
			{
				Report::error();
				goto tpl;
			}
			$emails = array_values(DB::fetchAll('user_email', 'user_email'));
		}
		if (!$emails)
		{
			Report::warning(__('Aucun utilisateur n\'a été sélectionné.'));
			goto tpl;
		}

		// Envoi du courriel.
		$bcc = count($emails) > 1 ? implode(', ', $emails) : '';
		$to = count($emails) > 1 ? '' : implode(', ', $emails);
		$mail = new Mail();
		$mail->messages[] =
		[
			'to' => $to,
			'bcc' => $bcc,
			'name' => $_POST['name'],
			'from' => $_POST['email'],
			'subject' => $_POST['subject'],
			'message' => $_POST['message']
		];
		if (!$mail->send())
		{
			Report::error();
			goto tpl;
		}

		// Confirmation de l'envoi du message.
		App::redirect('users-sendmail/confirm');

		// Template.
		tpl:

		// Identifiant des utilisateurs (si fourni).
		$users_id = explode(',', (string) (empty($_POST)
			? ($_GET['users_id'] ?? $_GET['users_ids'] ?? 0)
			: 0));
		$user_id_valid = 0;

		// Liste des membres.
		$users_tpl = [];
		foreach ($users as &$i)
		{
			if (in_array($i['user_id'], $users_id))
			{
				$user_id_valid = 1;
			}
			$users_tpl[] =
			[
				'email' => $i['user_email'],
				'id' => (int) $i['user_id'],
				'name' => User::getNickname(
					$i['user_login'], (string) $i['user_nickname']
				),
				'selected' => (int) ((isset($_POST['users_list'])
					&& in_array($i['user_id'], $_POST['users_list']))
					|| (in_array($i['user_id'], $users_id)))
			];
		}

		// Liste des groupes.
		$groups_tpl = [];
		foreach ($groups as &$i)
		{
			$groups_tpl[] =
			[
				'id' => (int) $i['group_id'],
				'name' => L10N::getTextGroupName(
					(int) $i['group_id'], $i['group_name']
				),
				'selected' => (int) (isset($_POST['groups_list'])
					&& in_array($i['group_id'], $_POST['groups_list']))
			];
		}

		// Informations de template.
		Template::set('sendmail',
		[
			'email' => $_POST['email'] ?? Auth::$infos['user_email'],
			'form_action' => App::getURL(str_replace('/confirm', '', $_GET['q_pageless'] ?? '')),
			'groups_list' => $groups_tpl,
			'groups_select' => $_POST['groups_select'] ?? 0,
			'maxlength' => Mail::FIELDS_MAXLENGTH,
			'message' => $_POST['message'] ?? '',
			'name' => $_POST['name'] ?? User::getNickname(
				Auth::$infos['user_login'],
				(string) Auth::$infos['user_nickname']
			),
			'subject' => $_POST['subject'] ?? '',
			'users_activated' => $_POST['users_activated'] ??  0,
			'users_all' => $_POST['users_all'] ?? 0,
			'users_deactivated' => $_POST['users_deactivated'] ?? 0,
			'users_list' => $users_tpl,
			'users_pending' => $_POST['users_pending'] ?? 0,
			'users_select' => $user_id_valid || ($_POST['users_select'] ?? 0)
		]);
	}

	/**
	 * Informations de template pour le moteur de recherche.
	 *
	 * @param array $functions
	 *
	 * @return void
	 */
	public static function tplSearch(array &$functions): void
	{
		// Colonnes.
		$columns = $functions['columns'](
		[
			'user_crtip' => FALSE,
			'user_lastvstip' => FALSE,
			'user_login' => TRUE,
			'user_email' => FALSE,
			'user_website' => FALSE
		]);

		// État.
		$status = $functions['select']('status', [
			[
				'value' => '*',
				'text' => '*' . __('Tous')
			],
			[
				'value' => '1',
				'text' => __('Activé')
			],
			[
				'value' => '0',
				'text' => __('Désactivé')
			],
			[
				'value' => '-1',
				'text' => __('En attente')
			]
		]);

		Template::set('search', $functions['date']());
		Template::set('search', [
			'date' => self::$search->options['date'] ?? FALSE,
			'date_column' => self::$search->options['date_column'] ?? 'user_crtdt',
			'columns' => $columns,
			'status' => $status
		]);
	}

	/**
	 * Définit les paramètres de template pour la section.
	 *
	 * @param string $tpl_filename
	 *
	 * @return void
	 */
	public static function tplSection(string $tpl_filename): void
	{
		Template::set('page',
		[
			'link' => App::getURL('users'),
			'title' => __('Utilisateurs')
		]);
		Template::set('section', 'users');
		Template::set('template',
		[
			'content' => $tpl_filename . '.tpl.php',
			'file' => 'user.tpl.php'
		]);
	}



	/**
	 * Récupération des groupes pour la gestion des utilisateurs.
	 *
	 * @param int $group_id
	 *   Identifiant du groupe de l'utilisateur.
	 *
	 * @return void
	 */
	private static function _getUsersGroups(int $group_id = 0): void
	{
		// Récupération des groupes.
		$where = self::_sqlWhere();
		$sql = "SELECT group_id AS id,
					   group_name AS name,
					   group_admin AS admin,
					   (SELECT COUNT(*)
						  FROM {users} AS u,
							  {groups} AS g2
						 WHERE {$where['sql']}
						   AND g2.group_id = u.group_id
						   AND g2.group_id = g.group_id) AS nb_users
				  FROM {groups} AS g
				 WHERE group_id != 2
			  ORDER BY group_id ASC";
		if (!DB::execute($sql, $where['params']))
		{
			return;
		}
		$groups = DB::fetchAll('id');
		Template::set('users_count', array_sum(array_column($groups, 'nb_users')));

		// Fil d'Ariane.
		$breadcrumb =
		[
			[
				'current' => TRUE,
				'name' => isset($_GET['group_id'])
					? L10N::getTextGroupName((int) $_GET['group_id'],
						$groups[$_GET['group_id']]['name'] ?? '')
					: __('Tous'),
				'url' => App::getURL($_GET['q_pageless'])
			]
		];
		Template::set('breadcrumb', $breadcrumb);

		// Lien vers tous les groupes.
		$link = 'users';
		if (strstr($_GET['q'], '/pending'))
		{
			$link .= '/pending';
		}
		if (isset($_GET['search']))
		{
			$link .= '/search/' . $_GET['search'];
		}
		Template::set('all_groups_link', App::getURL($link));

		// Informations de template.
		$groups = array_values($groups);
		foreach ($groups as &$i)
		{
			$i['current'] = (isset($_POST['group']) && $i['id'] == $_POST['group'])
				|| ($group_id && $i['id'] == $group_id);
			$i['name'] = L10N::getTextGroupName((int) $i['id'], $i['name']);
			$link = 'users/group/' . $i['id'];
			if (strstr($_GET['q'], '/pending'))
			{
				$link .= '/pending';
			}
			if (isset($_GET['search']))
			{
				$link .= '/search/' . $_GET['search'];
			}
			$i['link'] = App::getURL($link);
		}
		Template::set('groups', $groups);
	}

	/**
	 * Retourne la partie SELECT de la requête SQL servant
	 * à récupérer les statistiques d'un utilisateur.
	 *
	 * @return string
	 */
	private static function _sqlUserStats(): string
	{
		$image_types = DB::inInt(Item::IMAGE_TYPES);
		$video_types = DB::inInt(Item::VIDEO_TYPES);
		$sql =
		[
			// Nombre de commentaires.
			  '(SELECT COUNT(*)
				  FROM {comments} AS com
			 LEFT JOIN {items} AS i USING (item_id)
				 WHERE com.user_id = u.user_id) AS comments',

			// Nombre de favoris.
			  '(SELECT COUNT(*)
				  FROM {favorites} AS f
			 LEFT JOIN {items} USING (item_id)
				 WHERE f.user_id = u.user_id) AS favorites',

			// Nombre d'albums.
			  '(SELECT COUNT(*)
				  FROM {categories} AS cat
				 WHERE cat.user_id = u.user_id
				   AND cat_id > 1
				   AND cat_filemtime IS NOT NULL) AS albums',

			// Nombre de fichiers.
			  '(SELECT COUNT(*)
				  FROM {items} AS i
				 WHERE i.user_id = u.user_id) AS items',

			// Nombre de votes.
			  '(SELECT COUNT(*)
				  FROM {votes} as v
			 LEFT JOIN {items} AS i USING (item_id)
				 WHERE v.user_id = u.user_id) AS votes'
		];

		return implode(",\n", $sql);
	}

	/**
	 * Retourne la clause WHERE pour la récupération des utilisateurs.
	 *
	 * @return array
	 */
	private static function _sqlWhere(): array
	{
		// On ne récupère pas les utilisateurs et groupe "invités".
		$params = [];
		$sql = 'u.user_id != 2 AND u.group_id != 2';

		// Moteur de recherche.
		if (isset($_GET['search']))
		{
			$search = self::$search->sql();
			$sql .= ' AND ' . $search['sql'];
			$params = $search['params'];
		}

		// En attente.
		$sql .= strstr($_GET['q'], '/pending')
			? ' AND user_status = "-1"'
			: ' AND user_status != "-2"';

		return ['sql' => $sql, 'params' => $params];
	}

	/**
	 * Données de template pour les paramètres de profile.
	 *
	 * @return void
	 */
	private static function _tplProfile(): void
	{
		// Informations de profil.
		$params = User::getProfileParams();
		$activated = FALSE;
		foreach ($params as $field => &$p)
		{
			if ($_GET['section'] == 'users-options' && $_POST)
			{
				$p['activated'] = (int) isset($_POST['profile'][$field]['activated']);
				$p['required'] = (int) isset($_POST['profile'][$field]['required']);
			}
			else if ($p['activated'])
			{
				$p['activated'] = 1;
				$p['required'] = (int) $p['required'];
				if (!in_array($field, ['group_id', 'login', 'password', 'status']))
				{
					$activated = TRUE;
				}
			}
			else
			{
				$p['activated'] = 0;
				$p['required'] = 0;
			}
		}
		Template::set('profile_activated', $activated);
		Template::set('profile_params', $params);
		Template::set('profile_custom',
		[
			'1' => ($_GET['section'] == 'users-options' && $_POST)
				? $_POST['profile']['custom_1']['name']
				: Config::$params['users_profile_params']['custom_1']['name'],
			'2' => ($_GET['section'] == 'users-options' && $_POST)
				? $_POST['profile']['custom_2']['name']
				: Config::$params['users_profile_params']['custom_2']['name'],
			'3' => ($_GET['section'] == 'users-options' && $_POST)
				? $_POST['profile']['custom_3']['name']
				: Config::$params['users_profile_params']['custom_3']['name'],
			'4' => ($_GET['section'] == 'users-options' && $_POST)
				? $_POST['profile']['custom_4']['name']
				: Config::$params['users_profile_params']['custom_4']['name'],
			'5' => ($_GET['section'] == 'users-options' && $_POST)
				? $_POST['profile']['custom_5']['name']
				: Config::$params['users_profile_params']['custom_5']['name']
		]);
	}

	/**
	 * Données de template pour l'état de l'utilisateur.
	 *
	 * @param string $status
	 *
	 * @return void
	 */
	private static function _tplStatus(?string $status = NULL): void
	{
		if (isset($_POST['status']))
		{
			$current_pending = $_POST['status'] == '-1';
			$current_deactive = $_POST['status'] == '0';
			$current_active = $_POST['status'] == '1';
		}
		else if ($status !== NULL)
		{
			$current_pending = $status == '-1';
			$current_deactive = $status == '0';
			$current_active = $status == '1';
		}
		Template::set('user_status',
		[
			[
				'value' => '1',
				'text' => L10N::getTextStatus(1),
				'current' => $current_active ?? FALSE
			],
			[
				'value' => '0',
				'text' => L10N::getTextStatus(0),
				'current' => $current_deactive ?? FALSE
			],
			[
				'value' => '-1',
				'text' => L10N::getTextStatus(-1),
				'current' => $current_pending ?? FALSE
			]
		]);
	}
}
?>