import {libWrapper, UtilLibWrapper} from "./PatcherLibWrapper.js";
import {SharedConsts} from "../shared/SharedConsts.js";
import {Config} from "./Config.js";
import {ChooseImporter} from "./ChooseImporter.js";
import {LGT} from "./Util.js";
import {UtilApplications} from "./UtilApplications.js";

class Patcher_TextEditor {
	static init () {
		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"TextEditor.enrichHTML",
			function (fnEnrichHtml, ...args) {
				if (!Config.get("journalEntries", "isEnableJournalEmbeds") && !Config.get("journalEntries", "isEnableContentLinks")) return fnEnrichHtml(...args);
				return Patcher_TextEditor.enrichHTML(fnEnrichHtml, ...args);
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);

		libWrapper.register(
			SharedConsts.MODULE_NAME,
			"JournalSheet.prototype._disableFields",
			function (fnDisableFields, ...args) {
				const res = fnDisableFields(...args);
				if (!Config.get("journalEntries", "isEnableJournalEmbeds")) return res;
				Patcher_TextEditor.Embed._doEnableToggleButtons(...args);
				return res;
			},
			UtilLibWrapper.LIBWRAPPER_MODE_WRAPPER,
		);

		$(document.body)
			.on("click", `.jemb__btn-toggle`, evt => {
				Patcher_TextEditor.Embed.handleToggleClick(evt);
			})
			.on("click", `.jlnk__entity-link`, evt => {
				Patcher_TextEditor.ContentLoader.handleClick(evt);
			});
	}

	/** Based on the original method. */
	static enrichHTML (originalEnrichHtml, content, opts, depth = 0) {
		opts = opts || {};

		if (opts.secrets === undefined) opts.secrets = false;
		if (opts.entities === undefined) opts.entities = true;
		if (opts.links === undefined) opts.links = true;
		if (opts.rolls === undefined) opts.rolls = true;

		// Call the original method--"content" is now enriched HTML
		content = originalEnrichHtml(content, opts);

		// If we are not to replace dynamic entity links, return the base content
		if (!opts.entities) return content;

		// Don't load compendiums--we don't match `EmbedCompendium`
		content = content
			.replace(/@Embed(JournalEntry)\[([^\]]+)](?:{([^}]+)})?/g, (...m) => Patcher_TextEditor.Embed.getHtml(opts, depth, ...m))
			.replace(/@([a-zA-Z]+)\[([^\]]+)](?:{([^}]+)})?/g, (...m) => Patcher_TextEditor.ContentLoader.getHtml(opts, depth, ...m))
		;

		return content;
	}
}

Patcher_TextEditor.Embed = class {
	static getHtml (enrichOpts, depth, fullText, entityType, entityNameOrId, displayText) {
		const config = CONFIG[entityType];
		const collection = config.collection.instance;
		const entity = this._getEntity(collection, entityNameOrId);

		if (!entity) return `<a class="entity-link broken"><i class="fas fa-unlink"></i> ${displayText || entityNameOrId}</a>`;
		if (this._getEntityPermissions(entity) < CONST.ENTITY_PERMISSIONS.OBSERVER) return `<a class="entity-link broken"><i class="fas fa-unlink"></i> ${displayText || entityNameOrId} <i>(you do not have sufficient permissions to view this journal entry)</i></a>`;

		// Get the standard Foundry link
		const htmlJournalLink = TextEditor._createContentLink(fullText, entityType, entityNameOrId, displayText).outerHTML;

		const isAutoExpand = Config.get("journalEntries", "isAutoExpandJournalEmbeds");
		if (entity.sheet._sheetMode === "image") {
			const img = entity.data.img;
			return `<div class="w-100 flex-col">
				<div class="flex-v-center mb-1 jemb__wrp-lnk">${htmlJournalLink}${this._getBtnHtmlToggle(isAutoExpand)}</div>
				<div class="flex-vh-center jemb__wrp-content ${isAutoExpand ? "" : "ve-hidden"}"><a target="_blank w-100" href="${img}"><img src="${img}" class="jemb__img"></a></div>
			</div>`;
		} else {
			// Avoid infinite loops
			const isTooDeep = depth === Patcher_TextEditor.Embed._MAX_RECURSION_DEPTH;
			const subContent = isTooDeep ? entity.data.content : TextEditor.enrichHTML(entity.data.content, enrichOpts, depth + 1);
			return `<div class="w-100 flex-col">
				<div class="flex-v-center mb-1 jemb__wrp-lnk">${htmlJournalLink}${this._getBtnHtmlToggle(isAutoExpand)}</div>
				${isTooDeep ? `<div class="mb-1 bold veapp__msg-error">Warning: too many recursive embeds! Have you made an infinite loop?</div>` : ""}
				<div class="w-100 jemb__wrp-content ${isAutoExpand ? "" : "ve-hidden"}">${subContent}</div>
			</div>`;
		}
	}

	static _getEntityPermissions (entity) {
		if (game.user.isGM) return CONST.ENTITY_PERMISSIONS.OWNER;
		return Math.max(entity.data.permission[game.user.id], entity.data.permission["default"]);
	}

	static _getEntity (collection, entityNameOrId) {
		// Match either on ID or by name
		let entity = null;
		if (/^[a-zA-Z0-9]{16}$/.test(entityNameOrId)) entity = collection.get(entityNameOrId);
		if (!entity) entity = collection.contents.find(e => e.data.name === entityNameOrId);
		return entity;
	}

	static handleToggleClick (event) {
		const $btn = $(event.currentTarget);
		const isExpanded = $btn.attr("data-plut-is-expanded") === "1";

		if (event.shiftKey) {
			event.preventDefault();

			const $editor = $btn.closest(`.editor`);
			$editor.find(`button[data-plut-is-expanded]`).each((i, e) => this._handleExpandCollapse($(e), isExpanded));
			return;
		}

		this._handleExpandCollapse($btn, isExpanded);
	}

	static _handleExpandCollapse ($btn, isExpanded) {
		const $wrp = $btn.parent().next();
		$wrp.toggleClass("ve-hidden", isExpanded);
		$btn
			.attr("data-plut-is-expanded", isExpanded ? "0" : "1")
			.html(isExpanded ? `<i class="fa fa-caret-square-left"></i>` : `<i class="fa fa-caret-square-down"></i>`)
			.title(`${isExpanded ? `Expand` : `Collapse`} Journal Entry (SHIFT for All Entries)`);
	}

	static _getBtnHtmlToggle (isAutoExpand) {
		return `<button class="btn btn-xxs btn-5et btn-default flex-vh-center mx-1 jemb__btn-toggle" data-plut-is-expanded="${isAutoExpand ? 1 : 0}" title="${isAutoExpand ? "Collapse" : "Expand"} Journal Entry (SHIFT for All Entries)" type="button">${isAutoExpand ? `<i class="fa fa-caret-square-down"></i>` : `<i class="fa fa-caret-square-left"></i>`}</button>`
	}

	/** Based on `FormApplication._disableFields` */
	static _doEnableToggleButtons (form) {
		for (let el of form.getElementsByTagName("BUTTON")) {
			if (el.classList.contains("jemb__btn-toggle")) el.removeAttribute("disabled");
		}
	}
}
Patcher_TextEditor.Embed._MAX_RECURSION_DEPTH = 69

