import { currentTimeContext } from "../../currentTimeContext.js";
import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { ICONS, phosphorIcon } from "../../icons.js";
import { getElementTypeColor } from "../../theme.js";
import { TrackItem } from "./TrackItem.js";
import { consume } from "@lit/context";
import { css, html, nothing } from "lit";
import { customElement } from "lit/decorators.js";
import { styleMap } from "lit/directives/style-map.js";

//#region src/gui/timeline/tracks/CaptionsTrack.ts
let measurementCanvas = null;
let measurementContext = null;
const textMeasurementCache = /* @__PURE__ */ new Map();
const MAX_CACHE_SIZE = 500;
/**
* Measure text width accurately using canvas.
* Matches the actual font used in word elements (font-weight: 500).
* Results are cached to avoid repeated measurements of the same text.
*/
function measureTextWidth(text, fontSize, fontWeight = 500) {
	const cacheKey = `${text}:${fontSize}:${fontWeight}`;
	const cached = textMeasurementCache.get(cacheKey);
	if (cached !== void 0) return cached;
	if (!measurementCanvas || !measurementContext) {
		measurementCanvas = document.createElement("canvas");
		measurementContext = measurementCanvas.getContext("2d");
	}
	if (!measurementContext) return text.length * fontSize * .6;
	measurementContext.font = `${fontWeight} ${fontSize}px ${getComputedStyle(document.body).fontFamily || "system-ui, sans-serif"}`;
	const width = measurementContext.measureText(text).width;
	if (textMeasurementCache.size >= MAX_CACHE_SIZE) {
		const keysToDelete = Array.from(textMeasurementCache.keys()).slice(0, MAX_CACHE_SIZE / 2);
		for (const key of keysToDelete) textMeasurementCache.delete(key);
	}
	textMeasurementCache.set(cacheKey, width);
	return width;
}
/**
* Check if words can fit individually within a segment when positioned by time
*
* Strategy: Allow overlaps as long as all words can be rendered within the container.
* Only use compact mode when words are so cramped they can't be displayed at all.
*/
function canWordsFitIndividually(words, segmentStart, segmentWidthPx, pixelsPerMs) {
	if (words.length === 0) return {
		fits: false,
		reason: "no words"
	};
	let totalTextWidth = 0;
	const wordWidths = [];
	for (const word of words) {
		if (!word) continue;
		const textWidth = measureTextWidth(word.text.trim(), 9, 500) + 4;
		const startPx = pixelsPerMs * (word.start - segmentStart) * 1e3;
		const endPx = pixelsPerMs * (word.end - segmentStart) * 1e3;
		const timeWidth = endPx - startPx;
		wordWidths.push({
			textWidth,
			timeWidth,
			startPx,
			endPx
		});
		totalTextWidth += textWidth;
	}
	if (totalTextWidth <= segmentWidthPx * .9) return { fits: true };
	for (const { textWidth, timeWidth } of wordWidths) if (timeWidth < textWidth * .3) return {
		fits: false,
		reason: `word too narrow (${timeWidth.toFixed(1)}px < ${(textWidth * .3).toFixed(1)}px)`
	};
	if (Math.max(...wordWidths.map((w) => w.endPx)) <= segmentWidthPx * 1.1) return { fits: true };
	return {
		fits: false,
		reason: `words exceed segment (total text: ${totalTextWidth.toFixed(1)}px, segment: ${segmentWidthPx.toFixed(1)}px)`
	};
}
let EFCaptionsTrack = class EFCaptionsTrack$1 extends TrackItem {
	constructor(..._args) {
		super(..._args);
		this.contextCurrentTimeMs = 0;
		this.lastPixelsPerMs = 0;
	}
	static {
		this.styles = [...TrackItem.styles, css`
      .segment-block {
        position: absolute;
        border-radius: 3px;
        transition: box-shadow 0.15s ease, z-index 0.15s ease;
        cursor: pointer;
        overflow: visible;
      }
      
      .segment-block:hover {
        box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
        z-index: 5;
      }
      
      .word-element {
        position: absolute;
        font-size: 9px;
        line-height: 1.2;
        white-space: nowrap;
        font-weight: 500;
        top: 50%;
        transform: translateY(-50%);
        padding: 2px 4px;
        border-radius: 2px;
        transition: all 0.1s ease;
        background: var(--ef-color-bg-elevated);
        color: var(--ef-color-text);
        z-index: 1;
      }
      
      .word-element.active {
        background: var(--ef-color-success);
        color: rgb(20, 30, 20);
        font-weight: 700;
        font-size: 10px;
        z-index: 10;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
      }
      
      .word-element.future {
        background: var(--ef-color-bg-inset);
        color: var(--ef-color-text);
        z-index: 5;
      }
      
      .segment-block.active .word-element:not(.active):not(.future) {
        color: var(--ef-color-text-muted);
        background: var(--ef-color-bg-elevated);
      }
      
      /* Compact text mode - when words are too small to position individually */
      .segment-block.compact-text {
        display: flex;
        align-items: center;
        padding: 0 4px;
        overflow: hidden;
        /* Keep position: absolute from .segment-block for correct time-based positioning */
      }
      
      /* Allow overflow on hover for compact text */
      .segment-block.compact-text:hover {
        overflow: visible;
        z-index: 100;
        /* Expand to fit content on hover */
        width: max-content !important;
        min-width: max-content;
        background: var(--ef-color-bg-elevated) !important;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
      }
      
      .segment-text-compact {
        font-size: 10px;
        line-height: 1.2;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        color: var(--ef-color-text);
        width: 100%;
      }
      
      /* On hover, show full text */
      .segment-block.compact-text:hover .segment-text-compact {
        overflow: visible;
        text-overflow: clip;
      }
      
      .segment-block.compact-text.active .segment-text-compact {
        color: var(--ef-color-text-muted);
        font-weight: 500;
      }
      
      .segment-duration-indicator {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        height: 2px;
        background: currentColor;
        opacity: 0.2;
        border-radius: 0 0 3px 3px;
      }
      
      .segment-block.active .segment-duration-indicator {
        opacity: 0.4;
        height: 2px;
      }
      
      .word-marker {
        position: absolute;
        bottom: 0;
        width: 1px;
        height: 30%;
        background: var(--ef-color-border-subtle);
        pointer-events: none;
      }
      
      .word-marker.active {
        background: var(--ef-color-text);
        height: 50%;
        width: 2px;
      }
    `];
	}
	updated(changedProperties) {
		super.updated(changedProperties);
		if (changedProperties.has("pixelsPerMs")) {
			const currentPixelsPerMs = this.pixelsPerMs;
			if (currentPixelsPerMs !== this.lastPixelsPerMs) {
				this.lastPixelsPerMs = currentPixelsPerMs;
				this.requestUpdate();
			}
		}
	}
	render() {
		const captionsData = this.element.unifiedCaptionsDataTask.value;
		return html`<div style=${styleMap(this.gutterStyles)}>
      <div
        class="relative"
        style="background-color: var(--filmstrip-bg);"
        ?data-focused=${this.isFocused}
        @mouseenter=${() => {
			if (this.focusContext) this.focusContext.focusedElement = this.element;
		}}
        @mouseleave=${() => {
			if (this.focusContext) this.focusContext.focusedElement = null;
		}}
      >
        <div
          ?data-focused=${this.isFocused}
          class="trim-container relative mb-0 block text-nowrap border text-sm overflow-visible"
          style=${styleMap({
			...this.trimPortionStyles,
			height: "var(--timeline-track-height, 22px)",
			backgroundColor: this.isFocused ? "var(--filmstrip-item-focused)" : "var(--filmstrip-item-bg)",
			borderColor: "var(--filmstrip-border)",
			borderLeftColor: this.getElementTypeColor(),
			borderLeftWidth: "3px",
			minHeight: "22px"
		})}
        >
          ${this.renderCaptionsData(captionsData)}
          ${this.enableTrim ? html`<ef-trim-handles
                element-id=${this.element.id || ""}
                pixels-per-ms=${this.pixelsPerMs}
                trim-start-ms=${this.element.trimStartMs ?? 0}
                trim-end-ms=${this.element.trimEndMs ?? 0}
                intrinsic-duration-ms=${this.element.intrinsicDurationMs ?? this.element.durationMs}
                @trim-change=${this.handleTrimChange}
              ></ef-trim-handles>` : nothing}
        </div>
      </div>
      ${this.renderChildren()}
    </div>`;
	}
	renderCaptionsData(captionsData) {
		if (!captionsData) return html``;
		const captions = this.element;
		const rootTimegroup = captions.rootTimegroup;
		const captionsLocalTimeSec = ((this.contextCurrentTimeMs || rootTimegroup?.currentTimeMs || 0) - captions.startTimeMs) / 1e3;
		const captionColor = getElementTypeColor("captions", this);
		const activeWord = captionsData.word_segments.find((word) => captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end);
		return html`
      ${captionsData.word_segments.map((word) => {
			const wordStartPx = this.pixelsPerMs * word.start * 1e3;
			const wordWidth = this.pixelsPerMs * (word.end - word.start) * 1e3;
			const isActive = word === activeWord;
			if (wordWidth < 1.5) return nothing;
			return html`<div
        class="word-marker ${isActive ? "active" : ""}"
        style=${styleMap({ left: `${wordStartPx}px` })}
      ></div>`;
		})}
      ${captionsData.segments.map((segment) => {
			const isActiveSegment = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
			const segmentStartPx = this.pixelsPerMs * segment.start * 1e3;
			const segmentWidth = this.pixelsPerMs * (segment.end - segment.start) * 1e3;
			const segmentDuration = (segment.end - segment.start) * 1e3;
			const wordsInSegment = captionsData.word_segments.filter((word) => word.start >= segment.start && word.end <= segment.end).sort((a, b) => a.start - b.start);
			const density = Math.min(wordsInSegment.length / 10, 1);
			const useCompactText = !canWordsFitIndividually(wordsInSegment, segment.start, segmentWidth, this.pixelsPerMs).fits;
			let avgSpacing = 0;
			if (!useCompactText && wordsInSegment.length > 1) {
				let totalSpacing = 0;
				let spacingCount = 0;
				for (let i = 0; i < wordsInSegment.length - 1; i++) {
					const word1 = wordsInSegment[i];
					const word2 = wordsInSegment[i + 1];
					if (!word1 || !word2) continue;
					const word1EndPx = this.pixelsPerMs * (word1.end - segment.start) * 1e3;
					const spacing = this.pixelsPerMs * (word2.start - segment.start) * 1e3 - word1EndPx;
					if (spacing > 0) {
						totalSpacing += spacing;
						spacingCount++;
					}
				}
				avgSpacing = spacingCount > 0 ? totalSpacing / spacingCount : 0;
			}
			const MIN_READABLE_FONT_SIZE = 6;
			const baseFontSize = 9;
			const activeFontSize = 10;
			let scaledFontSize = baseFontSize;
			let scaledActiveFontSize = activeFontSize;
			if (!useCompactText && wordsInSegment.length > 1 && avgSpacing < 8) {
				const scaleFactor = Math.max(MIN_READABLE_FONT_SIZE / baseFontSize, avgSpacing / 8);
				scaledFontSize = Math.max(MIN_READABLE_FONT_SIZE, baseFontSize * scaleFactor);
				scaledActiveFontSize = Math.max(MIN_READABLE_FONT_SIZE, activeFontSize * scaleFactor);
			}
			const renderWords = () => {
				if (useCompactText) return html`
            <span class="segment-text-compact">${segment.text}</span>
          `;
				return wordsInSegment.map((word) => {
					const wordOffsetFromSegmentStart = (word.start - segment.start) * 1e3;
					const wordLeftPx = this.pixelsPerMs * wordOffsetFromSegmentStart;
					const wordWidthPx = this.pixelsPerMs * (word.end - word.start) * 1e3;
					const isActive = word === activeWord;
					const isFuture = activeWord && word.start > activeWord.end;
					return html`
            <span
              class="word-element ${isActive ? "active" : ""} ${isFuture ? "future" : ""}"
              style=${styleMap({
						left: `${wordLeftPx}px`,
						minWidth: `${Math.max(wordWidthPx, 8)}px`,
						fontSize: isActive ? `${scaledActiveFontSize}px` : `${scaledFontSize}px`,
						top: "50%"
					})}
              title="Word: '${word.text}' (${word.start.toFixed(2)}s - ${word.end.toFixed(2)}s)"
            >
              ${word.text.trim()}
            </span>
          `;
				});
			};
			return html`<div
        class="segment-block ${isActiveSegment ? "active" : ""} ${useCompactText ? "compact-text" : ""}"
        style=${styleMap({
				left: `${segmentStartPx}px`,
				width: `${Math.max(segmentWidth, 4)}px`,
				height: "100%",
				top: "0px",
				backgroundColor: isActiveSegment ? `color-mix(in srgb, var(--ef-color-type-captions) ${30 + density * 20}%, transparent)` : `color-mix(in srgb, var(--ef-color-type-captions) ${10 + density * 10}%, transparent)`,
				borderColor: isActiveSegment ? captionColor : `color-mix(in srgb, var(--ef-color-type-captions) 40%, transparent)`,
				minWidth: segmentWidth < 20 ? "20px" : "auto"
			})}
        title=${useCompactText ? `Caption: '${segment.text}'\nDuration: ${this.formatDuration(segmentDuration)}\nTime: ${segment.start.toFixed(2)}s - ${segment.end.toFixed(2)}s` : `Caption: '${segment.text}'\nDuration: ${this.formatDuration(segmentDuration)}\nTime: ${segment.start.toFixed(2)}s - ${segment.end.toFixed(2)}s\nWords: ${wordsInSegment.length}`}
        @click=${(e) => {
				e.stopPropagation();
				if (rootTimegroup) rootTimegroup.currentTimeMs = captions.startTimeMs + segment.start * 1e3;
			}}
      >
        ${renderWords()}
        ${!useCompactText ? html`<div class="segment-duration-indicator"></div>` : nothing}
      </div>`;
		})}
    `;
	}
	renderChildren() {
		return nothing;
	}
};
__decorate([consume({
	context: currentTimeContext,
	subscribe: true
})], EFCaptionsTrack.prototype, "contextCurrentTimeMs", void 0);
EFCaptionsTrack = __decorate([customElement("ef-captions-track")], EFCaptionsTrack);
let EFCaptionsActiveWordTrack = class EFCaptionsActiveWordTrack$1 extends TrackItem {
	get captionsTrackStyles() {
		const parentCaptions = this.element.closest("ef-captions");
		return {
			position: "relative",
			left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
			width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
		};
	}
	render() {
		const parentCaptions = this.element.closest("ef-captions");
		const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
		if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
        <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
          ${phosphorIcon(ICONS.microphone)} Active Word
        </div>
      </div>`;
		const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
		return html`<div style=${styleMap(this.captionsTrackStyles)}>
      <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
        ${captionsData.word_segments.map((word) => {
			const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
			return html`<div
            class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
            style=${styleMap({
				left: `${this.pixelsPerMs * word.start * 1e3}px`,
				width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
				height: "100%",
				top: "0px",
				backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-item-bg)",
				borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-border)"
			})}
            title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
          >
            ${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap" style="background-color: var(--filmstrip-caption-bg);">${word.text.trim()}</span>` : ""}
          </div>`;
		})}
      </div>
    </div>`;
	}
};
EFCaptionsActiveWordTrack = __decorate([customElement("ef-captions-active-word-track")], EFCaptionsActiveWordTrack);
let EFCaptionsSegmentTrack = class EFCaptionsSegmentTrack$1 extends TrackItem {
	get captionsTrackStyles() {
		const parentCaptions = this.element.closest("ef-captions");
		return {
			position: "relative",
			left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
			width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
		};
	}
	render() {
		const parentCaptions = this.element.closest("ef-captions");
		const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
		if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
        <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
          ${phosphorIcon(ICONS.textT)} Segment
        </div>
      </div>`;
		const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
		return html`<div style=${styleMap(this.captionsTrackStyles)}>
      <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
        ${captionsData.segments.map((segment) => {
			const isCurrentlyActive = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
			return html`<div
            class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
            style=${styleMap({
				left: `${this.pixelsPerMs * segment.start * 1e3}px`,
				width: `${this.pixelsPerMs * (segment.end - segment.start) * 1e3}px`,
				height: "100%",
				top: "0px",
				backgroundColor: isCurrentlyActive ? "var(--filmstrip-segment-bg)" : "var(--filmstrip-item-bg)",
				borderColor: isCurrentlyActive ? "var(--filmstrip-segment-border)" : "var(--filmstrip-border)"
			})}
            title="Segment: '${segment.text}' (${segment.start}s - ${segment.end}s)"
          >
            ${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap" style="background-color: var(--filmstrip-segment-bg);">${segment.text}</span>` : ""}
          </div>`;
		})}
      </div>
    </div>`;
	}
};
EFCaptionsSegmentTrack = __decorate([customElement("ef-captions-segment-track")], EFCaptionsSegmentTrack);
let EFCaptionsBeforeWordTrack = class EFCaptionsBeforeWordTrack$1 extends TrackItem {
	get captionsTrackStyles() {
		const parentCaptions = this.element.closest("ef-captions");
		return {
			position: "relative",
			left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
			width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
		};
	}
	render() {
		const parentCaptions = this.element.closest("ef-captions");
		const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
		if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
        <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
          ${phosphorIcon(ICONS.arrowLeft)} Before
        </div>
      </div>`;
		const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
		return html`<div style=${styleMap(this.captionsTrackStyles)}>
      <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
        ${captionsData.word_segments.map((word) => {
			const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
			return html`<div
            class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
            style=${styleMap({
				left: `${this.pixelsPerMs * word.start * 1e3}px`,
				width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
				height: "100%",
				top: "0px",
				backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-waveform-bg)",
				borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-waveform-border)"
			})}
            title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
          >
          </div>`;
		})}
      </div>
    </div>`;
	}
};
EFCaptionsBeforeWordTrack = __decorate([customElement("ef-captions-before-word-track")], EFCaptionsBeforeWordTrack);
let EFCaptionsAfterWordTrack = class EFCaptionsAfterWordTrack$1 extends TrackItem {
	get captionsTrackStyles() {
		const parentCaptions = this.element.closest("ef-captions");
		return {
			position: "relative",
			left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
			width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
		};
	}
	render() {
		const parentCaptions = this.element.closest("ef-captions");
		const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
		if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
        <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
          ${phosphorIcon(ICONS.arrowRight)} After
        </div>
      </div>`;
		const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
		return html`<div style=${styleMap(this.captionsTrackStyles)}>
      <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
        ${captionsData.word_segments.map((word) => {
			const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
			return html`<div
            class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
            style=${styleMap({
				left: `${this.pixelsPerMs * word.start * 1e3}px`,
				width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
				height: "100%",
				top: "0px",
				backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-waveform-bg)",
				borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-waveform-border)"
			})}
            title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
          >
          </div>`;
		})}
      </div>
    </div>`;
	}
};
EFCaptionsAfterWordTrack = __decorate([customElement("ef-captions-after-word-track")], EFCaptionsAfterWordTrack);

//#endregion
//# sourceMappingURL=CaptionsTrack.js.map