<?php
declare( strict_types = 1 );

namespace MediaWiki\Extension\Translate\TranslatorSandbox;

use FormatJson;
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Html\Html;
use MediaWiki\Parser\Sanitizer;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\User\Options\UserOptionsLookup;
use MediaWiki\User\User;
use MediaWiki\Utils\MWTimestamp;

/**
 * Special page for managing sandboxed users.
 *
 * @author Niklas Laxström
 * @author Amir E. Aharoni
 * @license GPL-2.0-or-later
 * @ingroup SpecialPage TranslateSpecialPage
 */
class ManageTranslatorSandboxSpecialPage extends SpecialPage {
	/** @var TranslationStashReader */
	private $stash;
	/** @var UserOptionsLookup */
	private $userOptionsLookup;
	private TranslateSandbox $translateSandbox;

	public const CONSTRUCTOR_OPTIONS = [
		'TranslateUseSandbox',
	];

	public function __construct(
		TranslationStashReader $stash,
		UserOptionsLookup $userOptionsLookup,
		TranslateSandbox $translateSandbox,
		ServiceOptions $options
	) {
		$this->stash = $stash;
		$this->userOptionsLookup = $userOptionsLookup;
		$this->translateSandbox = $translateSandbox;

		parent::__construct(
			'ManageTranslatorSandbox',
			'translate-sandboxmanage',
			$options->get( 'TranslateUseSandbox' )
		);
	}

	public function doesWrites() {
		return true;
	}

	protected function getGroupName() {
		return 'translation';
	}

	public function execute( $params ) {
		$this->setHeaders();
		$this->checkPermissions();
		$out = $this->getOutput();
		$out->addModuleStyles(
			[
				'ext.translate.special.managetranslatorsandbox.styles',
				'mediawiki.ui.button',
				'jquery.uls.grid',
			]
		);
		$out->addModules( 'ext.translate.special.managetranslatorsandbox' );

		$this->showPage();
	}

	/** Generates the whole page html and appends it to output */
	private function showPage(): void {
		$out = $this->getOutput();

		$nojs = Html::errorBox(
			$this->msg( 'tux-nojs' )->escaped(),
			'',
			'tux-nojs'
		);
		$out->addHTML( $nojs );

		$out->addHTML(
			<<<HTML
				<div class="grid tsb-container">
					<div class="row">
						<div class="nine columns pane filter">{$this->makeFilter()}</div>
						<div class="three columns pane search">{$this->makeSearchBox()}</div>
					</div>
					<div class="row tsb-body">
						<div class="four columns pane requests">
							{$this->makeList()}
							<div class="request-footer">
								<span class="selected-counter">
									{$this->msg( 'tsb-selected-count' )->numParams( 0 )->escaped()}
								</span>
								\u{00A0}
								<a href="#" class="older-requests-indicator"></a>
							</div>
						</div>
						<div class="eight columns pane details"></div>
					</div>
				</div>
				HTML
		);
	}

	private function makeFilter(): string {
		return $this->msg( 'tsb-filter-pending' )->escaped();
	}

	private function makeSearchBox(): string {
		return <<<HTML
			<input class="request-filter-box right"
				placeholder="{$this->msg( 'tsb-search-requests' )->escaped()}" type="search" />
			HTML;
	}

	private function makeList(): string {
		$items = [];
		$requests = [];
		$users = $this->translateSandbox->getUsers();

		/** @var User $user */
		foreach ( $users as $user ) {
			$reminders = $this->userOptionsLookup->getOption( $user, 'translate-sandbox-reminders' );
			$reminders = $reminders ? explode( '|', $reminders ) : [];
			$remindersCount = count( $reminders );
			if ( $remindersCount ) {
				$lastReminderTimestamp = new MWTimestamp( end( $reminders ) );
				$lastReminderAgo = htmlspecialchars(
					$this->getHumanTimestamp( $lastReminderTimestamp )
				);
			} else {
				$lastReminderAgo = '';
			}

			$requests[] = [
				'username' => $user->getName(),
				'email' => $user->getEmail(),
				'gender' => $this->userOptionsLookup->getOption( $user, 'gender' ),
				'registrationdate' => $user->getRegistration(),
				'translations' => count( $this->stash->getTranslations( $user ) ),
				'languagepreferences' => FormatJson::decode(
					$this->userOptionsLookup->getOption( $user, 'translate-sandbox' )
				),
				'userid' => $user->getId(),
				'reminderscount' => $remindersCount,
				'lastreminder' => $lastReminderAgo,
			];
		}

		// Sort the requests based on translations and registration date
		usort( $requests, [ $this, 'translatorRequestSort' ] );

		foreach ( $requests as $request ) {
			$items[] = $this->makeRequestItem( $request );
		}

		$requestsList = implode( "\n", $items );

		return <<<HTML
			<div class="row request-header">
				<div class="four columns">
					<button class="language-selector unselected">
						{$this->msg( 'tsb-all-languages-button-label' )->escaped()}
					</button>
				</div>
				<div class="five columns request-count"></div>
				<div class="three columns text-center">
					<input class="request-selector-all" name="request" type="checkbox" />
				</div>
			</div>
			<div class="requests-list">
				{$requestsList}
			</div>
			HTML;
	}

	private function makeRequestItem( array $request ): string {
		$requestdataEnc = htmlspecialchars( FormatJson::encode( $request ) );
		$nameEnc = htmlspecialchars( $request['username'] );
		$nameEncForId =
			htmlspecialchars(
				Sanitizer::escapeIdForAttribute( 'tsb-request-' . $request['username'] )
			);
		$emailEnc = htmlspecialchars( $request['email'] );
		$countEnc = htmlspecialchars( (string)$request['translations'] );
		$timestamp = new MWTimestamp( $request['registrationdate'] );
		$agoEnc = htmlspecialchars( $this->getHumanTimestamp( $timestamp ) );

		return <<<HTML
			<div class="row request" data-data="$requestdataEnc" id="$nameEncForId">
				<div class="two columns amount">
					<div class="translation-count">$countEnc</div>
				</div>
				<div class="seven columns request-info">
					<div class="row username">$nameEnc</div>
					<div class="row email" dir="ltr">$emailEnc</div>
				</div>
				<div class="three columns approval text-center">
					<input class="row request-selector" name="request" type="checkbox" />
					<div class="row signup-age">$agoEnc</div>
				</div>
			</div>
			HTML;
	}

	private function getHumanTimestamp( MWTimestamp $ts ): string {
		return $this->getLanguage()->getHumanTimestamp( $ts, null, $this->getUser() );
	}

	/**
	 * Sorts groups by descending order of number of translations,
	 * registration date and username
	 */
	private function translatorRequestSort( array $a, array $b ): int {
		return $b['translations'] <=> $a['translations']
			?: $b['registrationdate'] <=> $a['registrationdate']
				?: strnatcasecmp( $a['username'], $b['username'] );
	}
}
