<?php

use MediaWiki\Html\Html;
use MediaWiki\Language\Language;
use MediaWiki\MediaWikiServices;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Specials\SpecialEditWatchlist;
use MediaWiki\Title\Title;
use MobileFrontend\Hooks\HookRunner;
use MobileFrontend\Models\MobileCollection;
use MobileFrontend\Models\MobilePage;

/**
 * The mobile version of the watchlist editing page.
 * @deprecated in future this should be the core SpecialEditWatchlist page (T109277)
 */
class SpecialMobileEditWatchlist extends SpecialEditWatchlist {
	private const WATCHLIST_TAB_PATHS = [
		'Special:Watchlist',
		'Special:EditWatchlist'
	];
	private const LIMIT = 50;

	/** @var string The name of the title to begin listing the watchlist from */
	protected $offsetTitle;

	public function __construct() {
		$req = $this->getRequest();
		$this->offsetTitle = $req->getVal( 'from', '' );
		$watchStoreItem = MediaWikiServices::getInstance()->getWatchedItemStore();
		parent::__construct( $watchStoreItem );
	}

	/**
	 * Renders the subheader.
	 */
	protected function outputSubtitle() {
		$user = $this->getUser();
	}

	/**
	 * Gets the HTML fragment for a watched page. The client uses a very different
	 * structure for client-rendered items in PageListItem.hogan.
	 *
	 * @param MobilePage $mp a definition of the page to be rendered.
	 * @return string
	 */
	protected function getLineHtml( MobilePage $mp ) {
		$thumb = $mp->getSmallThumbnailHtml( true );
		$title = $mp->getTitle();
		if ( !$thumb ) {
			$thumb = Html::rawElement( 'div', [
				'class' => 'list-thumb list-thumb-placeholder'
				], Html::element( 'span', [
					'class' => 'mf-icon-image'
				] )
			);
		}
		$timestamp = $mp->getLatestTimestamp();
		$user = $this->getUser();
		$titleText = $title->getPrefixedText();
		if ( $timestamp ) {
			$className = 'title';
		} else {
			$className = 'title new';
		}

		$html =
			Html::openElement( 'li', [
				'class' => 'page-summary',
				'title' => $titleText,
				'data-id' => $title->getArticleID()
			] ) .
			Html::openElement( 'a', [ 'href' => $title->getLocalURL(), 'class' => $className ] );
		$html .= $thumb;
		$html .=
			Html::element( 'h3', [], $titleText );

		$html .= Html::closeElement( 'a' ) .
			Html::closeElement( 'li' );

		return $html;
	}

	/**
	 * The main entry point for the page.
	 *
	 * @param string|null $mode Whether the user is viewing, editing, or clearing their
	 *  watchlist
	 */
	public function execute( $mode ) {
		// Anons don't get a watchlist edit
		$this->requireLogin( 'mobile-frontend-watchlist-purpose' );

		$out = $this->getOutput();
		$out->addBodyClasses( 'mw-mf-special-page' );
		parent::execute( $mode );
		$out->setPageTitleMsg( $this->msg( 'watchlist' ) );
	}

	/**
	 * Finds the offset of the page given in this->offsetTitle
	 * If doesn't exist returns 0 to show from beginning of array of pages.
	 *
	 * @param array $pages
	 * @return int where the index of the next page to be shown.
	 */
	private function getPageOffset( $pages ) {
		// Deal with messiness of mediawiki
		$pages = array_keys( $pages );

		if ( $this->offsetTitle ) {
			// PHP is stupid. strict test to avoid issues when page '0' is watched.
			$offset = array_search( $this->offsetTitle, $pages, true );
			// Deal with cases where invalid title given
			if ( $offset === false ) {
				$offset = 0;
			}
		} else {
			$offset = 0;
		}
		return $offset;
	}

	/**
	 * Create paginated view of entire watchlist
	 *
	 * @param array $pages
	 * @return array of pages that should be displayed in current view
	 */
	private function getPagesToDisplay( $pages ) {
		$offset = $this->getPageOffset( $pages );
		// Get the slice we are going to display and display it
		return array_slice( $pages, $offset, self::LIMIT, true );
	}

