/**
 * Bundle notification item widget.
 * This widget is expandable and displays
 * inner notifications that constitute the bundle.
 *
 * @class
 * @extends mw.echo.ui.NotificationItemWidget
 *
 * @constructor
 * @param {mw.echo.Controller} controller Echo notifications controller
 * @param {mw.echo.dm.BundleNotificationItem} model Notification group model
 * @param {Object} [config={}]
 * @param {boolean} [config.animateSorting=false] Animate the sorting of items
 */
mw.echo.ui.BundleNotificationItemWidget = function MwEchoUiBundleNotificationItemWidget( controller, model, config ) {
	config = config || {};

	// Parent constructor
	mw.echo.ui.BundleNotificationItemWidget.super.call( this, controller, model, config );

	this.toggleMarkAsReadButtons( true );

	this.listWidget = new mw.echo.ui.SortedListWidget(
		// Sorting callback
		( ( a, b ) => {
			// Reverse sorting
			if ( b.getTimestamp() < a.getTimestamp() ) {
				return -1;
			} else if ( b.getTimestamp() > a.getTimestamp() ) {
				return 1;
			}

			// Fallback on IDs
			return b.getId() - a.getId();
		} ),
		// Config
		{
			classes: [ 'mw-echo-ui-bundleNotificationItemWidget-group' ],
			timestamp: this.getTimestamp(),
			$overlay: this.$overlay,
			animated: !!config.animateSorting,
		},
	);

	this.listWidget.$element
		// We have to manually set the display to 'none' here because
		// otherwise the 'slideUp' and 'slideDown' jQuery effects don't
		// work
		.css( 'display', 'none' );

	// Prevent clicks on the list padding area from activating the primary link
	this.listWidget.$element.on( 'click', ( e ) => {
		if ( e.target.closest( 'a' ) === this.$element[ 0 ] ) {
			e.preventDefault();
		}
	} );

	// Initialize closed
	this.expanded = false;

	// Add "expand" button
	this.toggleExpandButton = new OO.ui.ButtonOptionWidget( {
		icon: 'expand',
		framed: false,
		classes: [ 'mw-echo-ui-notificationItemWidget-content-actions-button' ],
	} );
	this.updateExpandButton();
	this.actionsButtonSelectWidget.addItems( [ this.toggleExpandButton ], 0 );

	// Events
	this.toggleExpandButton.connect( this, { click: 'expand' } );

	if ( !this.model.getPrimaryUrl() ) {
		// If there's no primary link, make sure a click
		// triggers the 'expand' action
		this.$content.on( 'click', this.expand.bind( this ) );
	}

	// Initialization
	this.populateFromModel();
	this.toggleExpanded( false );
	this.toggleRead( false );
	this.$element
		.addClass( 'mw-echo-ui-bundleNotificationItemWidget' )
		.append(
			$( '<div>' )
				.addClass( 'mw-echo-ui-bundleNotificationItemWidget-separator' ),
			this.listWidget.$element,
		);

	// Events
	this.model.connect( this, { update: 'updateDataFromModel' } );

	// Update read and seen states from the model
	this.updateDataFromModel();
};

/* Initialization */

OO.inheritClass( mw.echo.ui.BundleNotificationItemWidget, mw.echo.ui.NotificationItemWidget );

/* Methods */

/**
 * @inheritdoc
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.markRead = function ( isRead ) {
	this.controller.markEntireListModelRead( this.model.getModelName(), isRead );
};

/**
 * Populate the items in this widget according to the data
 * in the model
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.populateFromModel = function () {
	this.getList().addItems( this.model.getList().getItems().map( ( singleNotifModel ) => new mw.echo.ui.SingleNotificationItemWidget(
		this.controller,
		singleNotifModel,
		{
			$overlay: this.$overlay,
			bundle: true,
		},
	) ) );
};

/**
 * Update item state when the item model changes.
 *
 * @fires OO.EventEmitter#sortChange
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.updateDataFromModel = function () {
	this.toggleRead( this.model.isRead() );
	this.toggleSeen( this.model.isSeen() );
	this.emit( 'sortChange' );
};

/**
 * Toggle the visibility of the notification item list and the placeholder/error widget.
 *
 * @param {boolean} showList Show the list
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.toggleListDisplay = function ( showList ) {
	this.listWidget.toggle( showList );
};

/**
 * Expand the group and fetch the list of notifications.
 * Only fetch the first time we expand.
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.expand = function () {
	this.toggleExpanded( !this.expanded );
	this.updateExpandButton();

	this.$element.toggleClass( 'mw-echo-ui-bundleNotificationItemWidget-expanded', this.expanded );
};

/**
 * Toggle the expand/collapsed state of this group widget
 *
 * @param {boolean} show Show the widget expanded
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.toggleExpanded = function ( show ) {
	this.expanded = show !== undefined ? !!show : !this.expanded;

	if ( show ) {
		// FIXME: Use CSS transition
		// eslint-disable-next-line no-jquery/no-slide
		this.getList().$element.slideDown();
	} else {
		// eslint-disable-next-line no-jquery/no-slide
		this.getList().$element.slideUp();
	}
};

/**
 * Update the expand button label
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.updateExpandButton = function () {
	this.toggleExpandButton.setLabel(
		this.expanded ?
			mw.msg( 'notification-link-text-collapse-all' ) :
			mw.msg( 'notification-link-text-expand-all' ),
	);
	this.toggleExpandButton.setIcon(
		this.expanded ?
			'collapse' :
			'expand',
	);
	// T258706
	this.toggleExpandButton.setActive( false );
};

/**
 * Get the list widget contained in this item
 *
 * @return {mw.echo.ui.SortedListWidget} List widget
 */
mw.echo.ui.BundleNotificationItemWidget.prototype.getList = function () {
	return this.listWidget;
};
