import { webNamespaces } from "../../web-namespaces/index.js";
import { zwitch } from "../../zwitch/index.js";
import { visit } from "../../unist-util-visit/lib/index.js";
import esm_default from "../../@ungap/structured-clone/esm/index.js";
import { fromParse5 } from "../../hast-util-from-parse5/lib/index.js";
import { toParse5 } from "../../hast-util-to-parse5/lib/index.js";
import { htmlVoidElements } from "../../html-void-elements/index.js";
import { TokenType } from "../node_modules/parse5/dist/common/token.js";
import { getTagID } from "../node_modules/parse5/dist/common/html.js";
import { TokenizerMode } from "../node_modules/parse5/dist/tokenizer/index.js";
import { Parser } from "../node_modules/parse5/dist/parser/index.js";
import "../node_modules/parse5/dist/index.js";
import { pointEnd, pointStart } from "../../unist-util-position/lib/index.js";
var gfmTagfilterExpression = /<(\/?)(iframe|noembed|noframes|plaintext|script|style|textarea|title|xmp)(?=[\t\n\f\r />])/gi, knownMdxNames = new Set([
	"mdxFlowExpression",
	"mdxJsxFlowElement",
	"mdxJsxTextElement",
	"mdxTextExpression",
	"mdxjsEsm"
]), parseOptions = {
	sourceCodeLocationInfo: !0,
	scriptingEnabled: !1
};
function raw(t, T) {
	let D = documentMode(t), O = zwitch("type", {
		handlers: {
			root,
			element,
			text,
			comment,
			doctype,
			raw: handleRaw
		},
		unknown
	}), k = {
		parser: D ? new Parser(parseOptions) : Parser.getFragmentParser(void 0, parseOptions),
		handle(t) {
			O(t, k);
		},
		stitches: !1,
		options: T || {}
	};
	O(t, k), resetTokenizer(k, pointStart());
	let A = fromParse5(D ? k.parser.document : k.parser.getFragment(), { file: k.options.file });
	return k.stitches && visit(A, "comment", function(t, C, w) {
		let T = t;
		if (T.value.stitch && w && C !== void 0) {
			let t = w.children;
			return t[C] = T.value.stitch, C;
		}
	}), A.type === "root" && A.children.length === 1 && A.children[0].type === t.type ? A.children[0] : A;
}
function all(t, C) {
	let w = -1;
	/* istanbul ignore else - invalid nodes, see rehypejs/rehype-raw#7. */
	if (t) for (; ++w < t.length;) C.handle(t[w]);
}
function root(t, C) {
	all(t.children, C);
}
function element(t, C) {
	startTag(t, C), all(t.children, C), endTag(t, C);
}
function text(t, C) {
	C.parser.tokenizer.state > 4 && (C.parser.tokenizer.state = 0);
	let w = {
		type: TokenType.CHARACTER,
		chars: t.value,
		location: createParse5Location(t)
	};
	resetTokenizer(C, pointStart(t)), C.parser.currentToken = w, C.parser._processToken(C.parser.currentToken);
}
function doctype(t, C) {
	let w = {
		type: TokenType.DOCTYPE,
		name: "html",
		forceQuirks: !1,
		publicId: "",
		systemId: "",
		location: createParse5Location(t)
	};
	resetTokenizer(C, pointStart(t)), C.parser.currentToken = w, C.parser._processToken(C.parser.currentToken);
}
function stitch(t, C) {
	C.stitches = !0;
	let w = cloneWithoutChildren(t);
	"children" in t && "children" in w && (w.children = raw({
		type: "root",
		children: t.children
	}, C.options).children), comment({
		type: "comment",
		value: { stitch: w }
	}, C);
}
function comment(t, C) {
	let w = t.value, T = {
		type: TokenType.COMMENT,
		data: w,
		location: createParse5Location(t)
	};
	resetTokenizer(C, pointStart(t)), C.parser.currentToken = T, C.parser._processToken(C.parser.currentToken);
}
function handleRaw(t, C) {
	/* c8 ignore next 12 -- removed in <https://github.com/inikulin/parse5/pull/897> */
	if (C.parser.tokenizer.preprocessor.html = "", C.parser.tokenizer.preprocessor.pos = -1, C.parser.tokenizer.preprocessor.lastGapPos = -2, C.parser.tokenizer.preprocessor.gapStack = [], C.parser.tokenizer.preprocessor.skipNextNewLine = !1, C.parser.tokenizer.preprocessor.lastChunkWritten = !1, C.parser.tokenizer.preprocessor.endOfChunkHit = !1, C.parser.tokenizer.preprocessor.isEol = !1, setPoint(C, pointStart(t)), C.parser.tokenizer.write(C.options.tagfilter ? t.value.replace(gfmTagfilterExpression, "&lt;$1$2") : t.value, !1), C.parser.tokenizer._runParsingLoop(), C.parser.tokenizer.state === 72 || C.parser.tokenizer.state === 78) {
		C.parser.tokenizer.preprocessor.lastChunkWritten = !0;
		let t = C.parser.tokenizer._consume();
		C.parser.tokenizer._callState(t);
	}
}
function unknown(t, C) {
	let w = t;
	if (C.options.passThrough && C.options.passThrough.includes(w.type)) stitch(w, C);
	else {
		let t = "";
		throw knownMdxNames.has(w.type) && (t = ". It looks like you are using MDX nodes with `hast-util-raw` (or `rehype-raw`). If you use this because you are using remark or rehype plugins that inject `'html'` nodes, then please raise an issue with that plugin, as its a bad and slow idea. If you use this because you are using markdown syntax, then you have to configure this utility (or plugin) to pass through these nodes (see `passThrough` in docs), but you can also migrate to use the MDX syntax"), Error("Cannot compile `" + w.type + "` node" + t);
	}
}
function resetTokenizer(t, C) {
	setPoint(t, C);
	let w = t.parser.tokenizer.currentCharacterToken;
	w && w.location && (w.location.endLine = t.parser.tokenizer.preprocessor.line, w.location.endCol = t.parser.tokenizer.preprocessor.col + 1, w.location.endOffset = t.parser.tokenizer.preprocessor.offset + 1, t.parser.currentToken = w, t.parser._processToken(t.parser.currentToken)), t.parser.tokenizer.paused = !1, t.parser.tokenizer.inLoop = !1, t.parser.tokenizer.active = !1, t.parser.tokenizer.returnState = TokenizerMode.DATA, t.parser.tokenizer.charRefCode = -1, t.parser.tokenizer.consumedAfterSnapshot = -1, t.parser.tokenizer.currentLocation = null, t.parser.tokenizer.currentCharacterToken = null, t.parser.tokenizer.currentToken = null, t.parser.tokenizer.currentAttr = {
		name: "",
		value: ""
	};
}
function setPoint(t, C) {
	if (C && C.offset !== void 0) {
		let w = {
			startLine: C.line,
			startCol: C.column,
			startOffset: C.offset,
			endLine: -1,
			endCol: -1,
			endOffset: -1
		};
		t.parser.tokenizer.preprocessor.lineStartPos = -C.column + 1, t.parser.tokenizer.preprocessor.droppedBufferSize = C.offset, t.parser.tokenizer.preprocessor.line = C.line, t.parser.tokenizer.currentLocation = w;
	}
}
function startTag(C, w) {
	let T = C.tagName.toLowerCase();
	if (w.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return;
	resetTokenizer(w, pointStart(C));
	let E = w.parser.openElements.current, O = "namespaceURI" in E ? E.namespaceURI : webNamespaces.html;
	O === webNamespaces.html && T === "svg" && (O = webNamespaces.svg);
	let j = toParse5({
		...C,
		children: []
	}, { space: O === webNamespaces.svg ? "svg" : "html" }), M = {
		type: TokenType.START_TAG,
		tagName: T,
		tagID: getTagID(T),
		selfClosing: !1,
		ackSelfClosing: !1,
		attrs: "attrs" in j ? j.attrs : [],
		location: createParse5Location(C)
	};
	w.parser.currentToken = M, w.parser._processToken(w.parser.currentToken), w.parser.tokenizer.lastStartTagName = T;
}
function endTag(t, C) {
	let w = t.tagName.toLowerCase();
	if (!C.parser.tokenizer.inForeignNode && htmlVoidElements.includes(w) || C.parser.tokenizer.state === TokenizerMode.PLAINTEXT) return;
	resetTokenizer(C, pointEnd(t));
	let T = {
		type: TokenType.END_TAG,
		tagName: w,
		tagID: getTagID(w),
		selfClosing: !1,
		ackSelfClosing: !1,
		attrs: [],
		location: createParse5Location(t)
	};
	C.parser.currentToken = T, C.parser._processToken(C.parser.currentToken), w === C.parser.tokenizer.lastStartTagName && (C.parser.tokenizer.state === TokenizerMode.RCDATA || C.parser.tokenizer.state === TokenizerMode.RAWTEXT || C.parser.tokenizer.state === TokenizerMode.SCRIPT_DATA) && (C.parser.tokenizer.state = TokenizerMode.DATA);
}
function documentMode(t) {
	let C = t.type === "root" ? t.children[0] : t;
	return !!(C && (C.type === "doctype" || C.type === "element" && C.tagName.toLowerCase() === "html"));
}
function createParse5Location(t) {
	let C = pointStart(t) || {
		line: void 0,
		column: void 0,
		offset: void 0
	}, w = pointEnd(t) || {
		line: void 0,
		column: void 0,
		offset: void 0
	};
	return {
		startLine: C.line,
		startCol: C.column,
		startOffset: C.offset,
		endLine: w.line,
		endCol: w.column,
		endOffset: w.offset
	};
}
function cloneWithoutChildren(t) {
	return "children" in t ? esm_default({
		...t,
		children: []
	}) : esm_default(t);
}
export { raw };