	/**
	 * Get the HTML needed to show if a user doesn't watch any page, show information
	 * how to watch pages where no pages have been watched.
	 * @param bool $feed Render as feed (true) or list (false) view?
	 * @param Language $lang The language of the current mode
	 * @return string
	 */
	public static function getEmptyListHtml( $feed, $lang ) {
		$dir = $lang->isRTL() ? 'rtl' : 'ltr';

		$config = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Config' );
		$imgUrl = $config->get( 'ExtensionAssetsPath' ) .
			"/MobileFrontend/images/emptywatchlist-page-actions-$dir.png";

		if ( $feed ) {
			$msg = Html::element( 'p', [], wfMessage( 'mobile-frontend-watchlist-feed-empty' )->plain() );
		} else {
			$msg = Html::element( 'p', [],
				wfMessage( 'mobile-frontend-watchlist-a-z-empty-howto' )->plain()
			);
			$msg .= Html::element( 'img', [
				'src' => $imgUrl,
				'alt' => wfMessage( 'mobile-frontend-watchlist-a-z-empty-howto-alt' )->plain(),
			] );
		}

		return Html::openElement( 'div', [ 'class' => 'info empty-page' ] ) .
			$msg .
			Html::element( 'a',
				[ 'class' => 'button', 'href' => Title::newMainPage()->getLocalURL() ],
				wfMessage( 'mobile-frontend-watchlist-back-home' )->plain()
			) .
			Html::closeElement( 'div' );
	}

	/**
	 * Identify the next page to be shown
	 *
	 * @param array $pages
	 * @return string|bool representing title of next page to show or
	 *  false if there isn't another page to show.
	 */
	private function getNextPage( $pages ) {
		$total = count( $pages );
		$offset = $this->getPageOffset( $pages );
		$limit = self::LIMIT;

		// Work out if we need a more button and where to start from
		if ( $total > $offset + $limit ) {
			$pageKeys = array_keys( $pages );
			$from = $pageKeys[$offset + $limit];
		} else {
			$from = false;
		}
		return $from;
	}

	/**
	 * Renders the view/edit (normal) mode of the watchlist.
	 */
	protected function executeViewEditWatchlist() {
		$ns = NS_MAIN;
		$images = [];

		$watchlist = $this->getWatchlistInfo();

		if ( isset( $watchlist[$ns] ) ) {
			$allPages = $watchlist[$ns];
			$from = $this->getNextPage( $allPages );
			$allPages = $this->getPagesToDisplay( $allPages );
		} else {
			$allPages = [];
			$from = false;
		}

		// Begin rendering of watchlist.
		$watchlist = [ $ns => $allPages ];
		$services = MediaWikiServices::getInstance();
		( new HookRunner( $services->getHookContainer() ) )
			->onSpecialMobileEditWatchlist__images(
				$this->getContext(), $watchlist, $images
			);

		// create list of pages
		$mobilePages = new MobileCollection();
		$pageKeys = array_keys( $watchlist[$ns] );
		$repoGroup = $services->getRepoGroup();
		foreach ( $pageKeys as $dbkey ) {
			if ( isset( $images[$ns][$dbkey] ) ) {
				$page = new MobilePage(
					Title::makeTitleSafe( $ns, $dbkey ),
					$repoGroup->findFile( $images[$ns][$dbkey] )
				);
			} else {
				$page = new MobilePage( Title::makeTitleSafe( $ns, $dbkey ) );
			}
			$mobilePages->add( $page );
		}

		if ( $mobilePages->isEmpty() ) {
			$html = self::getEmptyListHtml( false, $this->getLanguage() );
		} else {
			$html = $this->getViewHtml( $mobilePages );
		}
		if ( $from ) {
			// show more link if there are more items to show
			$qs = [ 'from' => $from ];
			$html .= Html::element( 'a',
				[
					'class' => 'mw-mf-watchlist-more',
					'href' => SpecialPage::getTitleFor( 'EditWatchlist' )->getLocalURL( $qs ),
				],
				$this->msg( 'mobile-frontend-watchlist-more' )->text() );
		}
		$out = $this->getOutput();
		$out->addHTML( $html );
		$out->addModules( 'mobile.special.watchlist.scripts' );
		$out->addModuleStyles(
			[
				'mobile.pagelist.styles',
				'mobile.pagesummary.styles'
			]
		);
	}

	/**
	 * @param MobileCollection $collection Collection of pages to get view for
	 * @return string html representation of collection in watchlist view
	 */
	protected function getViewHtml( MobileCollection $collection ) {
		$html = Html::openElement( 'ul', [ 'class' => 'content-unstyled mw-mf-page-list thumbs'
			. ' page-summary-list mw-mf-watchlist-page-list' ] );
		foreach ( $collection as $mobilePage ) {
			$html .= $this->getLineHtml( $mobilePage );
		}
		$html .= Html::closeElement( 'ul' );
		return $html;
	}

	/**
	 * @inheritDoc
	 */
	public function getAssociatedNavigationLinks() {
		return self::WATCHLIST_TAB_PATHS;
	}
}
