define(['showdown', 'citation'], function (showdown, citation) {
	return showdown.extension('showdown-citation', function() {
		const Cite = citationRequire('citation-js');
		var allCites = new Cite();
		// set up a custom CSL template so that we can use apa style without the url at the end.
		// for DOI's, we add this url manually so that it can have a  tag (not supported in CSL)
		let templateName = 'apa-no-url'
		// the docs for citation.js indicate that the CSL should go right into the doc as so.
		// TODO: figure out a better way to import this.
		let template = ''+
		''
		let config = Cite.plugins.config.get('csl');
		config.templates.add(templateName, template);
		var subbib = function(bibobj, keyarr) {
			let filtered = _.filter(bibobj.data, function(item) {
				return keyarr.includes(item['citation-label']);
			});
			return Cite(filtered);
		};
		var not_in_bib = function(bibobj, keyarr) {
			// Return an array containing the elements of `keyarr` that are not
			// matched by entries in `bibobj`
			let labels = bibobj.data.map(d => d['citation-label']);
			let filtered = _.filter(keyarr, function(item) {
				return !labels.includes(item);
			});
			return filtered;
		};
		var read_bibli = {
			// This sub-extension will look for bibtex, wrapped in  tags.
			// When found, they'll be added to the cite object.
			type: "lang",
			filter: function (text, converter, options) {
				var left = '',
				right = '',
				flags = 'g',
				replacement = function (wholeMatch, match, left, right) {
					let citeInfo = new Cite(wholeMatch.replace(/<\/*bibtex>/g, ''));
					// add citation data to "master list" of references
					// (automatically sorts and removes duplicates)
					allCites.add(citeInfo.data);
				};
				return showdown.helper.replaceRecursiveRegExp(text, replacement, left, right, flags);
			}
		};
		var print_bibli = {
			type: "output",
			filter: function(text){
				if(allCites.data.length > 0){
					// make bibliography
					var citeBib = allCites.format('bibliography', {
						format: 'html',
						template: templateName,
						lang: 'en-US',
						append: function (entry) {
							var doi = entry.DOI;
							if (typeof doi === 'undefined' || doi === null){
								return ""
							} else {
								return "  doi:" + doi + ""
							}
						}
					})
					// add in id attributes so we can hack in a link from the inline cite
					citeBib = citeBib.replace(/(data-csl-entry-id="([^"]+)")/g, 'id="$2" $1');
					return ( text + "
Bibliography
" + citeBib );
				} else {
					return ( text );
				}
			}
		};
		var print_inline_cites = {
			type: "lang",
			filter: function(text) {
				var left = '\\[(@[^\\]]+)',
				right = '\\]',
				flags = 'g',
				replacement = function(wholeMatch, match, left, right) {
					// let keys = wholeMatch.replace(/<\/*inlinecite>/g, '').split(";");
					let keys = wholeMatch.replace(/[@\[\]\s]*/g, '').split(",");
					let subcites = subbib(allCites, keys);
					let citestring =  subcites.format('citation', {
						format: 'html',
						template: templateName,
						lang: 'en-US',
					});
					if (subcites.data.length == 0) {
						// none of the keys handed in matched anything in the bib.
						// We'll just hand back the keys in parentheses
						citestring = "(" + keys.join("; ").replace(/_/g, "\\_") + ")";
					} else if (subcites.data.length < keys.length) {
						// At least one of the keys found a match, but not all keys
						// We'll insert the not found keys into the citation
						let nope = not_in_bib(allCites, keys).join("; ").replace(/_/g, "\\_");
						citestring = citestring.replace(/([^)]*)\)/g, "$1; " + nope + ")");
					}
					// Now we have to deal with a hacky work around to get links to the bibliography
					citestring = citestring.replace(/labelisinhere([^@]*)@labelisinhere/g, '');
					citestring = citestring.replace(/endtheanchortaghere/g, '');
					return citestring;
				}
				return showdown.helper.replaceRecursiveRegExp(text, replacement, left, right, flags);
			},
		};
		return [read_bibli, print_inline_cites, print_bibli];
	});
});