import select from 'select-dom';
import linkifyUrls from 'linkify-urls';
import linkifyIssues from 'linkify-issues';
import features from '../libs/features';
import getTextNodes from '../libs/get-text-nodes';
import {getOwnerAndRepo} from '../libs/utils';

// Shared class necessary to avoid also shortening the links
export const linkifiedURLClass = 'rgh-linkified-code';

// If we are not in a repo, relative issue references won't make sense
// but `user`/`repo` need to be set to avoid breaking errors in `linkify-issues`
// https://github.com/sindresorhus/refined-github/issues/1305
const currentRepo = getOwnerAndRepo();
const options = {
	user: currentRepo.ownerName || '/',
	repo: currentRepo.repoName || '/',
	type: 'dom',
	baseUrl: '',
	attributes: {
		rel: 'noreferrer noopener',
		class: linkifiedURLClass // Necessary to avoid also shortening the links
	}
};

export const editTextNodes = (
	fn: typeof linkifyIssues | typeof linkifyUrls,
	el: HTMLElement
): void => {
	for (const textNode of getTextNodes(el)) {
		if (fn === linkifyUrls && textNode.textContent!.length < 11) { // Shortest url: http://j.mp
			continue;
		}

		const linkified = fn(textNode.textContent!, options);
		if (linkified.children.length > 0) { // Children are <a>
			if (fn === linkifyIssues) {
				// Enable native issue title fetch
				for (const link of (linkified.children as HTMLCollectionOf<HTMLAnchorElement>)) {
					const issue = link.href.split('/').pop();
					link.setAttribute('class', 'issue-link js-issue-link tooltipped tooltipped-ne');
					link.setAttribute('data-error-text', 'Failed to load issue title');
					link.setAttribute('data-permission-text', 'Issue title is private');
					link.setAttribute('data-url', link.href);
					link.setAttribute('data-id', `rgh-issue-${issue}`);
				}
			}

			textNode.replaceWith(linkified);
		}
	}
};

function init(): false | void {
	const wrappers = select.all(`
		.blob-wrapper:not(.${linkifiedURLClass}),
		.comment-body:not(.${linkifiedURLClass})
	`);

	// Don't linkify any already linkified code
	if (wrappers.length === 0) {
		return false;
	}

	// Linkify full URLs
	// `.blob-code-inner` in diffs
	// `pre` in GitHub comments
	for (const el of select.all('.blob-code-inner, pre', wrappers)) {
		editTextNodes(linkifyUrls, el);
	}

	// Linkify issue refs in comments
	for (const el of select.all('span.pl-c', wrappers)) {
		editTextNodes(linkifyIssues, el);
	}

	// Mark code block as touched
	for (const el of wrappers) {
		el.classList.add(linkifiedURLClass);
	}
}

features.add({
	id: 'linkify-urls-in-code',
	description: 'Make URLs in code clickable',
	load: features.onAjaxedPages,
	init
});
