/**
 * Edit check to detect links to redirect pages
 *
 * @class
 * @extends mw.editcheck.LinkEditCheck
 *
 * @constructor
 * @param {mw.editcheck.Controller} controller
 * @param {Object} [config]
 * @param {boolean} [includeSuggestions=false]
 */
mw.editcheck.RedirectEditCheck = function MWRedirectEditCheck() {
	// Parent constructor
	mw.editcheck.RedirectEditCheck.super.apply( this, arguments );
};

/* Inheritance */

OO.inheritClass( mw.editcheck.RedirectEditCheck, mw.editcheck.LinkEditCheck );

OO.mixinClass( mw.editcheck.RedirectEditCheck, mw.editcheck.ContentBranchNodeCheck );

/* Static properties */

mw.editcheck.RedirectEditCheck.static.defaultConfig = ve.extendObject( {}, mw.editcheck.RedirectEditCheck.super.static.defaultConfig, {
	showAsCheck: false,
	showAsSuggestion: false
} );

mw.editcheck.RedirectEditCheck.static.title = 'Link to the final page';

mw.editcheck.RedirectEditCheck.static.name = 'redirect';

mw.editcheck.RedirectEditCheck.static.description = 'This link points to a redirect page. Link to the final page instead.';

// HACK: Use plain string above so Special:EditChecks can parse.
const description = mw.editcheck.RedirectEditCheck.static.description;
mw.editcheck.RedirectEditCheck.static.description = () => $( $.parseHTML( description ) );

mw.editcheck.RedirectEditCheck.static.choices = [
	{
		action: 'fix',
		label: 'Update link'
	},
	{
		action: 'dismiss',
		label: OO.ui.deferMsg( 'ooui-dialog-process-dismiss' )
	}
];

mw.editcheck.RedirectEditCheck.static.linkClasses = [ ve.dm.MWInternalLinkAnnotation ];

/* Methods */

mw.editcheck.RedirectEditCheck.prototype.checkNode = function ( node, surfaceModel ) {
	const checkRedirect = ( annotation ) => ve.init.platform.linkCache.get(
		annotation.getAttribute( 'lookupTitle' )
	).then( ( linkData ) => !!( linkData && linkData.redirect ) );

	const ranges = node.getAnnotationRanges()
		// exclude links where the link target matches the link text
		.filter( ( annRange ) => {
			if ( annRange.annotation.name !== ve.dm.MWInternalLinkAnnotation.static.name ) {
				return false;
			}
			const labelTitle = mw.Title.newFromText( surfaceModel.getLinearFragment( annRange.range ).getText() );
			if ( !labelTitle ) {
				// Label isn't a valid title, so can't be equal to the target.
				return true;
			}
			const title = mw.Title.newFromText( annRange.annotation.getDisplayTitle() );
			// Normalise titles, and compare. If the titles are equal, or the target is a
			// prefix of the label, then it's likely this is indented to produce compact
			// wikitext, e.g. [[redirect]] or [[redirect]]s
			return !labelTitle.getPrefixedText().startsWith( title.getPrefixedText() );
		} );
	const actionsPromises = ranges.map( ( annRange ) => checkRedirect( annRange.annotation )
		.then( ( isRedirect ) => isRedirect ?
			this.buildActionFromLinkRange( annRange.range, surfaceModel ) : null
		)
	);
	return actionsPromises;
};

mw.editcheck.RedirectEditCheck.prototype.act = function ( choice, action, surface ) {
	if ( choice === 'fix' ) {
		const fragment = action.fragments[ 0 ];
		const linkAnnotation = this.getLinkFromFragment( fragment );

		if ( !linkAnnotation ) {
			return;
		}

		return surface.getTarget().getContentApi().get( {
			action: 'query',
			titles: linkAnnotation.getAttribute( 'lookupTitle' ),
			redirects: true
		} ).then( ( data ) => {
			const targetTitle = ve.getProp( data, 'query', 'redirects', 0, 'to' );
			if ( targetTitle ) {
				const newLinkAnnotation = ve.dm.MWInternalLinkAnnotation.static.newFromTitle(
					new mw.Title( targetTitle )
				);
				fragment
					.annotateContent( 'clear', linkAnnotation )
					.annotateContent( 'add', newLinkAnnotation );

				action.select( surface, true );
			}
		} );
	}
	// Parent method
	return mw.editcheck.RedirectEditCheck.super.prototype.act.apply( this, arguments );
};

/* Registration */

mw.editcheck.editCheckFactory.register( mw.editcheck.RedirectEditCheck );