const fs = require( 'fs' );
const path = require( 'path' );
const { CodeMirrorMediaWiki } = require( '../../../resources/modes/mediawiki/codemirror.mediawiki.js' );
const tests = require( '../parser/tests.json' );

const mwConfig = {
	doubleUnderscore: [
		{
			__notoc__: 'notoc',
			__nogallery__: 'nogallery',
			__forcetoc__: 'forcetoc',
			__toc__: 'toc',
			__noeditsection__: 'noeditsection',
			__notitleconvert__: 'notitleconvert',
			__notc__: 'notc',
			__nocontentconvert__: 'nocontentconvert',
			__nocc__: 'nocc',
			__archivedtalk__: 'archivedtalk',
			__notalk__: 'notalk'
		},
		{
			__NEWSECTIONLINK__: 'newsectionlink',
			__NONEWSECTIONLINK__: 'nonewsectionlink',
			__HIDDENCAT__: 'hiddencat',
			__EXPECTUNUSEDCATEGORY__: 'expectunusedcategory',
			__EXPECTUNUSEDTEMPLATE__: 'expectunusedtemplate',
			__INDEX__: 'index',
			__NOINDEX__: 'noindex',
			__STATICREDIRECT__: 'staticredirect',
			__NOGLOBAL__: 'noglobal',
			__DISAMBIG__: 'disambig',
			__EXPECTED_UNCONNECTED_PAGE__: 'expected_unconnected_page'
		}
	],
	functionHooks: [
		'ns',
		'nse',
		'urlencode',
		'lcfirst',
		'ucfirst',
		'lc',
		'uc',
		'localurl',
		'localurle',
		'fullurl',
		'fullurle',
		'canonicalurl',
		'canonicalurle',
		'formatnum',
		'grammar',
		'gender',
		'plural',
		'formal',
		'bidi',
		'numberingroup',
		'language',
		'padleft',
		'padright',
		'anchorencode',
		'defaultsort',
		'filepath',
		'pagesincategory',
		'pagesize',
		'protectionlevel',
		'protectionexpiry',
		'pagename',
		'pagenamee',
		'fullpagename',
		'fullpagenamee',
		'subpagename',
		'subpagenamee',
		'rootpagename',
		'rootpagenamee',
		'basepagename',
		'basepagenamee',
		'talkpagename',
		'talkpagenamee',
		'subjectpagename',
		'subjectpagenamee',
		'pageid',
		'revisionid',
		'revisionday',
		'revisionday2',
		'revisionmonth',
		'revisionmonth1',
		'revisionyear',
		'revisiontimestamp',
		'revisionuser',
		'cascadingsources',
		'namespace',
		'namespacee',
		'namespacenumber',
		'talkspace',
		'talkspacee',
		'subjectspace',
		'subjectspacee',
		'numberofarticles',
		'numberoffiles',
		'numberofusers',
		'numberofactiveusers',
		'numberofpages',
		'numberofadmins',
		'numberofedits',
		'bcp47',
		'dir',
		'interwikilink',
		'interlanguagelink',
		'contentmodel',
		'int',
		'special',
		'speciale',
		'tag',
		'formatdate',
		'displaytitle',
		'if',
		'ifeq',
		'switch',
		'ifexist',
		'ifexpr',
		'iferror',
		'time',
		'timel',
		'timef',
		'timefl',
		'expr',
		'rel2abs',
		'titleparts',
		'pendingchangelevel',
		'categorytree',
		'lst',
		'lstx',
		'lsth',
		'target',
		'babel',
		'coordinates',
		'invoke',
		'related',
		'noexternallanglinks',
		'shortdesc',
		'property',
		'statements',
		'commaseparatedlist',
		'assessment',
		'chart',
		'mentor',
		'msgnw'
	],
	functionSynonyms: [
		{
			ns: 'ns',
			nse: 'nse',
			urlencode: 'urlencode',
			lcfirst: 'lcfirst',
			ucfirst: 'ucfirst',
			lc: 'lc',
			uc: 'uc',
			localurl: 'localurl',
			localurle: 'localurle',
			fullurl: 'fullurl',
			fullurle: 'fullurle',
			canonicalurl: 'canonicalurl',
			canonicalurle: 'canonicalurle',
			formatnum: 'formatnum',
			grammar: 'grammar',
			gender: 'gender',
			plural: 'plural',
			bidi: 'bidi',
			'#language': 'language',
			padleft: 'padleft',
			padright: 'padright',
			anchorencode: 'anchorencode',
			filepath: 'filepath',
			pageid: 'pageid',
			int: 'int',
			'#special': 'special',
			'#speciale': 'speciale',
			'#tag': 'tag',
			'#formatdate': 'formatdate',
			'#dateformat': 'formatdate',
			'#if': 'if',
			'#ifeq': 'ifeq',
			'#switch': 'switch',
			'#ifexist': 'ifexist',
			'#ifexpr': 'ifexpr',
			'#iferror': 'iferror',
			'#time': 'time',
			'#timel': 'timel',
			'#expr': 'expr',
			'#rel2abs': 'rel2abs',
			'#titleparts': 'titleparts',
			pendingchangelevel: 'pendingchangelevel',
			'#categorytree': 'categorytree',
			'#lst': 'lst',
			'#section': 'lst',
			'#lstx': 'lstx',
			'#section-x': 'lstx',
			'#lsth': 'lsth',
			'#section-h': 'lsth',
			'#target': 'target',
			'#babel': 'babel',
			'#coordinates': 'coordinates',
			'#invoke': 'invoke',
			'#related': 'related',
			noexternallanglinks: 'noexternallanglinks',
			'#property': 'property',
			'#statements': 'statements',
			'#commaseparatedlist': 'commaseparatedlist',
			'#assessment': 'assessment',
			'#chart': 'chart',
			'#mentor': 'mentor',
			articlepath: 'articlepath',
			server: 'server',
			servername: 'servername',
			scriptpath: 'scriptpath',
			stylepath: 'stylepath',
			numberofwikis: 'numberofwikis',
			wbreponame: 'wbreponame',
			msgnw: 'msgnw'
		},
		{
			'#FORMAL': 'formal',
			NUMBERINGROUP: 'numberingroup',
			NUMINGROUP: 'numberingroup',
			DEFAULTSORT: 'defaultsort',
			DEFAULTSORTKEY: 'defaultsort',
			DEFAULTCATEGORYSORT: 'defaultsort',
			PAGESINCATEGORY: 'pagesincategory',
			PAGESINCAT: 'pagesincategory',
			PAGESIZE: 'pagesize',
			PROTECTIONLEVEL: 'protectionlevel',
			PROTECTIONEXPIRY: 'protectionexpiry',
			PAGENAME: 'pagename',
			PAGENAMEE: 'pagenamee',
			FULLPAGENAME: 'fullpagename',
			FULLPAGENAMEE: 'fullpagenamee',
			SUBPAGENAME: 'subpagename',
			SUBPAGENAMEE: 'subpagenamee',
			ROOTPAGENAME: 'rootpagename',
			ROOTPAGENAMEE: 'rootpagenamee',
			BASEPAGENAME: 'basepagename',
			BASEPAGENAMEE: 'basepagenamee',
			TALKPAGENAME: 'talkpagename',
			TALKPAGENAMEE: 'talkpagenamee',
			SUBJECTPAGENAME: 'subjectpagename',
			ARTICLEPAGENAME: 'subjectpagename',
			SUBJECTPAGENAMEE: 'subjectpagenamee',
			ARTICLEPAGENAMEE: 'subjectpagenamee',
			REVISIONID: 'revisionid',
			REVISIONDAY: 'revisionday',
			REVISIONDAY2: 'revisionday2',
			REVISIONMONTH: 'revisionmonth',
			REVISIONMONTH1: 'revisionmonth1',
			REVISIONYEAR: 'revisionyear',
			REVISIONTIMESTAMP: 'revisiontimestamp',
			REVISIONUSER: 'revisionuser',
			CASCADINGSOURCES: 'cascadingsources',
			NAMESPACE: 'namespace',
			NAMESPACEE: 'namespacee',
			NAMESPACENUMBER: 'namespacenumber',
			TALKSPACE: 'talkspace',
			TALKSPACEE: 'talkspacee',
			SUBJECTSPACE: 'subjectspace',
			ARTICLESPACE: 'subjectspace',
			SUBJECTSPACEE: 'subjectspacee',
			ARTICLESPACEE: 'subjectspacee',
			NUMBEROFARTICLES: 'numberofarticles',
			NUMBEROFFILES: 'numberoffiles',
			NUMBEROFUSERS: 'numberofusers',
			NUMBEROFACTIVEUSERS: 'numberofactiveusers',
			NUMBEROFPAGES: 'numberofpages',
			NUMBEROFADMINS: 'numberofadmins',
			NUMBEROFEDITS: 'numberofedits',
			'#bcp47': 'bcp47',
			'#dir': 'dir',
			'#interwikilink': 'interwikilink',
			'#interlanguagelink': 'interlanguagelink',
			'#contentmodel': 'contentmodel',
			DISPLAYTITLE: 'displaytitle',
			'#timef': 'timef',
			'#timefl': 'timefl',
			SHORTDESC: 'shortdesc',
			'!': '!',
			'=': '=',
			CURRENTMONTH: 'currentmonth',
			CURRENTMONTH2: 'currentmonth',
			CURRENTMONTH1: 'currentmonth1',
			CURRENTMONTHNAME: 'currentmonthname',
			CURRENTMONTHNAMEGEN: 'currentmonthnamegen',
			CURRENTMONTHABBREV: 'currentmonthabbrev',
			CURRENTDAY: 'currentday',
			CURRENTDAY2: 'currentday2',
			CURRENTDAYNAME: 'currentdayname',
			CURRENTYEAR: 'currentyear',
			CURRENTTIME: 'currenttime',
			CURRENTHOUR: 'currenthour',
			LOCALMONTH: 'localmonth',
			LOCALMONTH2: 'localmonth',
			LOCALMONTH1: 'localmonth1',
			LOCALMONTHNAME: 'localmonthname',
			LOCALMONTHNAMEGEN: 'localmonthnamegen',
			LOCALMONTHABBREV: 'localmonthabbrev',
			LOCALDAY: 'localday',
			LOCALDAY2: 'localday2',
			LOCALDAYNAME: 'localdayname',
			LOCALYEAR: 'localyear',
			LOCALTIME: 'localtime',
			LOCALHOUR: 'localhour',
			SITENAME: 'sitename',
			CURRENTWEEK: 'currentweek',
			CURRENTDOW: 'currentdow',
			LOCALWEEK: 'localweek',
			LOCALDOW: 'localdow',
			REVISIONSIZE: 'revisionsize',
			CURRENTVERSION: 'currentversion',
			CURRENTTIMESTAMP: 'currenttimestamp',
			LOCALTIMESTAMP: 'localtimestamp',
			DIRECTIONMARK: 'directionmark',
			DIRMARK: 'directionmark',
			CONTENTLANGUAGE: 'contentlanguage',
			CONTENTLANG: 'contentlanguage',
			USERLANGUAGE: 'userlanguage',
			PAGELANGUAGE: 'pagelanguage'
		}
	],
	imageKeywords: {
		'alt=$1': 'alt',
		baseline: 'baseline',
		border: 'border',
		bottom: 'bottom',
		center: 'center',
		centre: 'center',
		'class=$1': 'class',
		frame: 'framed',
		framed: 'framed',
		enframed: 'framed',
		frameless: 'frameless',
		'lang=$1': 'lang',
		left: 'left',
		'link=$1': 'link',
		'thumbnail=$1': 'manualthumb',
		'thumb=$1': 'manualthumb',
		middle: 'middle',
		none: 'none',
		'page=$1': 'page',
		'page $1': 'page',
		right: 'right',
		sub: 'sub',
		super: 'super',
		sup: 'super',
		'text-bottom': 'text-bottom',
		'text-top': 'text-top',
		thumb: 'thumbnail',
		thumbnail: 'thumbnail',
		top: 'top',
		upright: 'upright',
		'upright=$1': 'upright',
		'upright $1': 'upright',
		$1px: 'width'
	},
	redirection: [
		'#REDIRECT'
	],
	subst: {
		'SAFESUBST:': 'safesubst',
		'SUBST:': 'subst'
	},
	tagModes: {
		nowiki: 'mw-tag-nowiki',
		pre: 'mw-tag-pre',
		indicator: 'mediawiki',
		ref: 'text/mediawiki',
		references: 'text/mediawiki'
	},
	tags: {
		pre: true,
		nowiki: true,
		gallery: true,
		indicator: true,
		langconvert: true,
		graph: true,
		timeline: true,
		hiero: true,
		charinsert: true,
		ref: true,
		references: true,
		inputbox: true,
		imagemap: true,
		source: true,
		syntaxhighlight: true,
		poem: true,
		categorytree: true,
		section: true,
		score: true,
		templatestyles: true,
		templatedata: true,
		math: true,
		ce: true,
		chem: true,
		maplink: true,
		mapframe: true,
		'page-collection': true,
		phonos: true,
		dynamicpagelist: true,
		translate: true,
		tvar: true
	},
	urlProtocols: 'bitcoin\\:|ftp\\:\\/\\/|ftps\\:\\/\\/|geo\\:|git\\:\\/\\/|gopher\\:\\/\\/|http\\:\\/\\/|https\\:\\/\\/|irc\\:\\/\\/|ircs\\:\\/\\/|magnet\\:|mailto\\:|matrix\\:|mms\\:\\/\\/|news\\:|nntp\\:\\/\\/|redis\\:\\/\\/|sftp\\:\\/\\/|sip\\:|sips\\:|sms\\:|ssh\\:\\/\\/|svn\\:\\/\\/|tel\\:|telnet\\:\\/\\/|urn\\:|wikipedia\\:\\/\\/|worldwind\\:\\/\\/|xmpp\\:|//',
	variableIDs: [
		'!',
		'=',
		'currentmonth',
		'currentmonth1',
		'currentmonthname',
		'currentmonthnamegen',
		'currentmonthabbrev',
		'currentday',
		'currentday2',
		'currentdayname',
		'currentyear',
		'currenttime',
		'currenthour',
		'localmonth',
		'localmonth1',
		'localmonthname',
		'localmonthnamegen',
		'localmonthabbrev',
		'localday',
		'localday2',
		'localdayname',
		'localyear',
		'localtime',
		'localhour',
		'numberofarticles',
		'numberoffiles',
		'numberofedits',
		'articlepath',
		'pageid',
		'sitename',
		'server',
		'servername',
		'scriptpath',
		'stylepath',
		'pagename',
		'pagenamee',
		'fullpagename',
		'fullpagenamee',
		'namespace',
		'namespacee',
		'namespacenumber',
		'currentweek',
		'currentdow',
		'localweek',
		'localdow',
		'revisionid',
		'revisionday',
		'revisionday2',
		'revisionmonth',
		'revisionmonth1',
		'revisionyear',
		'revisiontimestamp',
		'revisionuser',
		'revisionsize',
		'subpagename',
		'subpagenamee',
		'talkspace',
		'talkspacee',
		'subjectspace',
		'subjectspacee',
		'talkpagename',
		'talkpagenamee',
		'subjectpagename',
		'subjectpagenamee',
		'numberofusers',
		'numberofactiveusers',
		'numberofpages',
		'currentversion',
		'rootpagename',
		'rootpagenamee',
		'basepagename',
		'basepagenamee',
		'currenttimestamp',
		'localtimestamp',
		'directionmark',
		'contentlanguage',
		'userlanguage',
		'pagelanguage',
		'numberofadmins',
		'cascadingsources',
		'bcp47',
		'contentmodel',
		'dir',
		'language',
		'numberofwikis',
		'pendingchangelevel',
		'noexternallanglinks',
		'wbreponame'
	]
};
const { parser } = new CodeMirrorMediaWiki( mwConfig ).language;

const results = [];
describe( 'Parser tests', () => {
	for ( const { desc, wikitext } of tests ) {
		it( desc, () => {
			const tree = parser.parse( wikitext ),
				nodes = [];
			tree.iterate( {
				enter( node ) {
					if ( node.name === 'Document' ) {
						return;
					}
					const name = node.name.replace( /_+/g, ' ' ).trim();
					if ( name ) {
						nodes.push( {
							text: wikitext.slice( node.from, node.to ),
							name
						} );
					}
				}
			} );
			const result = { desc, wikitext, nodes };
			results.push( result );
			try {
				expect( nodes ).toEqual( tests.find( ( { desc: d } ) => desc === d ).nodes );
			} catch ( e ) {
				e.cause = { message: `\n${ wikitext }` };
				throw e;
			}
		} );
	}
	afterAll( () => {
		if ( process.env.UPDATE_PARSER_TESTS ) {
			fs.writeFileSync(
				path.join( 'tests', 'jest', 'parser', 'tests.json' ),
				`${ JSON.stringify( results, null, '\t' ) }\n`
			);
		}
	} );
} );
