/**
 * A pagination widget allowing the user to go forward, backwards,
 * and after a couple of pages, go back to home.
 *
 * @class
 * @extends OO.ui.Widget
 *
 * @constructor
 * @param {mw.echo.dm.PaginationModel} paginationModel Pagination model
 * @param {Object} [config={}]
 * @param {number} [config.itemsPerPage=25] Number of items per page
 * @param {number} [config.showFirstButton=true] Show a button that allows the user
 *  to go back to the first page.
 * @param {number} [config.showFirstButtonAfter=2] Pick the number of pages that it
 *  takes to show the button that takes the user back to the first set
 *  of results.
 * @param {string} [config.startButtonLabel] The label used for the start button
 */
mw.echo.ui.PaginationWidget = function MwEchoUiPaginationWidget( paginationModel, config ) {
	config = config || {};

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

	this.model = paginationModel;

	this.showFirstButton = config.showFirstButton === undefined ? true : !!config.showFirstButton;
	this.showFirstButtonAfter = config.showFirstButtonAfter || 2;
	this.itemsPerPage = config.itemsPerPage || 25;

	// Pagination elements
	this.labelWidget = new OO.ui.LabelWidget( {
		classes: [ 'mw-echo-ui-paginationWidget-label' ],
	} );

	this.startButton = new OO.ui.ButtonWidget( {
		classes: [ 'mw-echo-ui-paginationWidget-start' ],
		label: config.startButtonLabel || mw.msg( 'notification-timestamp-today' ),
		data: 'start',
	} );

	this.dirSelectWidget = new OO.ui.ButtonSelectWidget( {
		classes: [ 'mw-echo-ui-paginationWidget-direction' ],
		items: [
			new OO.ui.ButtonOptionWidget( {
				icon: 'previous',
				data: 'prev',
			} ),
			new OO.ui.ButtonOptionWidget( {
				icon: 'next',
				data: 'next',
			} ),
		],
	} );

	// Events
	this.startButton.connect( this, { click: [ 'emit', 'change', 'start' ] } );
	this.dirSelectWidget.connect( this, { choose: 'onDirSelectWidgetChoose' } );
	this.model.connect( this, { update: 'updateWidgetState' } );

	// Initialization
	this.updateWidgetState();
	this.$element
		.addClass( 'mw-echo-ui-paginationWidget' )
		.append(
			$( '<div>' )
				.addClass( 'mw-echo-ui-paginationWidget-row' )
				.append(
					this.labelWidget.$element,
					this.startButton.$element,
					this.dirSelectWidget.$element,
				),
		);
};

/* Initialization */

OO.inheritClass( mw.echo.ui.PaginationWidget, OO.ui.Widget );

/* Events */

/**
 * Pagination changed
 *
 * @event mw.echo.ui.PaginationWidget#change
 * @param {string} direction Direction of movement 'prev',
 * 'next' or 'start'
 */

/* Methods */

/**
 * Respond to dir select widget choose event
 *
 * @param {OO.ui.ButtonOptionWidget} item Chosen button
 * @fires mw.echo.ui.PaginationWidget#change
 */
mw.echo.ui.PaginationWidget.prototype.onDirSelectWidgetChoose = function ( item ) {
	const dir = item && item.getData();

	if ( dir ) {
		this.emit( 'change', dir );
		item.setSelected( false );
	}
};

/**
 * Update the state - disabled and visibility - of the sub widgets.
 */
mw.echo.ui.PaginationWidget.prototype.updateWidgetState = function () {
	this.dirSelectWidget.findItemFromData( 'prev' )
		.setDisabled( this.isDisabled() || !this.model.hasPrevPage() );
	this.dirSelectWidget.findItemFromData( 'next' )
		.setDisabled( this.isDisabled() || !this.model.hasNextPage() );

	this.startButton.toggle(
		!this.isDisabled() &&
		this.model.getCurrPageIndex() >= this.showFirstButtonAfter,
	);

	// Only show pagination buttons if there's anywhere to go
	this.dirSelectWidget.toggle( this.model.hasPrevPage() || this.model.hasNextPage() );

	// Update label text and visibility
	this.updateLabel();
	this.labelWidget.toggle( !this.isDisabled() );
};

/**
 * Set the 'disabled' state of the widget.
 *
 * @param {boolean} disabled Disable widget
 * @chainable
 * @return {mw.echo.ui.PaginationWidget}
 */
mw.echo.ui.PaginationWidget.prototype.setDisabled = function ( disabled ) {
	// Parent method
	mw.echo.ui.PaginationWidget.super.prototype.setDisabled.call( this, disabled );

	if (
		this.dirSelectWidget &&
		this.startButton &&
		this.labelWidget
	) {
		this.updateWidgetState();
	}

	return this;
};

/**
 * Update the pagination label according to the page number, the amount of notifications
 * per page, and the number of notifications on the current page.
 */
mw.echo.ui.PaginationWidget.prototype.updateLabel = function () {
	const itemsInPage = this.model.getCurrentPageItemCount(),
		firstNotifNum = this.model.getCurrPageIndex() * this.itemsPerPage,
		lastNotifNum = firstNotifNum + itemsInPage;

	let label;
	if ( itemsInPage === 0 ) {
		label = '';
	} else if ( !this.model.hasPrevPage() && !this.model.hasNextPage() ) {
		label = mw.msg(
			'echo-specialpage-pagination-numnotifications',
			mw.language.convertNumber( itemsInPage ),
		);
	} else {
		label = mw.msg(
			'echo-specialpage-pagination-range',
			mw.language.convertNumber( firstNotifNum + 1 ),
			mw.language.convertNumber( lastNotifNum ),
		);
	}

	this.labelWidget.setLabel( label );
};
