import { DEFAULT_THEMES } from "../constants.js";
import { areRenderRangesEqual } from "../utils/areRenderRangesEqual.js";
import { FileDiff } from "./FileDiff.js";
import { resolveVirtualFileMetrics } from "../utils/resolveVirtualFileMetrics.js";

//#region src/components/AdvancedVirtualizedFileDiff.ts
let instanceId = -1;
var AdvancedVirtualizedFileDiff = class extends FileDiff {
	__id = `virtualized-file-diff:${++instanceId}`;
	unifiedTop;
	splitTop;
	unifiedHeight = 0;
	splitHeight = 0;
	metrics;
	fileDiff;
	renderedRange;
	constructor({ unifiedTop, splitTop, fileDiff }, options = { theme: DEFAULT_THEMES }, metrics, workerManager) {
		super(options, workerManager, true);
		this.fileDiff = fileDiff;
		this.unifiedTop = unifiedTop;
		this.splitTop = splitTop;
		const { hunkSeparators = "line-info" } = this.options;
		this.metrics = resolveVirtualFileMetrics(typeof hunkSeparators === "function" ? "custom" : hunkSeparators, metrics);
		this.computeSize();
	}
	cleanUp(recycle = false) {
		super.cleanUp(recycle);
		this.renderedRange = void 0;
	}
	computeSize() {
		const { options: { disableFileHeader = false }, fileDiff, metrics: { diffHeaderHeight, fileGap, hunkSeparatorHeight, lineHeight } } = this;
		if (!disableFileHeader) {
			this.unifiedHeight += diffHeaderHeight;
			this.splitHeight += diffHeaderHeight;
		} else {
			this.unifiedHeight += fileGap;
			this.splitHeight += fileGap;
		}
		for (const hunk of fileDiff.hunks) {
			this.unifiedHeight += hunk.unifiedLineCount * lineHeight;
			this.splitHeight += hunk.splitLineCount * lineHeight;
		}
		const hunkCount = fileDiff.hunks.length;
		const [firstHunk] = fileDiff.hunks;
		if (firstHunk != null) {
			let hunkSize = (hunkSeparatorHeight + fileGap * 2) * (hunkCount - 1);
			if (firstHunk.additionStart > 1 || firstHunk.deletionStart > 1) hunkSize += hunkSeparatorHeight + fileGap;
			this.unifiedHeight += hunkSize;
			this.splitHeight += hunkSize;
		}
		if (hunkCount > 0) {
			this.unifiedHeight += fileGap;
			this.splitHeight += fileGap;
		}
	}
	virtualizedRender({ renderWindow, fileContainer }) {
		const { fileDiff } = this;
		const renderRange = this.computeRenderRangeFromWindow(renderWindow);
		if (this.fileContainer != null && areRenderRangesEqual(renderRange, this.renderedRange)) return;
		this.renderedRange = renderRange;
		fileContainer = this.getOrCreateFileContainer(fileContainer);
		this.render({
			fileDiff,
			fileContainer,
			renderRange
		});
	}
	computeRenderRangeFromWindow({ top, bottom }) {
		const { diffStyle = "split", disableFileHeader = false } = this.options;
		const { diffHeaderHeight, fileGap, hunkLineCount, hunkSeparatorHeight, lineHeight } = this.metrics;
		const { lineCount, fileTop, fileHeight } = getSpecs(this, diffStyle);
		if (fileTop < top - fileHeight || fileTop > bottom) {
			console.error("VirtulizedFileDiff.computeRenderRangeFromWindow: invalid render", this.fileDiff.name);
			return {
				startingLine: 0,
				totalLines: 0,
				bufferBefore: 0,
				bufferAfter: 0
			};
		}
		if (lineCount <= hunkLineCount) return {
			startingLine: 0,
			totalLines: Infinity,
			bufferBefore: 0,
			bufferAfter: 0
		};
		const headerRegion = disableFileHeader ? fileGap : diffHeaderHeight;
		let absoluteLineTop = fileTop + headerRegion;
		let currentLine = 0;
		const hunkOffsets = [];
		let startingLine;
		let endingLine = 0;
		for (const hunk of this.fileDiff.hunks) {
			let hunkGap = 0;
			if (hunk.additionStart > 1 || hunk.deletionStart > 1) {
				hunkGap = hunkSeparatorHeight + fileGap;
				if (hunk !== this.fileDiff.hunks[0]) hunkGap += fileGap;
				absoluteLineTop += hunkGap;
			}
			const hunkLineCount$1 = diffStyle === "split" ? hunk.splitLineCount : hunk.unifiedLineCount;
			for (let l = 0; l < hunkLineCount$1; l++) {
				if (currentLine % hunkLineCount$1 === 0) hunkOffsets.push(absoluteLineTop - (fileTop + headerRegion + (l === 0 ? hunkGap : 0)));
				if (startingLine == null && absoluteLineTop > top - lineHeight && absoluteLineTop < bottom) {
					startingLine = currentLine;
					endingLine = startingLine + 1;
				} else if (startingLine != null && absoluteLineTop < bottom) endingLine++;
				currentLine++;
				absoluteLineTop += lineHeight;
			}
		}
		if (startingLine == null) return {
			startingLine: 0,
			totalLines: 0,
			bufferBefore: fileHeight - headerRegion,
			bufferAfter: 0
		};
		startingLine = Math.floor(startingLine / hunkLineCount) * hunkLineCount;
		const totalLines = Math.ceil((endingLine - startingLine) / hunkLineCount) * hunkLineCount;
		const finalHunkBufferOffset = (startingLine + totalLines) / hunkLineCount;
		const bufferBefore = hunkOffsets[startingLine / hunkLineCount] ?? 0;
		const bufferAfter = finalHunkBufferOffset < hunkOffsets.length ? fileHeight - headerRegion - hunkOffsets[finalHunkBufferOffset] - fileGap : 0;
		return {
			startingLine,
			totalLines,
			bufferBefore,
			bufferAfter
		};
	}
};
function getSpecs(instance, type = "split") {
	if (type === "split") return {
		lineCount: instance.fileDiff.splitLineCount,
		fileTop: instance.splitTop,
		fileHeight: instance.splitHeight
	};
	return {
		lineCount: instance.fileDiff.unifiedLineCount,
		fileTop: instance.unifiedTop,
		fileHeight: instance.unifiedHeight
	};
}

//#endregion
export { AdvancedVirtualizedFileDiff };
//# sourceMappingURL=AdvancedVirtualizedFileDiff.js.map