import { __decorate } from "../../../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { EFVideo } from "../../../elements/EFVideo.js";
import { TrackItem } from "./TrackItem.js";
import { extractWaveformData } from "./waveformUtils.js";
import { timelineStateContext } from "../timelineStateContext.js";
import "./EFThumbnailStrip.js";
import { consume } from "@lit/context";
import { css, html, nothing } from "lit";
import { customElement, state } from "lit/decorators.js";
import { styleMap } from "lit/directives/style-map.js";
import { createRef, ref } from "lit/directives/ref.js";

//#region src/gui/timeline/tracks/VideoTrack.ts
/** Padding for virtual rendering */
const VIRTUAL_RENDER_PADDING_PX = 100;
/** Height of thumbnail section */
const THUMBNAIL_HEIGHT = 24;
/** Height of audio section when present */
const AUDIO_SECTION_HEIGHT = 14;
let EFVideoTrack = class EFVideoTrack$1 extends TrackItem {
	constructor(..._args) {
		super(..._args);
		this.audioCanvasRef = createRef();
		this._waveformData = null;
		this._hasAudio = false;
	}
	static {
		this.styles = [...TrackItem.styles, css`
      .video-content {
        display: flex;
        flex-direction: column;
        height: 100%;
      }
      .thumbnail-section {
        position: relative;
        flex: 0 0 ${THUMBNAIL_HEIGHT}px;
        height: ${THUMBNAIL_HEIGHT}px;
        background: var(--ef-color-bg-inset);
      }
      .audio-section {
        position: relative;
        flex: 0 0 ${AUDIO_SECTION_HEIGHT}px;
        height: ${AUDIO_SECTION_HEIGHT}px;
        background: var(--ef-color-bg-elevated);
        border-top: 1px solid var(--ef-color-border-subtle);
        overflow: hidden;
      }
      .audio-section-canvas {
        position: absolute;
        top: 0;
        height: 100%;
      }
    `];
	}
	#lastSrc = null;
	#abortController = null;
	#renderRequested = false;
	/**
	* Check if video has audio and load waveform data
	*/
	async #checkAndLoadAudioWaveform() {
		const video = this.element;
		const src = video?.src;
		if (!src || src === this.#lastSrc) return;
		this.#lastSrc = src;
		this._hasAudio = false;
		this._waveformData = null;
		this.#abortController?.abort();
		this.#abortController = new AbortController();
		try {
			if (video.mediaEngineTask) {
				if ((await video.mediaEngineTask.taskComplete)?.tracks.audio) {
					this._hasAudio = true;
					const waveformData = await extractWaveformData(video, this.#abortController.signal);
					if (waveformData) {
						this._waveformData = waveformData;
						this.#scheduleRender();
					}
				}
			}
		} catch (error) {
			if (!(error instanceof DOMException && error.name === "AbortError")) {}
		}
	}
	#scheduleRender() {
		if (this.#renderRequested) return;
		this.#renderRequested = true;
		requestAnimationFrame(() => {
			this.#renderRequested = false;
			this.#renderAudioOverlay();
		});
	}
	#renderAudioOverlay() {
		const canvas = this.audioCanvasRef.value;
		const waveformData = this._waveformData;
		if (!canvas || !waveformData || !this._hasAudio) return;
		const video = this.element;
		const durationMs = video.durationMs ?? 0;
		if (durationMs === 0) return;
		const pixelsPerMs = this._timelineState?.pixelsPerMs ?? this.pixelsPerMs;
		const trackWidthPx = durationMs * pixelsPerMs;
		const trackStartPx = (video.startTimeMs ?? 0) * pixelsPerMs;
		const scrollLeft = this._timelineState?.viewportScrollLeft ?? 0;
		const viewportWidth = this._timelineState?.viewportWidth ?? 800;
		const visibleLeftPx = scrollLeft - VIRTUAL_RENDER_PADDING_PX;
		const visibleRightPx = scrollLeft + viewportWidth + VIRTUAL_RENDER_PADDING_PX;
		if (trackStartPx + trackWidthPx < visibleLeftPx || trackStartPx > visibleRightPx) {
			canvas.style.display = "none";
			return;
		}
		canvas.style.display = "block";
		const visibleStartInTrack = Math.max(0, visibleLeftPx - trackStartPx);
		const visibleEndInTrack = Math.min(trackWidthPx, visibleRightPx - trackStartPx);
		const visibleWidthPx = visibleEndInTrack - visibleStartInTrack;
		if (visibleWidthPx <= 0) return;
		const height = AUDIO_SECTION_HEIGHT;
		const dpr = window.devicePixelRatio || 1;
		const targetWidth = Math.ceil(visibleWidthPx * dpr);
		const targetHeight = Math.ceil(height * dpr);
		if (canvas.width !== targetWidth || canvas.height !== targetHeight) {
			canvas.width = targetWidth;
			canvas.height = targetHeight;
		}
		canvas.style.left = `${visibleStartInTrack}px`;
		canvas.style.width = `${visibleWidthPx}px`;
		const ctx = canvas.getContext("2d");
		if (!ctx) return;
		ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
		ctx.clearRect(0, 0, visibleWidthPx, height);
		const sourceInMs = video.sourceStartMs ?? 0;
		const timeStartMs = sourceInMs + visibleStartInTrack / pixelsPerMs;
		const timeEndMs = sourceInMs + visibleEndInTrack / pixelsPerMs;
		this.#drawAudioWaveform(ctx, waveformData, visibleWidthPx, height, timeStartMs, timeEndMs);
	}
	#drawAudioWaveform(ctx, waveformData, width, height, startMs, endMs) {
		const { peaks, samplesPerSecond } = waveformData;
		const startSample = Math.floor(startMs / 1e3 * samplesPerSecond);
		const sampleCount = Math.ceil(endMs / 1e3 * samplesPerSecond) - startSample;
		if (sampleCount <= 0 || width <= 0) return;
		const centerY = height / 2;
		const halfHeight = height / 2 - 1;
		const pixelsPerSample = width / sampleCount;
		ctx.fillStyle = getComputedStyle(this).getPropertyValue("--ef-color-success").trim() || "rgb(74, 222, 128)";
		ctx.globalAlpha = .9;
		ctx.beginPath();
		for (let i = 0; i <= sampleCount; i++) {
			const peakIndex = (startSample + i) * 2;
			if (peakIndex + 1 >= peaks.length) break;
			const maxValue = peaks[peakIndex + 1] ?? 0;
			const px = i * pixelsPerSample;
			const py = centerY - maxValue * halfHeight;
			if (i === 0) ctx.moveTo(px, py);
			else ctx.lineTo(px, py);
		}
		for (let i = sampleCount; i >= 0; i--) {
			const peakIndex = (startSample + i) * 2;
			if (peakIndex >= peaks.length) continue;
			const minValue = peaks[peakIndex] ?? 0;
			const px = i * pixelsPerSample;
			const py = centerY - minValue * halfHeight;
			ctx.lineTo(px, py);
		}
		ctx.closePath();
		ctx.fill();
		ctx.globalAlpha = .3;
		ctx.strokeStyle = getComputedStyle(this).getPropertyValue("--ef-color-success").trim() || "rgb(74, 222, 128)";
		ctx.lineWidth = 1;
		ctx.beginPath();
		ctx.moveTo(0, centerY);
		ctx.lineTo(width, centerY);
		ctx.stroke();
		ctx.globalAlpha = 1;
	}
	connectedCallback() {
		super.connectedCallback();
		this.#checkAndLoadAudioWaveform();
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#abortController?.abort();
	}
	updated(changedProperties) {
		super.updated(changedProperties);
		if (this.element?.src !== this.#lastSrc) this.#checkAndLoadAudioWaveform();
		if (changedProperties.has("_timelineState") || changedProperties.has("_waveformData")) this.#scheduleRender();
		if (this._waveformData) this.#scheduleRender();
	}
	/**
	* Get the total track height based on whether audio is present
	*/
	#getTrackHeight() {
		if (this._hasAudio && this._waveformData) return THUMBNAIL_HEIGHT + AUDIO_SECTION_HEIGHT;
		return THUMBNAIL_HEIGHT;
	}
	render() {
		const video = this.element;
		const elementId = this.element.id || "";
		if (!(video instanceof EFVideo)) return html``;
		const trimStartMs = this.element.trimStartMs ?? 0;
		const trimEndMs = this.element.trimEndMs ?? 0;
		const intrinsicDurationMs = this.element.intrinsicDurationMs ?? this.element.durationMs;
		const trackHeight = this.#getTrackHeight();
		const hasAudioSection = this._hasAudio && this._waveformData;
		const typeColor = this.getElementTypeColor();
		return html`<div style=${styleMap(this.gutterStyles)}>
      <div
        ?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"
          style=${styleMap({
			...this.trimPortionStyles,
			height: `${trackHeight}px`,
			backgroundColor: this.isFocused ? "color-mix(in srgb, var(--ef-color-primary) 25%, transparent)" : "var(--ef-color-bg-inset)",
			borderLeft: `3px solid ${typeColor}`,
			borderRadius: "3px"
		})}
        >
          <div class="video-content">
            <div class="thumbnail-section">
              <ef-thumbnail-strip
                .targetElement=${this.element}
                thumbnail-height=${THUMBNAIL_HEIGHT}
                thumbnail-spacing-px="48"
                pixels-per-ms=${this.pixelsPerMs}
              ></ef-thumbnail-strip>
            </div>
            ${hasAudioSection ? html`<div class="audio-section">
                  <canvas ${ref(this.audioCanvasRef)} class="audio-section-canvas"></canvas>
                </div>` : nothing}
          </div>
          ${this.enableTrim ? html`<ef-trim-handles
                element-id=${elementId}
                pixels-per-ms=${this.pixelsPerMs}
                trim-start-ms=${trimStartMs}
                trim-end-ms=${trimEndMs}
                intrinsic-duration-ms=${intrinsicDurationMs}
                @trim-change=${this.handleTrimChange}
              ></ef-trim-handles>` : nothing}
        </div>
      </div>
      ${this.renderChildren()}
    </div>`;
	}
};
__decorate([consume({
	context: timelineStateContext,
	subscribe: true
}), state()], EFVideoTrack.prototype, "_timelineState", void 0);
__decorate([state()], EFVideoTrack.prototype, "_waveformData", void 0);
__decorate([state()], EFVideoTrack.prototype, "_hasAudio", void 0);
EFVideoTrack = __decorate([customElement("ef-video-track")], EFVideoTrack);

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