import { NEWLINE_REGEXP, escapeRegExp } from "../utils/regexp-utils.js";
import { Position, Range, init_main } from "../../../vscode-languageserver-types/lib/esm/main.js";
import { URI } from "../../../vscode-uri/lib/esm/index.js";
init_main();
function parseJSDoc(i, x, C) {
	let w, T;
	typeof i == "string" ? (T = x, w = C) : (T = i.range.start, w = x), T ||= Position.create(0, 0);
	let E = getLines(i), D = normalizeOptions(w);
	return parseJSDocComment({
		index: 0,
		tokens: tokenize({
			lines: E,
			position: T,
			options: D
		}),
		position: T
	});
}
function isJSDoc(i, x) {
	let S = normalizeOptions(x), C = getLines(i);
	if (C.length === 0) return !1;
	let w = C[0], T = C[C.length - 1], E = S.start, D = S.end;
	return !!E?.exec(w) && !!D?.exec(T);
}
function getLines(x) {
	let S = "";
	return S = typeof x == "string" ? x : x.text, S.split(NEWLINE_REGEXP);
}
var tagRegex = /\s*(@([\p{L}][\p{L}\p{N}]*)?)/uy, inlineTagRegex = /\{(@[\p{L}][\p{L}\p{N}]*)(\s*)([^\r\n}]+)?\}/gu;
function tokenize(i) {
	let x = [], w = i.position.line, T = i.position.character;
	for (let E = 0; E < i.lines.length; E++) {
		let D = E === 0, O = E === i.lines.length - 1, j = i.lines[E], M = 0;
		if (D && i.options.start) {
			let x = i.options.start?.exec(j);
			x && (M = x.index + x[0].length);
		} else {
			let x = i.options.line?.exec(j);
			x && (M = x.index + x[0].length);
		}
		if (O) {
			let x = i.options.end?.exec(j);
			x && (j = j.substring(0, x.index));
		}
		if (j = j.substring(0, lastCharacter(j)), skipWhitespace(j, M) >= j.length) {
			if (x.length > 0) {
				let i = Position.create(w, T);
				x.push({
					type: "break",
					content: "",
					range: Range.create(i, i)
				});
			}
		} else {
			tagRegex.lastIndex = M;
			let i = tagRegex.exec(j);
			if (i) {
				let E = i[0], D = i[1], O = Position.create(w, T + M), k = Position.create(w, T + M + E.length);
				x.push({
					type: "tag",
					content: D,
					range: Range.create(O, k)
				}), M += E.length, M = skipWhitespace(j, M);
			}
			if (M < j.length) {
				let i = j.substring(M), S = Array.from(i.matchAll(inlineTagRegex));
				x.push(...buildInlineTokens(S, i, w, T + M));
			}
		}
		w++, T = 0;
	}
	return x.length > 0 && x[x.length - 1].type === "break" ? x.slice(0, -1) : x;
}
function buildInlineTokens(i, x, w, T) {
	let E = [];
	if (i.length === 0) {
		let i = Position.create(w, T), D = Position.create(w, T + x.length);
		E.push({
			type: "text",
			content: x,
			range: Range.create(i, D)
		});
	} else {
		let D = 0;
		for (let O of i) {
			let i = O.index, k = x.substring(D, i);
			k.length > 0 && E.push({
				type: "text",
				content: x.substring(D, i),
				range: Range.create(Position.create(w, D + T), Position.create(w, i + T))
			});
			let A = k.length + 1, j = O[1];
			if (E.push({
				type: "inline-tag",
				content: j,
				range: Range.create(Position.create(w, D + A + T), Position.create(w, D + A + j.length + T))
			}), A += j.length, O.length === 4) {
				A += O[2].length;
				let i = O[3];
				E.push({
					type: "text",
					content: i,
					range: Range.create(Position.create(w, D + A + T), Position.create(w, D + A + i.length + T))
				});
			} else E.push({
				type: "text",
				content: "",
				range: Range.create(Position.create(w, D + A + T), Position.create(w, D + A + T))
			});
			D = i + O[0].length;
		}
		let O = x.substring(D);
		O.length > 0 && E.push({
			type: "text",
			content: O,
			range: Range.create(Position.create(w, D + T), Position.create(w, D + T + O.length))
		});
	}
	return E;
}
var nonWhitespaceRegex = /\S/, whitespaceEndRegex = /\s*$/;
function skipWhitespace(i, x) {
	let S = i.substring(x).match(nonWhitespaceRegex);
	return S ? x + S.index : i.length;
}
function lastCharacter(i) {
	let x = i.match(whitespaceEndRegex);
	if (x && typeof x.index == "number") return x.index;
}
function parseJSDocComment(i) {
	let x = Position.create(i.position.line, i.position.character);
	if (i.tokens.length === 0) return new JSDocCommentImpl([], Range.create(x, x));
	let w = [];
	for (; i.index < i.tokens.length;) {
		let x = parseJSDocElement(i, w[w.length - 1]);
		x && w.push(x);
	}
	let T = w[0]?.range.start ?? x, E = w[w.length - 1]?.range.end ?? x;
	return new JSDocCommentImpl(w, Range.create(T, E));
}
function parseJSDocElement(i, x) {
	let S = i.tokens[i.index];
	if (S.type === "tag") return parseJSDocTag(i, !1);
	if (S.type === "text" || S.type === "inline-tag") return parseJSDocText(i);
	appendEmptyLine(S, x), i.index++;
}
function appendEmptyLine(i, x) {
	if (x) {
		let S = new JSDocLineImpl("", i.range);
		"inlines" in x ? x.inlines.push(S) : x.content.inlines.push(S);
	}
}
function parseJSDocText(i) {
	let x = i.tokens[i.index], S = x, w = x, T = [];
	for (; x && x.type !== "break" && x.type !== "tag";) T.push(parseJSDocInline(i)), w = x, x = i.tokens[i.index];
	return new JSDocTextImpl(T, Range.create(S.range.start, w.range.end));
}
function parseJSDocInline(i) {
	return i.tokens[i.index].type === "inline-tag" ? parseJSDocTag(i, !0) : parseJSDocLine(i);
}
function parseJSDocTag(i, x) {
	let S = i.tokens[i.index++], w = S.content.substring(1);
	if (i.tokens[i.index]?.type === "text") if (x) {
		let T = parseJSDocLine(i);
		return new JSDocTagImpl(w, new JSDocTextImpl([T], T.range), x, Range.create(S.range.start, T.range.end));
	} else {
		let T = parseJSDocText(i);
		return new JSDocTagImpl(w, T, x, Range.create(S.range.start, T.range.end));
	}
	else {
		let i = S.range;
		return new JSDocTagImpl(w, new JSDocTextImpl([], i), x, i);
	}
}
function parseJSDocLine(i) {
	let x = i.tokens[i.index++];
	return new JSDocLineImpl(x.content, x.range);
}
function normalizeOptions(i) {
	if (!i) return normalizeOptions({
		start: "/**",
		end: "*/",
		line: "*"
	});
	let { start: x, end: S, line: C } = i;
	return {
		start: normalizeOption(x, !0),
		end: normalizeOption(S, !1),
		line: normalizeOption(C, !0)
	};
}
function normalizeOption(i, S) {
	if (typeof i == "string" || typeof i == "object") {
		let C = typeof i == "string" ? escapeRegExp(i) : i.source;
		return S ? /* @__PURE__ */ RegExp(`^\\s*${C}`) : /* @__PURE__ */ RegExp(`\\s*${C}\\s*$`);
	} else return i;
}
var JSDocCommentImpl = class {
	constructor(i, x) {
		this.elements = i, this.range = x;
	}
	getTag(i) {
		return this.getAllTags().find((x) => x.name === i);
	}
	getTags(i) {
		return this.getAllTags().filter((x) => x.name === i);
	}
	getAllTags() {
		return this.elements.filter((i) => "name" in i);
	}
	toString() {
		let i = "";
		for (let x of this.elements) if (i.length === 0) i = x.toString();
		else {
			let S = x.toString();
			i += fillNewlines(i) + S;
		}
		return i.trim();
	}
	toMarkdown(i) {
		let x = "";
		for (let S of this.elements) if (x.length === 0) x = S.toMarkdown(i);
		else {
			let C = S.toMarkdown(i);
			x += fillNewlines(x) + C;
		}
		return x.trim();
	}
}, JSDocTagImpl = class {
	constructor(i, x, S, C) {
		this.name = i, this.content = x, this.inline = S, this.range = C;
	}
	toString() {
		let i = `@${this.name}`, x = this.content.toString();
		return this.content.inlines.length === 1 ? i = `${i} ${x}` : this.content.inlines.length > 1 && (i = `${i}\n${x}`), this.inline ? `{${i}}` : i;
	}
	toMarkdown(i) {
		return i?.renderTag?.(this) ?? this.toMarkdownDefault(i);
	}
	toMarkdownDefault(i) {
		let x = this.content.toMarkdown(i);
		if (this.inline) {
			let S = renderInlineTag(this.name, x, i ?? {});
			if (typeof S == "string") return S;
		}
		let S = "";
		i?.tag === "italic" || i?.tag === void 0 ? S = "*" : i?.tag === "bold" ? S = "**" : i?.tag === "bold-italic" && (S = "***");
		let C = `${S}@${this.name}${S}`;
		return this.content.inlines.length === 1 ? C = `${C} — ${x}` : this.content.inlines.length > 1 && (C = `${C}\n${x}`), this.inline ? `{${C}}` : C;
	}
};
function renderInlineTag(i, x, S) {
	if (i === "linkplain" || i === "linkcode" || i === "link") {
		let C = x.indexOf(" "), w = x;
		if (C > 0) {
			let i = skipWhitespace(x, C);
			w = x.substring(i), x = x.substring(0, C);
		}
		return (i === "linkcode" || i === "link" && S.link === "code") && (w = `\`${w}\``), S.renderLink?.(x, w) ?? renderLinkDefault(x, w);
	}
}
function renderLinkDefault(i, x) {
	try {
		return URI.parse(i, !0), `[${x}](${i})`;
	} catch {
		return i;
	}
}
var JSDocTextImpl = class {
	constructor(i, x) {
		this.inlines = i, this.range = x;
	}
	toString() {
		let i = "";
		for (let x = 0; x < this.inlines.length; x++) {
			let S = this.inlines[x], C = this.inlines[x + 1];
			i += S.toString(), C && C.range.start.line > S.range.start.line && (i += "\n");
		}
		return i;
	}
	toMarkdown(i) {
		let x = "";
		for (let S = 0; S < this.inlines.length; S++) {
			let C = this.inlines[S], w = this.inlines[S + 1];
			x += C.toMarkdown(i), w && w.range.start.line > C.range.start.line && (x += "\n");
		}
		return x;
	}
}, JSDocLineImpl = class {
	constructor(i, x) {
		this.text = i, this.range = x;
	}
	toString() {
		return this.text;
	}
	toMarkdown() {
		return this.text;
	}
};
function fillNewlines(i) {
	return i.endsWith("\n") ? "\n" : "\n\n";
}
export { isJSDoc, parseJSDoc };
