( function () {
	'use strict';

	var state, hideOptionalMessages = '!optional';

	state = {
		group: null,
		language: null,
		messageList: null
	};

	mw.translate = mw.translate || {};
	var logger = require( 'ext.translate.eventlogginghelpers' );

	mw.translate = $.extend( mw.translate, {

		/**
		 * Change the group that is currently displayed
		 * in the TUX translation editor.
		 *
		 * @private
		 * @param {Object} group a message group object.
		 */
		changeGroup: function ( group ) {
			if ( !checkDirty() ) {
				return;
			}

			showAggregateSubgroupCount();

			state.group = group.id;

			var changes = {
				group: group.id,
				showMessage: null

			};

			mw.translate.changeUrl( changes );
			mw.translate.updateTabLinks( changes );
			removeGroupWarnings();
			state.messageList.changeSettings( changes );
			updateGroupInformation( state );
		},

		/**
		 * @private
		 * @param {string} language
		 */
		changeLanguage: function ( language ) {
			var changes = {
				language: language,
				showMessage: null
			};

			state.language = language;

			mw.translate.changeUrl( changes );
			mw.translate.updateTabLinks( changes );
			removeGroupWarnings();
			state.messageList.changeSettings( changes );
			state.groupSelector.updateTargetLanguage( language );
			updateGroupInformation( state );

			getTranslationStats( language ).done( function ( stats ) {
				logger.logClickEvent(
					'change_target_lang',
					'language_selector',
					{
						// eslint-disable-next-line camelcase
						target_lang: language,
						// eslint-disable-next-line camelcase
						translatable_count: stats.total,
						// eslint-disable-next-line camelcase
						translated_count: stats.translated
					}
				);
			} );
		},

		/**
		 * @internal
		 * @param {string} filter
		 */
		changeFilter: function ( filter ) {
			if ( !checkDirty() ) {
				return;
			}

			mw.translate.changeUrl( { filter: filter, showMessage: null } );
			state.messageList.changeSettings( { filter: getActualFilter( filter ) } );
		},

		/**
		 * @internal
		 * @param {Object} params
		 */
		changeUrl: function ( params ) {
			var uri = new mw.Uri( window.location.href );

			uri.extend( params );

			// Support removing keys from the query
			Object.keys( params ).forEach( function ( key ) {
				if ( params[ key ] === null || params[ key ] === undefined ) {
					delete uri.query[ key ];
				}
			} );

			mw.hook( 'mw.translate.translationView.stateChange' ).fire( state );

			if ( uri.toString() === window.location.href ) {
				return;
			}

			if ( $( '.tux-messagelist' ).length ) {
				history.replaceState( uri, null, uri.toString() );
			} else {
				window.location.href = uri.toString();
			}
		},

		/**
		 * Updates the navigation tabs.
		 *
		 * @private
		 * @param {Object} params Url parameters to update.
		 * @since 2013.05
		 */
		updateTabLinks: function ( params ) {
			$( '.tux-tab a' ).each( function () {
				var $a = $( this );
				var uri = new mw.Uri( $a.prop( 'href' ) );
				uri.extend( params );
				$a.prop( 'href', uri.toString() );
			} );
		}
	} );

	function getTranslationStats( language ) {
		return mw.translate.loadMessageGroupStatsForItem( state.language, state.group ).then(
			function () {
				var statsData = mw.translate.languagestats[ language ] || [];
				for ( var i = 0; i < statsData.length; i++ ) {
					if ( statsData[ i ].group === state.group ) {
						return statsData[ i ];
					}
				}

				return {
					total: 0,
					translated: 0
				};
			}
		);
	}

	function getActionSource() {
		var uri = new mw.Uri( window.location.href );
		return uri.query.action_source || 'direct_open';
	}

	function getActualFilter( filter ) {
		var realFilters = [ '!ignored' ];
		var uri = new mw.Uri( window.location.href );
		if ( uri.query.optional !== '1' ) {
			realFilters.push( hideOptionalMessages );
		}
		if ( filter ) {
			realFilters.push( filter );
		}

		return realFilters.join( '|' );
	}

	function checkDirty() {
		if ( mw.translate.isDirty() ) {
			// eslint-disable-next-line no-alert
			return confirm( mw.msg( 'translate-js-support-unsaved-warning' ) );
		}
		return true;
	}

	// Returns an array of jQuery objects of rows of translated
	// and proofread messages in the TUX editors.
	// Used several times.
	function getTranslatedMessages( $translateContainer ) {
		$translateContainer = $translateContainer || $( '.ext-translate-container' );
		return $translateContainer.find( '.tux-message-item' )
			.filter( '.translated, .proofread' );
	}

	/**
	 * Updates all group specific stuff on the page.
	 *
	 * @param {Object} stateInfo Information about current group and language.
	 * @param {string} stateInfo.group Message group id.
	 * @param {string} stateInfo.language Language.
	 */
	function updateGroupInformation( stateInfo ) {
		var props = 'id|priority|prioritylangs|priorityforce|description|label|sourcelanguage|class|subscription';

		mw.translate.recentGroups.append( stateInfo.group );

		mw.translate.getMessageGroup( stateInfo.group, props ).done( function ( group ) {
			updateDescription( group );
			updateGroupPriorityWarnings( group, stateInfo.language );
			updateGroupSubscription( group );
		} );
	}

	function updateDescription( group ) {
		var
			api = new mw.Api(),
			$description = $( '.tux-editor-header .description' );

		if ( group.description === null ) {
			$description.empty();
			return;
		}
		var description = group.description;
		if (
			group.class === 'WikiPageMessageGroup' &&
			group.sourcelanguage !== state.language &&
			// Message documentation does not have a translation page
			state.language !== mw.config.get( 'wgTranslateDocumentationLanguageCode' )
		) {
			description = mw.msg(
				'translate-tag-page-wikipage-desc',
				':' + group.label + '/' + state.language,
				':' + group.label,
				$.uls.data.getAutonym( group.sourcelanguage ),
				group.sourcelanguage,
				$.uls.data.getAutonym( state.language ),
				state.language );
		}

		api.parse( description ).done( function ( parsedDescription ) {
			// The parsed text is returned in a <p> tag,
			// so it's removed here.
			$description.html( parsedDescription );
		} ).fail( function () {
			$description.empty();
			mw.log( 'Error parsing description for group ' + group.id );
		} );
	}

	function updateGroupPriorityWarnings( group, language ) {
		var $groupWarning = $( '.tux-editor-header .tux-group-warning' );

		if ( group.priority === 'discouraged' ) {
			$groupWarning.append(
				$( '<p>' ).append( $( '<strong>' )
					.text( mw.message( 'tpt-discouraged-translation-header' ).text() )
				),
				$( '<p>' ).append( mw.message( 'tpt-discouraged-translation-content' ).parseDom() )
			);
		}

		var headerMessage, languagesMessage;
		if ( !group.prioritylangs && group.priorityforce ) {
			headerMessage = mw.message(
				'tpt-discouraged-language-force-header',
				$.uls.data.getAutonym( language )
			);
			languagesMessage = mw.message( 'tpt-translation-restricted-no-priority-languages-no-reason' );
			$groupWarning.append(
				$( '<p>' ).append( $( '<strong>' ).text( headerMessage.text() ) ),
				$( '<p>' ).text( languagesMessage.text() )
			);
			return;
		}

		if ( !group.prioritylangs || isPriorityLanguage( language, group.prioritylangs ) ) {
			return;
		}

		// Make a comma-separated list of preferred languages
		var $preferredLanguages = $( '<span>' );
		group.prioritylangs.forEach( function ( languageCode, index ) {
			// bidi isolation for language names
			$preferredLanguages.append(
				$( '<bdi>' ).text( $.uls.data.getAutonym( languageCode ) )
			);

			// Add comma between languages
			if ( index + 1 !== group.prioritylangs.length ) {
				$preferredLanguages.append( ', ' );
			}
		} );

		if ( group.priorityforce ) {
			headerMessage = mw.message(
				'tpt-discouraged-language-force-header',
				$.uls.data.getAutonym( language )
			);
			languagesMessage = mw.message(
				'tpt-discouraged-language-force-content',
				$preferredLanguages
			);
		} else {
			headerMessage = mw.message(
				'tpt-discouraged-language-header',
				$.uls.data.getAutonym( language )
			);
			languagesMessage = mw.message(
				'tpt-discouraged-language-content',
				$preferredLanguages
			);
		}

		$groupWarning.append(
			$( '<p>' ).append( $( '<strong>' ).text( headerMessage.text() ) ),
			$( '<p>' ).append( languagesMessage.parseDom() )
		);
	}

	function updateGroupSubscription( group ) {
		if ( mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) !== true ) {
			return;
		}

		var $tuxBreadcrumb = $( '.tux-breadcrumb' );
		if ( group.subscription === undefined ) {
			$tuxBreadcrumb.find( '.tux-watch-button' ).remove();
			return;
		}

		var buttonMessage = group.subscription ? 'tux-unwatch-group' : 'tux-watch-group';
		var watchClass = group.subscription ? 'tux-watch-group--watch' : 'tux-watch-group--unwatch';
		var $subscribeButton = $( '<button>' )
			// CSS Classes:
			// * tux-watch-group--watch
			// * tux-watch-group--unwatch
			.addClass( 'mw-ui-button tux-watch-button ' + watchClass )
			.data( 'subscribed', group.subscription )
			.on( 'click', toggleSubscription );

		$subscribeButton.append(
			$( '<span>' ).addClass( 'tux-watch-icon' ),
			$( '<span>' )
				.addClass( 'tux-watch-label' )
				// * tux-watch-group
				// * tux-unwatch-group
				.text( mw.msg( buttonMessage ) )
		);

		$tuxBreadcrumb.find( '.tux-watch-button' ).remove();
		$tuxBreadcrumb.append( $subscribeButton );
	}

	function removeGroupWarnings() {
		var $tuxHeader = $( '.tux-editor-header' );
		$tuxHeader.find( '.tux-group-warning' ).empty();
	}

	function isPriorityLanguage( language, priorityLanguages ) {
		// Don't show priority notice if the language is message documentation.
		if ( language === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {
			return true;
		}

		// If no priority language is set, return early.
		if ( !priorityLanguages ) {
			return true;
		}

		return priorityLanguages.indexOf( language ) !== -1;
	}

	function setupLanguageSelector( $element ) {
		var ulsOptions = {
			languages: mw.config.get( 'wgTranslateLanguages' ),
			showRegions: [ 'SP' ].concat( $.fn.lcd.defaults.showRegions ),
			onSelect: function ( languageCode ) {
				var languageDetails = mw.translate.getLanguageDetailsForHtml( languageCode );
				mw.translate.changeLanguage( languageCode );
				$element
					.find( '.ext-translate-target-language' )
					.text( languageDetails.autonym )
					.prop( {
						lang: languageDetails.code,
						dir: languageDetails.direction
					} );
			},
			ulsPurpose: 'translate-special-translate',
			quickList: function () {
				return mw.uls.getFrequentLanguageList();
			}
		};

		mw.translate.addExtraLanguagesToLanguageData( ulsOptions.languages, [ 'SP' ] );
		$element.uls( ulsOptions );
	}

	function addTuxGroupWarningContainer() {
		var $tuxEditorHeader = $( '.tux-editor-header' );
		var $tuxWarning = $tuxEditorHeader.find( 'tux-group-warning' );
		if ( !$tuxWarning.length ) {
			$tuxWarning = $( '<div>' )
				.addClass( 'mw-message-box-warning mw-message-box tux-group-warning twelve column' );
			$tuxEditorHeader.append( $tuxWarning );
		}
	}

	function toggleSubscription() {
		var api = new mw.Api();
		var $button = $( this );
		$button.prop( 'disabled', true );

		var subscriptionStatus = $button.data( 'subscribed' );

		var params = {
			action: 'messagegroupsubscription',
			groupId: state.group,
			operation: subscriptionStatus ? 'unsubscribe' : 'subscribe',
			assert: 'user',
			formatversion: 2
		};

		return api.postWithToken( 'csrf', params ).then(
			function ( response ) {
				var oldSubscriptionStatus = subscriptionStatus;
				if ( response.messagegroupsubscription && response.messagegroupsubscription.success === 1 ) {
					var buttonMessage = oldSubscriptionStatus ? 'tux-watch-group' : 'tux-unwatch-group';
					var watchClass = oldSubscriptionStatus ?
						'tux-watch-group--unwatch' : 'tux-watch-group--watch';
					$button
						.removeClass( [ 'tux-watch-group--watch', 'tux-watch-group--unwatch' ] )
						// CSS Classes:
						// * tux-watch-group--watch
						// * tux-watch-group--unwatch
						.addClass( watchClass )
						.data( 'subscribed', !oldSubscriptionStatus );

					$button.find( '.tux-watch-label' )
						// * tux-watch-group
						// * tux-unwatch-group
						.text( mw.msg( buttonMessage ) );

					loadWatchedMessageGroups();
				} else {
					mw.notify( mw.msg( 'tux-subscription-error' ) );
				}
			},
			function ( error ) {
				mw.notify( mw.msg( 'tux-subscription-error' ) );
				mw.log.error( 'messagegroupsubscription: Failed', error, params );
			}
		).always( function () {
			$button.prop( 'disabled', false );
		} );
	}

	function loadWatchedMessageGroups() {
		if ( mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) !== true ) {
			return;
		}

		var api = new mw.Api();
		var params = {
			action: 'query',
			list: 'messagegroupsubscription',
			formatversion: 2
		};

		return api.get( params ).then(
			function ( response ) {
				state.groupSelector.setWatchedGroups( response.query.messagegroupsubscription );
			},
			function ( error ) {
				mw.log.error( 'messagegroupsubscription: Failed to fetch user subscriptions', error, params );
			}
		);
	}

	function showAggregateSubgroupCount() {
		var $groupBreadcrumbs = $( '.tux-breadcrumb .grouptitle' );
		var $selectedGroup = $groupBreadcrumbs.last();
		var groupCounts = $selectedGroup.data( 'msggroup-subgroup-count' );
		if ( groupCounts === undefined ) {
			$groupBreadcrumbs
				.find( '.tux-breadcrumb__item--aggregate-count' )
				.remove();
		} else {
			var subGroups = mw.msg( 'translate-msggroupselector-view-subprojects', groupCounts );
			$selectedGroup.append(
				$( '<span>' ).append( mw.message( 'parentheses', $( '<span>' ).text( subGroups ) ).parse() )
					.addClass( 'tux-breadcrumb__item--aggregate-count' )
			);
		}
	}

	$( function () {
		var $messageList = $( '.tux-messagelist' );
		state.group = $( '.tux-messagetable-loader' ).data( 'messagegroup' );
		state.language = $messageList.data( 'targetlangcode' );
		var uri = new mw.Uri( window.location.href );

		if ( $messageList.length ) {
			$messageList.messagetable();
			state.messageList = $messageList.data( 'messagetable' );

			var filter = uri.query.filter;
			var offset = uri.query.showMessage;
			var limit;
			if ( offset ) {
				limit = uri.query.limit || 1;
				// Default to no filters
				filter = filter || '';
			}

			if ( filter === undefined ) {
				filter = '!translated';
			}

			$( '.tux-message-selector li' ).each( function () {
				var $this = $( this );

				if ( $this.data( 'filter' ) === filter ) {
					$this.addClass( 'selected' );
				}
			} );

			mw.translate.changeUrl( {
				group: state.group,
				language: state.language,
				filter: filter,
				showMessage: offset,
				optional: offset ? 1 : undefined
			} );

			// Start loading messages
			var actualFilter = getActualFilter( filter );
			state.messageList.changeSettings( {
				group: state.group,
				language: state.language,
				offset: offset,
				limit: limit,
				filter: actualFilter
			} );

			if ( actualFilter.indexOf( hideOptionalMessages ) === -1 ) {
				$( '#tux-option-optional' ).prop( 'checked', true );
			}
		}

		addTuxGroupWarningContainer();

		var position = {
			my: 'left top',
			at: 'left-10 bottom+5'
		};
		if ( $( document.body ).hasClass( 'rtl' ) ) {
			position = {
				my: 'right top',
				at: 'right+10 bottom+5'
			};
		}

		$( '.tux-breadcrumb__item--aggregate' ).msggroupselector( {
			onSelect: mw.translate.changeGroup,
			language: state.language,
			position: position,
			recent: mw.translate.recentGroups.get(),
			showWatched: mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) || false,
			menuClass: 'tux-groupselector-tpt'
		} );

		state.groupSelector = $( '.tux-breadcrumb__item--aggregate' ).data( 'msggroupselector' );
		loadWatchedMessageGroups();

		updateGroupInformation( state );

		showAggregateSubgroupCount();

		$( '.ext-translate-language-selector .uls' ).one( 'click', function () {
			var $target = $( this );
			mw.loader.using( 'ext.uls.mediawiki' ).done( function () {
				setupLanguageSelector( $target );
				$target.trigger( 'click' );
			} );
		} ).on( 'keypress', function () {
			$( this ).trigger( 'click' );
		} );

		if ( $.fn.translateeditor ) {
			// New translation editor
			$( '.tux-message' ).translateeditor();
		}

		var $translateContainer = $( '.ext-translate-container' );

		if ( mw.translate.canProofread() ) {
			$translateContainer.find( '.proofread-mode-button' ).removeClass( 'hide' );
		}

		var $hideTranslatedButton = $translateContainer.find( '.tux-editor-clear-translated' );
		$hideTranslatedButton
			.prop( 'disabled', !getTranslatedMessages( $translateContainer ).length )
			.on( 'click', function () {
				getTranslatedMessages( $translateContainer ).remove();
				$( this ).prop( 'disabled', true );
			} );

		// Message filter click handler
		$translateContainer.find( '.row.tux-message-selector > li' ).on( 'click', function () {
			var $this = $( this );

			if ( $this.hasClass( 'more' ) ) {
				return false;
			}

			var newFilter = $this.data( 'filter' );

			// Remove the 'selected' class from all the items.
			// Some of them could have been moved to under the "more" menu,
			// so everything under .row.tux-message-selector is searched.
			$translateContainer.find( '.row.tux-message-selector .selected' )
				.removeClass( 'selected' );
			mw.translate.changeFilter( newFilter );
			$this.addClass( 'selected' );

			var translated = newFilter !== '!translated';
			// TODO: this could should be in messagetable
			$hideTranslatedButton.toggleClass( 'hide', translated )
				.prop( 'disabled', !translated && !getTranslatedMessages( $translateContainer ).length );

			return false;
		} );

		// TODO: this could should be in messagetable
		$hideTranslatedButton
			.toggleClass( 'hide', $( '.tux-messagetable-loader' ).data( 'filter' ) !== '!translated' );

		// Don't let clicking the items in the "more" menu
		// affect the rest of it.
		$( '.row.tux-message-selector .more ul' )
			.on( 'click', function ( e ) {
				e.stopPropagation();
			} );

		$( '#tux-option-optional' ).on( 'change', function () {
			var currentUri = new mw.Uri( window.location.href ),
				checked = $( this ).prop( 'checked' );

			mw.translate.changeUrl( { optional: checked ? 1 : 0 } );
			mw.translate.changeFilter( currentUri.query.filter );
		} );

		getTranslationStats( state.language ).done( function ( stats ) {
			logger.logEvent(
				'interface_open',
				null,
				getActionSource(),
				{
					// eslint-disable-next-line camelcase
					source_lang: $messageList.data( 'sourcelangcode' ),
					// eslint-disable-next-line camelcase
					target_lang: state.language,
					// eslint-disable-next-line camelcase
					source_id: uri.query.group,
					// eslint-disable-next-line camelcase
					source_type: 'page',
					// eslint-disable-next-line camelcase
					translatable_count: stats.total,
					// eslint-disable-next-line camelcase
					translated_count: stats.translated
				}
			);
		} );
	} );

}() );
