/**
 * EditCheckActionWidget
 *
 * @class
 * @extends OO.ui.MessageWidget
 *
 * @param {Object} config Configuration options
 * @param {string} config.type Type of message (e.g., 'warning', 'error')
 * @param {string|jQuery|Function|OO.ui.HtmlSnippet} config.label Title
 * @param {string|jQuery|Function|OO.ui.HtmlSnippet} config.message Body message
 * @param {string|jQuery|Function|OO.ui.HtmlSnippet} [config.footer] Footer message
 * @param {string} [config.icon] Icon name
 * @param {boolean} [config.singleAction] This is the only action shown
 * @param {Object[]} [config.choices] User choices
 * @param {string} [config.mode] Mode for the action set widget
 * @param {boolean} [config.suggestion] This is a suggestion
 */
mw.editcheck.EditCheckActionWidget = function MWEditCheckActionWidget( config ) {
	this.singleAction = config.singleAction;
	this.mode = config.mode || '';
	this.suggestion = config.suggestion;

	this.name = config.name;

	this.actions = new OO.ui.ActionSet();
	this.actions.connect( this, {
		change: 'onActionsChange',
		click: [ 'emit', 'actionClick' ]
	} );

	mw.editcheck.EditCheckActionWidget.super.call( this, config );

	this.feedbackDeferred = null;

	this.collapsed = false;
	this.message = new OO.ui.LabelWidget( { label: config.message } );
	this.prompt = config.prompt && new OO.ui.LabelWidget( {
		label: config.prompt,
		classes: [ 've-ui-editCheckActionWidget-prompt' ]
	} );
	this.footer = config.footer && new OO.ui.LabelWidget( {
		label: config.footer,
		classes: [ 've-ui-editCheckActionWidget-footer' ]
	} );
	this.$actions = $( '<div>' ).addClass( 've-ui-editCheckActionWidget-actions oo-ui-element-hidden' );
	if ( this.prompt ) {
		this.$actions.addClass( 've-ui-editCheckActionWidget-actions-prompted' )
			.append( this.prompt.$element );
	}
	if ( config.choices ) {
		this.actions.add( config.choices.map(
			( choice ) => new OO.ui.ActionWidget( ve.extendObject( { modes: [ '' ], framed: true }, choice ) )
		) );
	}
	this.actions.setMode( this.mode );

	this.$element.on( 'click', this.onClick.bind( this ) );

	this.$body = $( '<div>' )
		.append( this.message.$element, this.$actions )
		.addClass( 've-ui-editCheckActionWidget-body' );

	if ( this.footer ) {
		this.$body.append( this.footer.$element );
	}

	if ( this.suggestion ) {
		this.$element.addClass( 've-ui-editCheckActionWidget-suggestion' );
	}

	this.$element
		.append( this.$body )
		.addClass( 've-ui-editCheckActionWidget' );
};

/* Inheritance */

OO.inheritClass( mw.editcheck.EditCheckActionWidget, OO.ui.MessageWidget );

/* Events */

/**
 * Fired when the user toggles the collapsed state of the widget.
 *
 * @event mw.editcheck.EditCheckActionWidget#togglecollapse
 */

/**
 * Fired when action set emits a click event
 *
 * @event mw.editcheck.EditCheckActionWidget#actionClick
 */

/* Methods */

/**
 * Set the mode
 *
 * @param {string} mode
 */
mw.editcheck.EditCheckActionWidget.prototype.setMode = function ( mode ) {
	this.mode = mode;
	this.actions.setMode( mode );
};

/**
 * Handle change events on the action set
 */
mw.editcheck.EditCheckActionWidget.prototype.onActionsChange = function () {
	let hasVisibleActions = false;
	this.actions.get().forEach( ( actionWidget ) => {
		this.$actions.append( actionWidget.$element );
		hasVisibleActions = hasVisibleActions || actionWidget.isVisible();
	} );
	this.$actions.toggleClass( 'oo-ui-element-hidden', !hasVisibleActions );
};

/**
 * @inheritdoc
 */