Patcher_TextEditor.ContentLoader = class {
	static getHtml (enrichOpts, depth, fullText, tag, pipeParts, displayText) {
		const importer = ChooseImporter.getImporter(tag);

		const name = (Renderer.splitTagByPipe(pipeParts)[0] || "");

		if (!importer) return `<a class="entity-link broken" title="Unknown Tag &quot;${tag.qq()}&quot;"><i class="fas fa-unlink"></i> ${StrUtil.qq(displayText || name)}</a>`;

		const config = CONFIG[importer.folderType];

		// (Should never occur)
		if (!config) return `<a class="entity-link broken" title="No CONFIG found for type &quot;${importer.folderType}&quot;\u2014this is a bug!"><i class="fas fa-unlink"></i> ${StrUtil.qq(displayText || name)}</a>`;

		const {displayText: displayTextPipe} = Renderer.utils.getTagMeta(pipeParts, `@${tag}`);

		return `<a class="jlnk__entity-link" draggable="true" data-plut-rich-link-text="${pipeParts.qq()}" data-plut-rich-link-tag="${tag.qq()}" title="Click to show. SHIFT-click to import."><i class="fas ${config.sidebarIcon}"></i> ${StrUtil.qq(displayTextPipe || displayText || name)}</a>`
	}

	static handleClick (evt) {
		evt.stopPropagation();
		evt.preventDefault();

		const pipeParts = evt.currentTarget.dataset.plutRichLinkText;
		const tag = evt.currentTarget.dataset.plutRichLinkTag;

		if (!pipeParts || !tag) return;
		const importer = ChooseImporter.getImporter(tag);

		const {source, page, hash, hashPreEncoded, hashHover, hashPreEncodedHover} = Renderer.utils.getTagMeta(pipeParts, `@${tag}`);

		let hashOut = hash;
		if (!hashPreEncoded) hashOut = UrlUtil.encodeForHash(hashOut);
		if (hashHover) hashOut = hashHover;
		if (hashHover && !hashPreEncodedHover) hashOut = UrlUtil.encodeForHash(hashOut);

		const isPermanent = !!evt.shiftKey;

		Renderer.hover.pCacheAndGet(page, source, hashOut)
			.then(ent => {
				const msgError = `Could not load "${pipeParts}" with tag "${tag}"!`;

				if (!ent) {
					console.error(...LGT, msgError);
					return ui.notifications.error(msgError);
				}

				importer.pImportEntry(ent, {isTemp: !isPermanent})
					.then(result => {
						if (isPermanent) UtilApplications.doShowImportedNotification(result);

						result.imported.forEach(fvttEnt => {
							if (fvttEnt.sheet) return fvttEnt.sheet.render(true);
							fvttEnt.render(true);
						});
					})
					.catch(err => {
						console.error(...LGT, err);
						ui.notifications.error(`${msgError} ${VeCt.STR_SEE_CONSOLE}`)
					});
			});
	}
}

export {Patcher_TextEditor};
