import { CONTINUE, SKIP } from "../../unist-util-visit-parents/lib/index.js";
import { visit } from "../../unist-util-visit/lib/index.js";
const BlockPolicy = {
	indicator: "indicator",
	textOnly: "text-only",
	remove: "remove"
};
function harden({ defaultOrigin: e = "", allowedLinkPrefixes: t = [], allowedImagePrefixes: i = [], allowDataImages: a = !1, allowedProtocols: o = [], blockedImageClass: s = "inline-block bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-400 px-3 py-1 rounded text-sm", blockedLinkClass: c = "text-gray-500", linkBlockPolicy: l = BlockPolicy.indicator, imageBlockPolicy: d = BlockPolicy.indicator }) {
	let f = t.length && !t.every((e) => e === "*"), p = i.length && !i.every((e) => e === "*");
	if (!e && (f || p)) throw Error("defaultOrigin is required when allowedLinkPrefixes or allowedImagePrefixes are provided");
	return (r) => {
		let f = createVisitor(e, t, i, a, o, s, c, l, d);
		stripNullChildren(r), visit(r, f);
	};
}
function parseUrl(e, t) {
	if (typeof e != "string") return null;
	try {
		return new URL(e);
	} catch {
		if (t) try {
			return new URL(e, t);
		} catch {
			return null;
		}
		if (e.startsWith("/") || e.startsWith("./") || e.startsWith("../")) try {
			return new URL(e, "http://example.com");
		} catch {
			return null;
		}
		return null;
	}
}
function isPathRelativeUrl(e) {
	return typeof e == "string" ? e.startsWith("/") || e.startsWith("./") || e.startsWith("../") : !1;
}
var safeProtocols = new Set([
	"https:",
	"http:",
	"irc:",
	"ircs:",
	"mailto:",
	"xmpp:",
	"blob:"
]), blockedProtocols = new Set([
	"javascript:",
	"data:",
	"file:",
	"vbscript:"
]);
function transformUrl(e, t, n, r = !1, i = !1, l = []) {
	if (!e) return null;
	if (typeof e == "string" && e.startsWith("#") && !i) try {
		if (new URL(e, "http://example.com").hash === e) return e;
	} catch {}
	if (typeof e == "string" && e.startsWith("data:")) return i && r && e.startsWith("data:image/") ? e : null;
	if (typeof e == "string" && e.startsWith("blob:")) {
		try {
			if (new URL(e).protocol === "blob:" && e.length > 5) {
				let t = e.substring(5);
				if (t && t.length > 0 && t !== "invalid") return e;
			}
		} catch {
			return null;
		}
		return null;
	}
	let u = parseUrl(e, n);
	if (!u || blockedProtocols.has(u.protocol) || !(safeProtocols.has(u.protocol) || l.includes(u.protocol) || l.includes("*"))) return null;
	if (u.protocol === "mailto:" || !u.protocol.match(/^https?:$/)) return u.href;
	let d = isPathRelativeUrl(e);
	return u && t.some((e) => {
		let t = parseUrl(e, n);
		return !t || t.origin !== u.origin ? !1 : u.href.startsWith(t.href);
	}) ? d ? u.pathname + u.search + u.hash : u.href : t.includes("*") ? u.protocol !== "https:" && u.protocol !== "http:" ? null : d ? u.pathname + u.search + u.hash : u.href : null;
}
function stripNullChildren(e) {
	if ("children" in e && Array.isArray(e.children)) {
		e.children = e.children.filter((e) => e != null);
		for (let t of e.children) stripNullChildren(t);
	}
}
var SEEN = Symbol("node-seen");
function resolveLinkBlockPolicy(e, t, n) {
	return t === BlockPolicy.remove ? { type: "remove" } : t === BlockPolicy.textOnly ? {
		type: "replace",
		element: {
			type: "element",
			tagName: "span",
			properties: {},
			children: [...e.children]
		}
	} : {
		type: "replace",
		element: {
			type: "element",
			tagName: "span",
			properties: {
				title: "Blocked URL: " + String(e.properties.href),
				class: n
			},
			children: [...e.children, {
				type: "text",
				value: " [blocked]"
			}]
		}
	};
}
function resolveImageBlockPolicy(e, t, n) {
	if (t === BlockPolicy.remove) return { type: "remove" };
	if (t === BlockPolicy.textOnly) {
		let t = String(e.properties.alt || "");
		return t ? {
			type: "replace",
			element: {
				type: "element",
				tagName: "span",
				properties: {},
				children: [{
					type: "text",
					value: t
				}]
			}
		} : { type: "remove" };
	}
	return {
		type: "replace",
		element: {
			type: "element",
			tagName: "span",
			properties: { class: n },
			children: [{
				type: "text",
				value: "[Image blocked: " + String(e.properties.alt || "No description") + "]"
			}]
		}
	};
}
var createVisitor = (e, r, i, a, o, s, c, u, m) => {
	let h = (g, _, v) => {
		if (g.type !== "element" || g[SEEN]) return !0;
		if (g.tagName === "a") {
			let i = transformUrl(g.properties.href, r, e, !1, !1, o);
			if (i === null) {
				if (g[SEEN] = !0, visit(g, h), v && typeof _ == "number") {
					let e = resolveLinkBlockPolicy(g, u, c);
					if (e.type === "remove") return v.children.splice(_, 1), [SKIP, _];
					v.children[_] = e.element;
				}
				return SKIP;
			} else return g.properties.href = i, g.properties.target = "_blank", g.properties.rel = "noopener noreferrer", !0;
		}
		if (g.tagName === "img") {
			let r = transformUrl(g.properties.src, i, e, a, !0, o);
			if (r === null) {
				if (g[SEEN] = !0, visit(g, h), v && typeof _ == "number") {
					let e = resolveImageBlockPolicy(g, m, s);
					if (e.type === "remove") return v.children.splice(_, 1), [SKIP, _];
					v.children[_] = e.element;
				}
				return SKIP;
			} else return g.properties.src = r, !0;
		}
		return !0;
	};
	return h;
};
export { harden };