mw.editcheck.EditCheckActionWidget.prototype.setDisabled = function ( disabled ) {
	// Calling setDisabled on the parent doesn't do anything useful,
	// and causes the icon to become the wrong color due to an
	// upstream bug
	// Parent method
	// OO.ui.Widget.prototype.setDisabled.call( this, disabled );
	this.actions.forEach( null, ( action ) => {
		action.setDisabled( disabled );
	} );
};

/**
 * Handle click events anywhere on the widget
 *
 * @param {jQuery.Event} e Click event
 * @fires mw.editcheck.EditCheckActionWidget#togglecollapse
 */
mw.editcheck.EditCheckActionWidget.prototype.onClick = function ( e ) {
	if ( this.singleAction ) {
		return;
	}
	if ( this.$body[ 0 ].contains( e.target ) ) {
		return;
	}
	this.emit( 'togglecollapse' );

	e.preventDefault();
};

/**
 * Toggle the collapsed state of the widget
 *
 * @param {boolean} [collapsed] The new collapsed state, toggles if unset
 */
mw.editcheck.EditCheckActionWidget.prototype.toggleCollapse = function ( collapsed ) {
	const previousState = this.collapsed;
	this.collapsed = collapsed !== undefined ? collapsed : !this.collapsed;
	this.$element.toggleClass( 've-ui-editCheckActionWidget-collapsed', this.collapsed );

	if ( this.collapsed && previousState !== this.collapsed && this.feedbackDeferred ) {
		this.feedbackDeferred.reject();
	}
};

/**
 * Show a feedback panel
 *
 * @param {Object} data
 * @param {string} data.title
 * @param {string} [data.description]
 * @param {Object[]} data.choices
 * @return {jQuery.Promise} Promise which resolves when feedback is submitted or is rejected when back is chosen
 */
mw.editcheck.EditCheckActionWidget.prototype.showFeedback = function ( data ) {
	const deferred = this.feedbackDeferred = ve.createDeferred();
	if ( this.suggestion ) {
		// Suggestions bypass feedback surveys
		return deferred.resolve().promise();
	}

	const form = new OO.ui.FieldsetLayout( {
		classes: [ 've-ui-editCheckActionWidget-feedback' ]
	} );
	const answerRadioSelect = new OO.ui.RadioSelectWidget( {
		items: data.choices.map( ( choice ) => new OO.ui.RadioOptionWidget( choice ) )
	} );
	const submit = new OO.ui.ButtonInputWidget( {
		label: ve.msg( 'editcheck-dialog-action-submit' ),
		flags: [ 'progressive', 'primary' ],
		disabled: true
	} );
	const back = new OO.ui.ButtonInputWidget( {
		label: ve.msg( 'editcheck-dialog-action-back' ),
		flags: [ 'safe', 'back' ],
		icon: 'previous'
	} );
	answerRadioSelect.on( 'select', () => {
		submit.setDisabled( !answerRadioSelect.findSelectedItem() );
	} );
	form.addItems( [
		new OO.ui.FieldLayout( answerRadioSelect, {
			label: data.description || ve.msg( 'editcheck-reject-description' ),
			align: 'top'
		} ),
		new OO.ui.HorizontalLayout( {
			items: [
				new OO.ui.FieldLayout( back ),
				new OO.ui.FieldLayout( submit )
			]
		} )
	] );
	submit.on( 'click', () => {
		const selectedItem = answerRadioSelect.findSelectedItem();
		const reason = selectedItem && selectedItem.getData();
		if ( reason ) {
			deferred.resolve( reason );
			ve.track( 'activity.editCheck-' + this.name, { action: 'edit-check-feedback-reason-' + reason } );
		}
	} );
	back.on( 'click', () => {
		deferred.reject();
	} );

	this.$body.prepend( form.$element );

	ve.track( 'activity.editCheck-' + this.name, { action: 'edit-check-feedback-shown' } );
	return deferred.promise().always( () => {
		// HACK: This causes the answerRadioSelect.onDocumentKeyDownHandler to be unbound
		// Otherwise, it'll swallow certain key events (arrow keys, enter, pagedown/up) forever.
		answerRadioSelect.$element.trigger( 'blur' );
		form.$element.remove();
		this.feedbackDeferred = null;
	} );
};