const
	CANCEL_GLYPH = 'close',
	Icon = require( './Icon' ),
	IconButton = require( './IconButton' );

/**
 * A set of shared icons.
 *
 * Factory methods are used to keep separate features that use the same icons
 * from accidentally manipulating one another's DOM when calling methods like
 * `remove`.
 *
 * @class icons
 * @singleton
 * @uses Icon
 */
const icons = {
	CANCEL_GLYPH,
	// Exported to support testing and stubbing
	Icon,
	IconButton,
	/**
	 * Gets a back icon
	 *
	 * The icon should be used to inform the user that the front-end is
	 * communicating with the back-end.
	 *
	 * @memberof icons
	 * @instance
	 * @return {IconButton}
	 */
	back() {
		return new icons.IconButton( {
			tagName: 'button',
			icon: 'previous',
			additionalClassNames: 'back',
			label: mw.msg( 'mobile-frontend-overlay-close' )
		} );
	},
	/**
	 * Gets a cancel icon
	 *
	 * The icon should be used to inform the user that the front-end is
	 * communicating with the back-end.
	 *
	 * @memberof icons
	 * @instance
	 * @param {string} [variant]
	 * @param {Object} [props] to extend
	 * @return {IconButton}
	 */
	cancel( variant, props = {} ) {
		const glyph = variant ? `${ CANCEL_GLYPH }-${ variant }` : `${ CANCEL_GLYPH }`;
		props.additionalClassNames = props.additionalClassNames || '';
		props.additionalClassNames += ' cancel';

		return new icons.IconButton( Object.assign( {
			tagName: 'button',
			icon: glyph,
			label: mw.msg( 'mobile-frontend-overlay-close' )
		}, props ) );
	},
	/**
	 * Gets a spinner icon. This uses IconButton but should never actually
	 * be a button or have full button styles, as its purely presentational
	 *
	 * The icon should be used to inform the user that the front-end is
	 * communicating with the back-end.
	 *
	 * @memberof icons
	 * @instance
	 * @param {Object} [props] See `Icon` for more details
	 * @return {IconButton}
	 */
	spinner( props = {} ) {
		if ( props.additionalClassNames === undefined ) {
			props.additionalClassNames = 'spinner loading';
		}

		const spinner = new icons.IconButton( Object.assign( {
			tagName: 'span',
			icon: 'spinner',
			label: mw.msg( 'mobile-frontend-loading-message' )
		}, props ) );

		// Update the element to not use button classes or attributes
		spinner.$el.removeClass();
		// eslint-disable-next-line mediawiki/class-doc
		spinner.$el.addClass( props.additionalClassNames );
		spinner.$el.attr( 'type', '' );
		if ( spinner.options.isIconOnly ) {
			spinner.$el.addClass( 'mf-spinner-icon-element' );
		}
		return spinner;
	},
	/**
	 * Gets a failure (error) icon
	 *
	 * @memberof icons
	 * @instance
	 * @return {IconButton}
	 */
	error() {
		return new icons.IconButton( {
			icon: 'alert-invert',
			additionalClassNames: 'load-fail-msg-icon'
		} );
	},
	/**
	 * Gets a non-filled watch star icon.
	 *
	 * @memberof icons
	 * @instance
	 * @param {Object} props
	 * @return {IconButton}
	 */
	watch( props = {} ) {
		props.additionalClassNames = props.additionalClassNames || '';
		props.additionalClassNames += ' watch-this-article';

		return new icons.IconButton( Object.assign( {
			icon: 'star-subtle'
		}, props ) );
	},
	/**
	 * Gets a filled watch star icon.
	 *
	 * @memberof icons
	 * @instance
	 * @param {Object} props
	 * @return {IconButton}
	 */
	watched( props = {} ) {
		props.additionalClassNames = props.additionalClassNames || '';
		props.additionalClassNames += ' watch-this-article watched';

		return new icons.IconButton( Object.assign( {
			icon: 'unStar-progressive'
		}, props ) );
	}
};

module.exports = icons;
