<?php
declare(strict_types = 1);

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

/**
 * Gestion des commentaires.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class GalleryComments extends Gallery
{
	/**
	 * Ajoute un commentaire.
	 *
	 * @return void
	 */
	public static function addComment(): void
	{
		Template::set('comments_add', 0);
		Template::set('comments_add_deactivated',
			Config::$params['comments_read_only'] || !GalleryItems::$infos['commentable']);
		self::_setCommentForm();

		// Commentaires en lecture seule ?
		if (Config::$params['comments_read_only'])
		{
			return;
		}

		// Permission de groupe.
		if (Template::$data['users']
		&& (!Auth::$groupPerms['comments_add'] || !Auth::$groupPerms['comments_read']))
		{
			return;
		}

		// Permission du fichier et de ses catégories parentes.
		if (!GalleryItems::$infos['commentable'])
		{
			return;
		}

		// Paramètres de formulaire.
		$remember = empty($_POST)
			? (bool) Auth::$prefs->read('comment_remember')
			: isset($_POST['remember']);
		Template::set('comments_add', 1);
		Template::set('comments_form', [
			'author' => isset($_POST['author'])
				? Utility::trimAll($_POST['author'])
				: Auth::$prefs->read('author'),
			'email' => isset($_POST['email'])
				? Utility::trimAll($_POST['email'])
				: Auth::$prefs->read('email'),
			'field_error' => '',
			'message' => isset($_POST['message']) ? Utility::trimAll($_POST['message']) : '',
			'moderate' => Config::$params['comments_moderate']
				|| (Template::$data['users'] && !Auth::$groupPerms['comments_add_mode']),
			'preview' => FALSE,
			'remember' => $remember,
			'website' => isset($_POST['website'])
				? Utility::trimAll($_POST['website'])
				: Auth::$prefs->read('website')
		]);

		// Si pas de message, on arrête là.
		if (!isset($_POST['message']))
		{
			return;
		}

		// Vérification par un faux champ de formulaire.
		if (!isset($_POST['f_email']) || $_POST['f_email'] !== '')
		{
			Report::warning('Bot detected.');
			return;
		}

		// Anti-double post (partie 1).
		$time = time();
		$comment_hash = md5($_GET['item_id'] . '|' . $_POST['message']);
		$comment_hash = md5(implode('|',
			[$_GET['item_id'], $_POST['message'], date('Y-m-d H', $time)]));
		$comment_hash_2 = md5(implode('|',
			[$_GET['item_id'], $_POST['message'], date('Y-m-d H', $time - 3600)]));
		if ($comment_hash == Auth::$prefs->read('comment_hash')
		 || $comment_hash_2 == Auth::$prefs->read('comment_hash'))
		{
			Report::warning(__('Double-post détecté : votre message n\'a pas été publié.'));
			return;
		}

		// Suppression des émojis ?
		if (Config::$params['comments_emoji_delete'])
		{
			$_POST['message'] = preg_replace('`' . Emoji::REGEXP . '`u', '', $_POST['message']);
		}

		// Commentaire à modérer ?
		$moderate = !isset($_POST['preview']) && (Config::$params['comments_moderate']
			|| (Template::$data['users'] && !Auth::$groupPerms['comments_add_mode']));

		// Auteur.
		$author = Auth::$id == 2 ? ($_POST['author'] ?? '') : Auth::$nickname;

		// Enregistrement du commentaire.
		$r = Comment::add((int) $_GET['item_id'], Auth::$id, $moderate,
			isset($_POST['preview']), $_POST['message'] ?? '',
			$author, $_POST['email'] ?? '', $_POST['website'] ?? ''
		);

		// Erreur.
		if ($r === FALSE)
		{
			Report::error();
		}

		// Commentaire rejeté.
		else if (is_array($r))
		{
			Report::warning($r['message']);
			Template::set('comments_form', ['field_error' => $r['field'] ?? '']);
		}

		// Commentaire accepté.
		else if ($r === TRUE)
		{
			if (isset($_POST['preview']))
			{
				Template::set('comments_form', ['preview' =>
				[
					'com_id' => 0,
					'com_crtdt' => date('Y-m-d H:i:s'),
					'com_author' => Auth::$infos['user_login']
						?? Utility::trimAll($_POST['author'] ?? ''),
					'com_email' => Auth::$infos['user_email']
						?? Utility::trimAll($_POST['email'] ?? ''),
					'com_website' => Auth::$infos['user_website']
						?? Utility::trimAll($_POST['website'] ?? ''),
					'com_message' => $_POST['message'],
					'user_id' => Auth::$id,
					'user_avatar' => Auth::$infos['user_avatar'] ?? 0,
					'user_login' => Auth::$infos['user_login'] ?? '',
					'user_nickname' => Auth::$infos['user_nickname'] ?? '',
					'user_status' => Auth::$infos['user_status'] ?? 1
				]]);
			}
			else
			{
				// Champs de formulaire.
				Template::set('comments_form',
				[
					'author' => $remember ? ($_POST['author'] ?? '') : '',
					'email' => $remember ? ($_POST['email'] ?? '') : '',
					'message' => '',
					'website' => $remember ? ($_POST['website'] ?? '') : ''
				]);

				// Message de validation.
				if ($moderate)
				{
					Report::success(__('Votre commentaire a été enregistré et'
						. ' sera publié après validation par un administrateur.'));
				}
				else
				{
					Report::success(__('Votre commentaire a été publié.'));
				}

				// Anti-double post (partie 2).
				Auth::$prefs->add('comment_hash', $comment_hash);

				// Gestion de l'option "Se souvenir de moi ?".
				if ($remember)
				{
					Auth::$prefs->add('comment_remember', '1');
					Auth::$prefs->add('author', Template::$data['comments_form']['author']);
					Auth::$prefs->add('email', Template::$data['comments_form']['email']);
					Auth::$prefs->add('website', Template::$data['comments_form']['website']);
				}
				else
				{
					Auth::$prefs->delete('comment_remember');
					Auth::$prefs->delete('author');
					Auth::$prefs->delete('email');
					Auth::$prefs->delete('website');
				}

				// Notification d'ajout.
				$item_id = (int) GalleryItems::$infos['item_id'];
				$item_name = GalleryItems::$infos['item_name'];
				$user_name = Auth::$id == 2 ? $_POST['author'] : Auth::$nickname;
				$mail = new Mail();
				$mail->notify($moderate ? 'comment-pending' : 'comment', [], Auth::$id,
				[
					'item_id' => $item_id,
					'item_name' => $item_name,
					'user_name' => $user_name
				]);
				$mail->send();

				// Notification de suivi.
				if (!$moderate && Config::$params['users'])
				{
					$album = [GalleryItems::$infos['cat_path']];
					$mail = new Mail();
					$mail->notify('comment-follow', $album, Auth::$id,
					[
						'item_id' => $item_id,
						'item_name' => $item_name,
						'user_name' => $user_name
					]);
					$mail->send();
				}
			}

			// Nombre de commentaires.
			$comments_count = Template::$data['item']['stats']['comments']['value'] + 1;
			Template::set('item',
			[
				'stats' =>
				[
					'comments' =>
					[
						'formated' => sprintf(
							$comments_count > 1
								? __('%s commentaires')
								: __('%s commentaire'),
							L10N::formatNumber((int) $comments_count)
						),
						'short' => L10N::formatShortNumber((int) $comments_count),
						'value' => $comments_count
					]
				]
			]);
		}
	}

	/**
	 * Récupération des commentaires d'une catégorie.
	 *
	 * @return int
	 */
	public static function getCommentsCategory(): int
	{
		Template::set('comments_count', $comments_count = 0);
		Template::set('comments_messages', []);
		self::_setCommentForm();
		$breadcrumb =
		[
			'category_link' => App::getURL(),
			'category_name' => __('la galerie'),
			'category_text' => '%s',
			'text' => __('Commentaires de %s')
		];

		// Clause WHERE.
		$params = [];
		$sql_where = 'com_status = "1"
		   AND cat_status = "1"
		   AND item_status = "1"';

		// Catégorie.
		$cat_id = $_GET['album_id'] ?? $_GET['category_id'];
		if ($cat_id > 1)
		{
			$sql = 'SELECT cat_url,
						   cat_name,
						   cat_path,
						   CASE WHEN cat_filemtime IS NULL
								THEN "category" ELSE "album"
								 END AS type
					  FROM {categories}
					 WHERE cat_id = ?';
			if (!DB::execute($sql, $cat_id))
			{
				return -1;
			}
			if (!$cat_infos = DB::fetchRow())
			{
				return 0;
			}
			$params['path'] = DB::likeEscape($cat_infos['cat_path']) . '/%';
			$sql_where .= ' AND item_path LIKE :path';
			$breadcrumb['category_link'] = App::getURL(
				$cat_infos['type'] . '/' . $cat_id . '-' . $cat_infos['cat_url']
			);
			$breadcrumb['category_name'] = $cat_infos['cat_name'];
			$breadcrumb['category_text'] = $cat_infos['type'] == 'category'
				? __('la catégorie %s')
				: __('l\'album %s');
		}

		// Utilisateur.
		if (isset($_GET['user_id']))
		{
			$sql = 'SELECT user_login,
						   user_nickname
					  FROM {users}
					 WHERE user_id = ?
					   AND user_id != 2';
			if (!DB::execute($sql, $_GET['user_id']))
			{
				return -1;
			}
			if (!$user_infos = DB::fetchRow())
			{
				return 0;
			}
			$params['user_id'] = $_GET['user_id'];
			$sql_where .= ' AND u.user_id = :user_id';
			$breadcrumb['text'] = $cat_id > 1
				? __('Commentaires de %s dans %s')
				: __('Commentaires de %s');
			$breadcrumb['user_link'] = App::getURL('user/' . $_GET['user_id']);
			$breadcrumb['user_name'] = User::getNickname(
				$user_infos['user_login'], $user_infos['user_nickname']
			);
		}

		// Fil d'Ariane.
		Template::set('breadcrumb', $breadcrumb);

		// Clause LIMIT.
		$nb_per_page = (int) Config::$params['pages_params']['comments']['nb_per_page'];
		$start = $nb_per_page * ($_GET['page'] - 1);

		// Récupération des commentaires.
		if (Config::$params['users'] && !Auth::$groupPerms['comments_read'])
		{
			$comments = [];
		}
		else
		{
			$sql = "SELECT com_id,
						   com_crtdt,
						   com_author,
						   com_email,
						   com_website,
						   com_message,
						   u.user_id,
						   user_avatar,
						   user_login,
						   user_nickname,
						   user_status,
						   i.item_id,
						   item_adddt,
						   item_type,
						   item_name,
						   item_path,
						   item_url,
						   item_duration,
						   item_orientation
					  FROM {comments} AS com
				 LEFT JOIN {users} AS u USING (user_id)
				 LEFT JOIN {items} AS i USING (item_id)
				 LEFT JOIN {categories} AS cat USING (cat_id)
					 WHERE $sql_where
					   AND " . SQL::catPerms() . "
					   AND " . SQL::catPassword() . "
				  ORDER BY com_crtdt DESC
					 LIMIT $start,$nb_per_page";
			DB::params($params);
			if (!DB::execute($sql))
			{
				return -1;
			}
			$comments = DB::fetchAll();
			if (!$comments && $_GET['page'] > 1)
			{
				App::redirect($_GET['q_pageless']);
			}
		}

		// Nombre de commentaires.
		if ($comments)
		{
			$sql = "SELECT COUNT(*)
					  FROM {comments} AS com
				 LEFT JOIN {users} AS u USING (user_id)
				 LEFT JOIN {items} AS i USING (item_id)
				 LEFT JOIN {categories} AS cat USING (cat_id)
					 WHERE $sql_where
					   AND " . SQL::catPerms() . "
					   AND " . SQL::catPassword();
			DB::params($params);
			if (!DB::execute($sql))
			{
				return -1;
			}
			$comments_count = DB::fetchVal();
			Template::set('comments_count', $comments_count);
		}

		// Formatage des données.
		$comments_formated = self::_getFormatedInfos($comments);
		$num = 0;
		$pages_count = $_GET['page'] > 1 ? ($_GET['page'] - 1) * $nb_per_page : 0;
		foreach ($comments_formated as &$i)
		{
			$i['num'] = $comments_count - $num - $pages_count;
			$num++;
		}
		Template::set('comments_messages', $comments_formated);

		// Pagination.
		$pages_count = ceil($comments_count / $nb_per_page);
		self::_pagination($pages_count);

		return 1;
	}

	/**
	 * Récupération des commentaires postés sur une photo ou une vidéo.
	 *
	 * @return void
	 */
	public static function getCommentsItem(): void
	{
		Template::set('comments_messages', []);

		// Permission de groupe.
		if (Config::$params['users'] && !Auth::$groupPerms['comments_read'])
		{
			return;
		}

		// Clause ORDER BY.
		$sql_order_by = Config::$params['comments_order_by'];
		$sql_order_by = in_array($sql_order_by, ['ASC', 'DESC']) ? $sql_order_by : 'ASC';

		// Récupération des commentaires.
		$sql = "SELECT com_id,
					   com_crtdt,
					   com_author,
					   com_email,
					   com_website,
					   com_message,
					   u.user_id,
					   u.user_avatar,
					   u.user_login,
					   u.user_nickname,
					   u.user_status
				  FROM {comments} AS com
			 LEFT JOIN {users} AS u USING (user_id)
				 WHERE com_status = '1'
				   AND item_id = ?
			  ORDER BY com_crtdt $sql_order_by";
		if (!DB::execute($sql, (int) $_GET['item_id']))
		{
			return;
		}
		$comments = DB::fetchAll();
		$comments_count = count($comments);

		// Prévisualisation.
		if ($preview = Template::$data['comments_form']['preview'] ?? [])
		{
			$comments_count++;
			if ($sql_order_by == 'ASC')
			{
				$comments[] = $preview;
			}
			else
			{
				array_unshift($comments, $preview);
			}
		}

		// Formatage des données.
		$comments_formated = self::_getFormatedInfos($comments);
		$n = $sql_order_by == 'ASC' ? 1 : $comments_count;
		foreach ($comments_formated as &$i)
		{
			$num = $sql_order_by == 'ASC' ? $n++ : $n--;
			$i['num'] = $num;
			$i['preview'] = $preview && $num == $comments_count;
		}
		Template::set('comments_messages', $comments_formated);
	}



	/**
	 * Formate les informations de plusieurs commentaires.
	 *
	 * @param array $comments
	 *   Informations brutes des commentaires.
	 *
	 * @return array
	 */
	private static function _getFormatedInfos(array &$comments): array
	{
		$n = 0;
		$comments_edit = [];
		$comments_formated = [];

		foreach ($comments as &$i)
		{
			// Commentaire.
			$comments_formated[$n] =
			[
				'date' => L10N::dt(__('%A %d %B %Y à %H\h%M'), $i['com_crtdt']),
				'date_short' => L10N::dt(__('%d/%m/%Y, %H:%M'), $i['com_crtdt']),
				'id' => $i['com_id'],
				'message' => $i['com_message']
			];

			// Utilisateur.
			$user_edit = Auth::$isAdmin || (Config::$params['users']
				&& Auth::$id != 2 && Auth::$id == $i['user_id']);
			$user_email = $i['user_id'] == 2 ? $i['com_email'] : NULL;
			$user_name = $i['user_id'] == 2
				? ($i['com_author'] === '' ? 'Guest' : $i['com_author'])
				: User::getNickname($i['user_login'], $i['user_nickname']);
			$user_website = $i['user_id'] == 2 ? $i['com_website'] : NULL;
			$comments_formated[$n]['user'] =
			[
				'avatar' => Avatar::getURL((int) $i['user_id'], (bool) $i['user_avatar']),
				'edit' => $user_edit,
				'email' => $user_email,
				'id' => $i['user_id'],
				'link' => $i['user_id'] == 2 || $i['user_status'] != 1
					|| empty(Auth::$groupPerms['members_profile'])
					? NULL
					: App::getURL('user/' . $i['user_id']),
				'name' => $user_name,
				'website' => $user_website
			];

			// Édition.
			if ($user_edit)
			{
				$params =
				[
					'message' => $i['com_message']
				];
				if ($i['user_id'] == 2)
				{
					$params = array_merge($params,
					[
						'user_email' => $user_email,
						'user_name' => $user_name,
						'user_website' => $user_website
					]);
				}
				$comments_edit[$i['com_id']] = $params;
			}

			// Fichier.
			if (isset($i['item_path']))
			{
				$item_link = App::getURL('item/' . $i['item_id'] . '-' . $i['item_url']);
				$comments_formated[$n]['item'] =
				[
					'is_video' => Item::isVideo($i['item_type']),
					'duration' => $i['item_duration'],
					'duration_text' => $i['item_duration']
						? App::formatDuration($i['item_duration'])
						: '00:00',
					'link' => $item_link,
					'link_comment' => $item_link . '#comment-' . $i['com_id'],
					'title' => $i['item_name'],
					'thumb_src' =>
						function($size = '', $quality = '') use ($i)
						{
							return App::getThumbSource(
								'item', $i, (string) $size, (string) $quality
							);
						}
				];
			}

			$n++;
		}

		Template::set('comments_edit', $comments_edit);
		return $comments_formated;
	}

	/**
	 * Formate les informations de plusieurs commentaires.
	 *
	 * @param array $params
	 *
	 * @return void
	 */
	private static function _setCommentForm(array $params = []): void
	{
		$comments_maxchars = (int) Config::$params['comments_maxchars'];
		$params = array_merge($params,
		[
			'author_maxlength' => Comment::COLUMNS_LENGTH_MAX['author'],
			'email_maxlength' => Comment::COLUMNS_LENGTH_MAX['email'],
			'email_required' => (bool) Config::$params['comments_required_email'],
			'message_maxlength' => $comments_maxchars > Comment::COLUMNS_LENGTH_MAX['message']
				? Comment::COLUMNS_LENGTH_MAX['message']
				: $comments_maxchars,
			'website_maxlength' => Comment::COLUMNS_LENGTH_MAX['website'],
			'website_required' => (bool) Config::$params['comments_required_website']
		]);
		Template::set('comments_form', $params);
	}
}
?>