import React from 'dom-chef';
import select from 'select-dom';
import zipTextNodes from 'zip-text-nodes';
import {applyToLink} from 'shorten-repo-url';
import linkifyURLsCore from 'linkify-urls';
import linkifyIssuesCore from 'linkify-issues';

import getTextNodes from '../helpers/get-text-nodes.js';
import parseBackticksCore from './parse-backticks.js';
import {buildRepoURL} from './index.js';

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

export const codeElementsSelector = [
	'.blob-code-inner', // Code lines
	':not(.notranslate) > .notranslate', // Code blocks in comments. May be wrapped twice
];

export function shortenLink(link: HTMLAnchorElement): void {
	// Exclude the link if the closest element found is not `.comment-body`
	// This avoids shortening links in code and code suggestions, but still shortens them in review comments
	// https://github.com/refined-github/refined-github/pull/4759#discussion_r702460890
	if (link.closest([...codeElementsSelector, '.comment-body'])?.classList.contains('comment-body')) {
		applyToLink(link, location.href);
	}
}

export function linkifyIssues(
	currentRepo: {owner?: string; name?: string},
	element: Element,
	options: Partial<linkifyIssuesCore.TypeDomOptions> = {},
): void {
	const linkified = linkifyIssuesCore(element.textContent!, {
		user: currentRepo.owner ?? '/',
		repository: currentRepo.name ?? '/',
		type: 'dom',
		baseUrl: '',
		...options,
		attributes: {
			class: linkifiedURLClass, // Necessary to avoid also shortening the links
			...options.attributes,
		},
	});
	if (linkified.children.length === 0) { // Children are <a>
		return;
	}

	// 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');
		link.dataset.errorText = 'Failed to load title';
		link.dataset.permissionText = 'Title is private';
		link.dataset.url = link.href;
		link.dataset.id = `rgh-issue-${issue!}`;
		link.dataset.hovercardType = 'issue';
		link.dataset.hovercardUrl = `${link.pathname}/hovercard`;
	}

	zipTextNodes(element, linkified);
}

export function linkifyURLs(element: Element): Element[] | void {
	if (element.textContent!.length < 15) { // Must be long enough for a URL
		return;
	}

	if (select.exists(linkifiedURLSelector, element)) {
		return select.all(linkifiedURLSelector, element);
	}

	const linkified = linkifyURLsCore(element.textContent!, {
		type: 'dom' as const,
		attributes: {
			rel: 'noreferrer noopener',
			class: linkifiedURLClass, // Necessary to avoid also shortening the links
		},
	});

	if (linkified.children.length === 0) { // Children are <a>
		return;
	}

	zipTextNodes(element, linkified);
}

export function parseBackticks(element: Element): void {
	for (const node of getTextNodes(element)) {
		const fragment = parseBackticksCore(node.textContent!);

		if (fragment.children.length > 0) {
			node.replaceWith(fragment);
		}
	}
}

