( function () {
	/**
	 * A widget that displays wikis and their pages to choose a filter
	 *
	 * @class
	 * @extends OO.ui.SelectWidget
	 *
	 * @constructor
	 * @param {mw.echo.dm.FiltersModel} filterModel Filters model
	 * @param {string} source Symbolic name for the source
	 * @param {Object} [config] Configuration object
	 * @param {string} [config.title] The title of this page group, usually
	 *  the name of the wiki that the pages belong to
	 * @param {number} [config.unreadCount] Number of unread notifications
	 * @param {number} [config.initialSelection] The page title of the option to select initially
	 */
	mw.echo.ui.PageFilterWidget = function MwEchoUiPageFilterWidget( filterModel, source, config ) {
		config = config || {};

		// Parent constructor
		mw.echo.ui.PageFilterWidget.super.call( this, config );

		this.model = filterModel;
		this.source = source;
		// This is to be able to fetch and recognize this widget
		// according to its source. The source is, in this case,
		// unique per filter widget.
		this.data = this.source;
		this.totalCount = config.unreadCount || this.model.getSourceTotalCount( this.source );

		this.initialSelection = config.initialSelection;

		// Title option
		this.title = new mw.echo.ui.PageNotificationsOptionWidget( {
			label: config.title,
			title: config.title,
			count: this.totalCount,
			isCapped: true,
			data: null,
			classes: [ 'mw-echo-ui-pageFilterWidget-title' ]
		} );

		// Initialization
		this.populateDataFromModel();
		this.$element
			.addClass( 'mw-echo-ui-pageFilterWidget' )
			.attr( 'aria-label', mw.msg( 'echo-specialpage-pagefilterwidget-aria-label' ) );
	};

	/* Initialization */

	OO.inheritClass( mw.echo.ui.PageFilterWidget, OO.ui.SelectWidget );

	/**
	 * Set the total count of this group
	 *
	 * @return {number} Total count
	 */
	mw.echo.ui.PageFilterWidget.prototype.getTotalCount = function () {
		return this.totalCount;
	};

	/**
	 * Populate the widget from the model
	 */
	mw.echo.ui.PageFilterWidget.prototype.populateDataFromModel = function () {
		const optionWidgets = [],
			sourcePages = this.model.getSourcePages( this.source );

		for ( const title in sourcePages ) {
			const isUserPage = sourcePages[ title ].ns === mw.config.get( 'wgNamespaceIds' ).user;
			const widget = new mw.echo.ui.PageNotificationsOptionWidget( {
				label: isUserPage ? sourcePages[ title ].unprefixed : title,
				title: isUserPage ? sourcePages[ title ].unprefixed : title,
				icon: isUserPage ? 'userAvatar' : 'article',
				count: sourcePages[ title ].count,
				data: title,
				classes: [ 'mw-echo-ui-pageFilterWidget-page' ]
			} );
			optionWidgets.push( widget );

			if ( this.initialSelection === title ) {
				widget.setSelected( true );
			}
		}

		this.setItems( optionWidgets );
	};

	/**
	 * Get the source associated with this filter
	 *
	 * @return {string} Source symbolic name
	 */
	mw.echo.ui.PageFilterWidget.prototype.getSource = function () {
		return this.source;
	};

	/**
	 * Get the title item
	 *
	 * @return {mw.echo.ui.PageNotificationsOptionWidget} Page title item
	 */
	mw.echo.ui.PageFilterWidget.prototype.getTitleItem = function () {
		return this.title;
	};

	/**
	 * Set the page items in this widget, in order
	 *
	 * @param {mw.echo.ui.PageNotificationsOptionWidget[]} items Item widgets to order and insert
	 */
	mw.echo.ui.PageFilterWidget.prototype.setItems = function ( items ) {
		this.clearItems();
		for ( let i = 0; i < items.length; i++ ) {
			const index = this.findInsertionIndex( items[ i ] );
			this.addItems( [ items[ i ] ], index );
		}

		// Add the title on top
		this.addItems( [ this.title ], 0 );
	};

	/**
	 * Find the proper insertion index for ordering when inserting items
	 *
	 * @private
	 * @param {mw.echo.ui.PageNotificationsOptionWidget} item Item widget
	 * @return {number} Insertion index
	 */
	mw.echo.ui.PageFilterWidget.prototype.findInsertionIndex = function ( item ) {
		return OO.binarySearch(
			this.items,
			( otherItem ) => this.sortingFunction( item, otherItem ),
			true
		);
	};

	/**
	 * Sorting function for item insertion
	 *
	 * @private
	 * @param {mw.echo.ui.PageNotificationsOptionWidget} item Item widget
	 * @param {mw.echo.ui.PageNotificationsOptionWidget} otherItem Another item widget
	 * @return {number} Ordering value
	 */
	mw.echo.ui.PageFilterWidget.prototype.sortingFunction = function ( item, otherItem ) {
		return Number( otherItem.getCount() ) - Number( item.getCount() );
	};
}() );
