let
	LanguageSearcher,
	sandbox;
const
	jQuery = require( '../utils/jQuery' ),
	dom = require( '../utils/dom' ),
	mediaWiki = require( '../utils/mw' ),
	mustache = require( '../utils/mustache' ),
	oo = require( '../utils/oo' ),
	sinon = require( 'sinon' ),
	apiLanguages = [
		{
			lang: 'ar',
			url: 'https://ar.wikipedia.org/wiki/%D8%A8%D8%A7%D8%B1%D8%A7%D9%83_%D8%A3%D9%88%D8%A8%D8%A7%D9%85%D8%A7',
			title: 'باراك أوباما',
			autonym: 'العربية'
		}, {
			lang: 'be',
			url: 'https://be.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',
			title: 'Барак Абама',
			autonym: 'беларуская'
		}, {
			lang: 'be-x-old',
			url: 'https://be-x-old.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',
			title: 'Барак Абама',
			autonym: 'беларуская (тарашкевіца)'
		}, {
			lang: 'ko',
			url: 'https://ko.wikipedia.org/wiki/%EB%B2%84%EB%9D%BD_%EC%98%A4%EB%B0%94%EB%A7%88',
			title: '버락 오바마',
			autonym: '한국어'
		}, {
			lang: 'ru',
			url: 'https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D0%B0%D0%BC%D0%B0,_%D0%91%D0%B0%D1%80%D0%B0%D0%BA',
			title: 'Обама, Барак',
			autonym: 'русский'
		}, {
			lang: 'uz',
			url: 'https://uz.wikipedia.org/wiki/Barak_Obama',
			title: 'Barak Obama',
			autonym: 'oʻzbekcha/ўзбекча'
		}, {
			lang: 'zh',
			url: 'https://zh.wikipedia.org/wiki/%E8%B4%9D%E6%8B%89%E5%85%8B%C2%B7%E5%A5%A5%E5%B7%B4%E9%A9%AC',
			title: '贝拉克·奥巴马',
			autonym: '中文'
		}, {
			lang: 'zh-min-nan',
			url: 'https://zh-min-nan.wikipedia.org/wiki/Barack_Obama',
			title: 'Barack Obama',
			langname: 'Chinese',
			autonym: 'Bân-lâm-gú'
		}, {
			lang: 'zh-yue',
			url: 'https://zh-yue.wikipedia.org/wiki/%E5%A5%A7%E5%B7%B4%E9%A6%AC',
			title: '奧巴馬',
			autonym: '粵語'
		}, {
			lang: 'zu',
			url: 'https://zu.wikipedia.org/wiki/Barack_Obama',
			title: 'Barack Obama',
			autonym: 'isiZulu'
		}
	],
	deviceLanguage = 'en-us',
	variants = [
		{
			lang: 'foo',
			url: '/w/index.php?title=Barack_Obama&variant=foo',
			autonym: 'Foo'
		},
		{
			lang: 'foo-x-piglatin',
			url: '/w/index.php?title=Barack_Obama&variant=foo-x-piglatin',
			autonym: 'Igpay Atinlay'
		}
	],
	frequentlyUsedLanguages = {
		'zh-min-nan': 1,
		zh: 2,
		en: 10,
		ko: 1
	};

function enterText( searcher, text ) {
	searcher.$el.find( 'input[type=search]' ).val( text ).trigger( 'input' );
}

QUnit.module( 'MobileFrontend LanguageSearcher.js', {
	beforeEach: function () {
		sandbox = sinon.sandbox.create();
		dom.setUp( sandbox, global );
		jQuery.setUp( sandbox, global );
		oo.setUp( sandbox, global );
		mediaWiki.setUp( sandbox, global );
		mustache.setUp( sandbox, global );

		LanguageSearcher = require( '../../../src/mobile.languages.structured/LanguageSearcher' );

		mw.util.escapeRegExp = ( str ) => str;
		sandbox.stub( mw.storage, 'get' ).withArgs( 'langMap' )
			.returns( JSON.stringify( frequentlyUsedLanguages ) );

		this.languageSearcher = new LanguageSearcher( {
			languages: apiLanguages,
			variants: variants,
			showSuggestedLanguages: true,
			deviceLanguage: deviceLanguage
		} );
	},
	afterEach: function () {
		jQuery.tearDown();
		sandbox.restore();
	}
} );

QUnit.test( 'renders output', function ( assert ) {
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list.suggested-languages a' ).length,
		5,
		'There are 5 suggested languages including variants.'
	);

	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list.all-languages a' ).length,
		7,
		'Seven languages are non-suggested.'
	);
} );

QUnit.test( 'saves the language count when link is clicked', function ( assert ) {
	const stub = sandbox.stub( mw.storage, 'set' );

	this.languageSearcher.$el.find( '[lang=foo-x-piglatin]' ).trigger( 'click' );

	assert.strictEqual( stub.callCount, 1, 'mw.storage.set is called once' );
	assert.deepEqual(
		stub.getCall( 0 ).args,
		[ 'langMap', '{"zh-min-nan":1,"zh":2,"en":10,"ko":1,"foo-x-piglatin":1}' ],
		'mw.storage.set is called with correct args'
	);
} );

QUnit.test( 'without variants, input event filters languages', function ( assert ) {
	const languageSearcher = new LanguageSearcher( {
		languages: apiLanguages,
		variants: false,
		showSuggestedLanguages: true,
		deviceLanguage: deviceLanguage
	} );

	enterText( languageSearcher, '' );
	assert.strictEqual(
		languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		10,
		'The search filter has been cleared. All 10 languages (including variants) are visible.'
	);

	enterText( languageSearcher, 'abcdefghij' );
	assert.strictEqual(
		languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		0,
		'No languages match "abcdefghij"'
	);

	enterText( languageSearcher, 'chin' );
	assert.true(
		languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&
		languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'zh-min-nan' ),
		'One language (zh-min-nan) matches "Chin" (langname) and only that language is visible.'
	);
} );

QUnit.test( 'with variants, input event filters languages', function ( assert ) {
	enterText( this.languageSearcher, '' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		12,
		'The search filter has been cleared. All 12 languages (including variants) are visible.'
	);

	enterText( this.languageSearcher, 'abcdefghij' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		0,
		'No languages match "abcdefghij"'
	);

	enterText( this.languageSearcher, 'zh' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		3,
		'Three languages match "zh" and only those languages are visible.'
	);

	enterText( this.languageSearcher, 'ol' );
	assert.true(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'be-x-old' ),
		'One language (be-x-old) matches "ol" and only that language is visible.'
	);

	enterText( this.languageSearcher, 'chin' );
	assert.true(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'zh-min-nan' ),
		'One language (zh-min-nan) matches "Chin" (langname) and only that language is visible.'
	);

	enterText( this.languageSearcher, 'ўз' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		1,
		'One language matches "ўз" and only that language is visible.'
	);

	enterText( this.languageSearcher, 'foo' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		2,
		'Two languages match "foo" and only those languages are visible.'
	);

	enterText( this.languageSearcher, 'igpay' );
	assert.strictEqual(
		this.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,
		1,
		'One language matches "igpay" and only that language is visible.'
	);
} );