export function linkifyCommit(sha: string): JSX.Element {
	// Data attributes copied from the commit in https://github.com/refined-github/github-url-detection/releases/tag/v7.1.2
	return (
		<code>
			<a
				className="Link--secondary"
				href={buildRepoURL('commit', sha)}
				data-hovercard-type="commit"
				data-hovercard-url={buildRepoURL('commit', sha, 'hovercard')}
			>
				{sha.slice(0, 7)}
			</a>
		</code>
	);
}
s'>derrick/fix/node-tests</option>
<option value='derrick/test/add-ed25519-tests'>derrick/test/add-ed25519-tests</option>
<option value='detect-libc'>detect-libc</option>
<option value='doc/0.8'>doc/0.8</option>
<option value='dylan/callback-fulfilled-after-rejection'>dylan/callback-fulfilled-after-rejection</option>
<option value='dylan/change-pathname-assert'>dylan/change-pathname-assert</option>
<option value='dylan/cli-fixes'>dylan/cli-fixes</option>
<option value='dylan/encoding-fix'>dylan/encoding-fix</option>
<option value='dylan/fix-bundling-lodash-es-is-buffer'>dylan/fix-bundling-lodash-es-is-buffer</option>
<option value='dylan/fix-error-inlining'>dylan/fix-error-inlining</option>
<option value='dylan/fix-module-field-in-exports'>dylan/fix-module-field-in-exports</option>
<option value='dylan/github-api-option' selected='selected'>dylan/github-api-option</option>
<option value='dylan/github-dependencies'>dylan/github-dependencies</option>
<option value='dylan/import-file-path'>dylan/import-file-path</option>
<option value='dylan/non-enumerable-export-values'>dylan/non-enumerable-export-values</option>
<option value='dylan/resolve-rope-in-string'>dylan/resolve-rope-in-string</option>
<option value='dylan/set-exit-code'>dylan/set-exit-code</option>
<option value='dylan/source-map-names-property'>dylan/source-map-names-property</option>
<option value='eventstream'>eventstream</option>
<option value='feat/ecosystem'>feat/ecosystem</option>
<option value='feat/npm'>feat/npm</option>
<option value='fix'>fix</option>
<option value='fix-prepare-stack-trace'>fix-prepare-stack-trace</option>
<option value='fix-websocket-upgrade'>fix-websocket-upgrade</option>
<option value='fs-watch-file'>fs-watch-file</option>
<option value='got'>got</option>
<option value='guides-3'>guides-3</option>
<option value='improve-docker'>improve-docker</option>
<option value='insensitive-pkg-names'>insensitive-pkg-names</option>
<option value='integration-tests'>integration-tests</option>
<option value='jarred/5859'>jarred/5859</option>
<option value='jarred/actions'>jarred/actions</option>
<option value='jarred/add-git'>jarred/add-git</option>
<option value='jarred/analytics'>jarred/analytics</option>
<option value='jarred/arenas'>jarred/arenas</option>
<option value='jarred/ast'>jarred/ast</option>
<option value='jarred/ast-again'>jarred/ast-again</option>
<option value='jarred/async_bio'>jarred/async_bio</option>
<option value='jarred/bench'>jarred/bench</option>
<option value='jarred/brotli'>jarred/brotli</option>
<option value='jarred/bump-uws'>jarred/bump-uws</option>
<option value='jarred/bundle-workspace-packages'>jarred/bundle-workspace-packages</option>
<option value='jarred/bunfig'>jarred/bunfig</option>
<option value='jarred/callable'>jarred/callable</option>
<option value='jarred/canvas'>jarred/canvas</option>
<option value='jarred/ci-check'>jarred/ci-check</option>
<option value='jarred/cjs2'>jarred/cjs2</option>
<option value='jarred/cleanup-error'>jarred/cleanup-error</option>
<option value='jarred/clipboard-objc'>jarred/clipboard-objc</option>
<option value='jarred/direct'>jarred/direct</option>
<option value='jarred/dump'>jarred/dump</option>
<option value='jarred/edgecase'>jarred/edgecase</option>
<option value='jarred/esbuild-plugin-api'>jarred/esbuild-plugin-api</option>
<option value='jarred/escapeHTML'>jarred/escapeHTML</option>
<option value='jarred/esm-conditions'>jarred/esm-conditions</option>
<option value='jarred/experiment-bsp'>jarred/experiment-bsp</option>
<option value='jarred/export-star-flat'>jarred/export-star-flat</option>
<option value='jarred/exports-map'>jarred/exports-map</option>
<option value='jarred/faster-error-capturestacktrace'>jarred/faster-error-capturestacktrace</option>
<option value='jarred/faster-ordered-properties'>jarred/faster-ordered-properties</option>
<option value='jarred/fastmalloc'>jarred/fastmalloc</option>
<option value='jarred/fetch-experiment'>jarred/fetch-experiment</option>
<option value='jarred/fetchheaders'>jarred/fetchheaders</option>
<option value='jarred/fix-blob-slice-test'>jarred/fix-blob-slice-test</option>
<option value='jarred/fix-bunbun-on-wsl'>jarred/fix-bunbun-on-wsl</option>
<option value='jarred/fix-crash'>jarred/fix-crash</option>
<option value='jarred/fix-http-compression'>jarred/fix-http-compression</option>
<option value='jarred/fix-issue-with-tsconfig-run'>jarred/fix-issue-with-tsconfig-run</option>
<option value='jarred/fix-proxy-regression'>jarred/fix-proxy-regression</option>
<option value='jarred/fixes-3129'>jarred/fixes-3129</option>
<option value='jarred/gen'>jarred/gen</option>
<option value='jarred/htmlrewriter'>jarred/htmlrewriter</option>
<option value='jarred/improve-testing'>jarred/improve-testing</option>
<option value='jarred/inquirer'>jarred/inquirer</option>
<option value='jarred/isolation'>jarred/isolation</option>
<option value='jarred/jsc'>jarred/jsc</option>
<option value='jarred/land'>jarred/land</option>
<option value='jarred/landing'>jarred/landing</option>
<option value='jarred/linux'>jarred/linux</option>
<option value='jarred/live-bindings'>jarred/live-bindings</option>
<option value='jarred/make-strings-better'>jarred/make-strings-better</option>
<option value='jarred/mdx-thrwawy'>jarred/mdx-thrwawy</option>
<option value='jarred/move'>jarred/move</option>
<option value='jarred/napi'>jarred/napi</option>
<option value='jarred/new-bund'>jarred/new-bund</option>
<option value='jarred/new-bund-ressurected-branch'>jarred/new-bund-ressurected-branch</option>
<option value='jarred/new-http'>jarred/new-http</option>
<option value='jarred/no-more-npm'>jarred/no-more-npm</option>
<option value='jarred/package-mapper'>jarred/package-mapper</option>
<option value='jarred/pg'>jarred/pg</option>
<option value='jarred/port'>jarred/port</option>
<option value='jarred/possibly-2732'>jarred/possibly-2732</option>
<option value='jarred/postgresql'>jarred/postgresql</option>
<option value='jarred/precompile-linux-dependencies'>jarred/precompile-linux-dependencies</option>
<option value='jarred/prepare-for-libuv'>jarred/prepare-for-libuv</option>
<option value='jarred/profiled-call'>jarred/profiled-call</option>
<option value='jarred/read-tsconfig-jsx'>jarred/read-tsconfig-jsx</option>
<option value='jarred/redo-evaluation-order'>jarred/redo-evaluation-order</option>
<option value='jarred/redo-zigstring-for-utf16'>jarred/redo-zigstring-for-utf16</option>
<option value='jarred/relay'>jarred/relay</option>
<option value='jarred/rename'>jarred/rename</option>
<option value='jarred/repl'>jarred/repl</option>
<option value='jarred/request-finalizer'>jarred/request-finalizer</option>
<option value='jarred/rewrite-router'>jarred/rewrite-router</option>
<option value='jarred/run'>jarred/run</option>
<option value='jarred/simdjson'>jarred/simdjson</option>
<option value='jarred/simplify'>jarred/simplify</option>
<option value='jarred/some-fixes-for-eventsource'>jarred/some-fixes-for-eventsource</option>
<option value='jarred/standalone-repro1'>jarred/standalone-repro1</option>
<option value='jarred/start'>jarred/start</option>
<option value='jarred/strong'>jarred/strong</option>
<option value='jarred/subprocess'>jarred/subprocess</option>
<option value='jarred/support-tee'>jarred/support-tee</option>
<option value='jarred/tcc'>jarred/tcc</option>
<option value='jarred/throw-if'>jarred/throw-if</option>
<option value='jarred/update-install-stuff'>jarred/update-install-stuff</option>
<option value='jarred/update-zig1'>jarred/update-zig1</option>
<option value='jarred/upgrade-zig-2'>jarred/upgrade-zig-2</option>
<option value='jarred/uws'>jarred/uws</option>
<option value='jarred/webkit-upgrade-may-17'>jarred/webkit-upgrade-may-17</option>
<option value='jarred/wip-more-reliable'>jarred/wip-more-reliable</option>
<option value='jarred/workers'>jarred/workers</option>
<option value='jarred/zlib'>jarred/zlib</option>
<option value='jarred/zls'>jarred/zls</option>
<option value='lithdew/picohttp-mimalloc'>lithdew/picohttp-mimalloc</option>
<option value='main'>main</option>
<option value='move-templates'>move-templates</option>
<option value='nestjs-guide'>nestjs-guide</option>
<option value='next-cleanup'>next-cleanup</option>
<option value='origin/main'>origin/main</option>
<option value='plugin/plugindata'>plugin/plugindata</option>
<option value='plugin/resolvedir'>plugin/resolvedir</option>
<option value='postinstall_3'>postinstall_3</option>
<option value='repl'>repl</option>
<option value='request-body-stream'>request-body-stream</option>
<option value='reserve-commands'>reserve-commands</option>
<option value='revert-5167-dylan/decode-regex-if-needed'>revert-5167-dylan/decode-regex-if-needed</option>
<option value='rfc/bun-bundler-api'>rfc/bun-bundler-api</option>
<option value='rfc/bunfig-overhaul'>rfc/bunfig-overhaul</option>
<option value='save-in-update'>save-in-update</option>
<option value='sdl'>sdl</option>
<option value='test/action'>test/action</option>
<option value='types/mock'>types/mock</option>
<option value='types/readable-stream-default'>types/readable-stream-default</option>
<option value='types/tty'>types/tty</option>
<option value='u/vjpr/zig-0.10'>u/vjpr/zig-0.10</option>
<option value='xHyroM/types/expose-Bun-Env'>xHyroM/types/expose-Bun-Env</option>
</select> <input type='submit' value='switch'/></form></td></tr>
<tr><td class='sub'>Unnamed repository; edit this file 'description' to name the repository.</td><td class='sub right'></td></tr></table>
<table class='tabs'><tr><td>
<a href='/ansg191/bun/about/?h=dylan/github-api-option'>about</a><a href='/ansg191/bun/?h=dylan/github-api-option'>summary</a><a href='/ansg191/bun/refs/?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9'>refs</a><a class='active' href='/ansg191/bun/log/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;follow=1'>log</a><a href='/ansg191/bun/tree/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9'>tree</a><a href='/ansg191/bun/commit/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>commit</a><a href='/ansg191/bun/diff/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>diff</a></td><td class='form'><form class='right' method='get' action='/ansg191/bun/log/integration/bunjs-only-snippets/fs-stream.js'>
<input type='hidden' name='h' value='dylan/github-api-option'/><input type='hidden' name='id' value='e26f96b748d783828669d46068f744f5852b6ba9'/><select name='qt'>
<option value='grep'>log msg</option>
<option value='author'>author</option>
<option value='committer'>committer</option>
<option value='range'>range</option>
</select>
<input class='txt' type='search' size='10' name='q' value=''/>
<input type='submit' value='search'/>
</form>
</td></tr></table>
<div class='path'>path: <a href='/ansg191/bun/log/?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>root</a>/<a href='/ansg191/bun/log/integration?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>integration</a>/<a href='/ansg191/bun/log/integration/bunjs-only-snippets?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>bunjs-only-snippets</a>/<a href='/ansg191/bun/log/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;follow=1'>fs-stream.js</a> (<a href='/ansg191/bun/log/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9'>unfollow</a>)</div><div class='content'><table class='list nowrap'><tr class='nohover'><th class='left'>Age</th><th class='left'>Commit message (<a href='/ansg191/bun/log/integration/bunjs-only-snippets/fs-stream.js?h=dylan/github-api-option&amp;id=e26f96b748d783828669d46068f744f5852b6ba9&amp;showmsg=1&amp;follow=1'>Expand</a>)</th><th class='left'>Author</th><th class='left'>Files</th><th class='left'>Lines</th></tr>
<tr><td><span title='2022-04-29 00:47:26 -0700'>2022-04-29</span></td><td><a href='/ansg191/bun/commit/tcc.zig?h=dylan/github-api-option&amp;id=8fa1c5ebf116571f41fb93065f728bd6437ae2d8&amp;follow=1'>commit more</a></td><td><img src='//www.gravatar.com/avatar/764ea52180f7f5236744034dd5e1a3c0?s=13&amp;d=retro' width='13' height='13' alt='Gravatar' /> Jarred Sumner
</td><td>3</td><td><span class='deletions'>-0</span>/<span class='insertions'>+81</span></td></tr>
