import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
import { EFMedia } from "./EFMedia.js";
import { TWMixin } from "../gui/TWMixin2.js";
import { DelayedLoadingState } from "../DelayedLoadingState.js";
import { makeScrubVideoBufferTask } from "./EFMedia/videoTasks/makeScrubVideoBufferTask.js";
import { makeScrubVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js";
import { makeScrubVideoInputTask } from "./EFMedia/videoTasks/makeScrubVideoInputTask.js";
import { makeScrubVideoSeekTask } from "./EFMedia/videoTasks/makeScrubVideoSeekTask.js";
import { makeScrubVideoSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js";
import { makeScrubVideoSegmentIdTask } from "./EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js";
import { makeUnifiedVideoSeekTask } from "./EFMedia/videoTasks/makeUnifiedVideoSeekTask.js";
import { makeVideoBufferTask } from "./EFMedia/videoTasks/makeVideoBufferTask.js";
import { Task } from "@lit/task";
import debug from "debug";
import { css, html } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import _decorate from "@oxc-project/runtime/helpers/decorate";
import { createRef, ref } from "lit/directives/ref.js";
const log = debug("ef:elements:EFVideo");
let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
	static {
		this.styles = [css`
      :host {
        display: block;
        position: relative;
      }
      canvas {
        all: inherit;
        overflow: hidden;
        position: static;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
        border: none;
        outline: none;
        box-shadow: none;
      }
      .loading-overlay {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(0, 0, 0, 0.6);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 10;
        backdrop-filter: blur(2px);
      }
      .loading-content {
        background: rgba(0, 0, 0, 0.8);
        border-radius: 8px;
        padding: 16px 24px;
        display: flex;
        align-items: center;
        gap: 12px;
        color: white;
        font-size: 14px;
        font-weight: 500;
      }
      .loading-spinner {
        width: 20px;
        height: 20px;
        border: 2px solid rgba(255, 255, 255, 0.2);
        border-left: 2px solid #fff;
        border-radius: 50%;
        animation: spin 1s linear infinite;
      }
      @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      .loading-message {
        font-size: 12px;
        opacity: 0.8;
      }
    `];
	}
	constructor() {
		super();
		this.canvasRef = createRef();
		this.videoBufferDurationMs = 1e4;
		this.maxVideoBufferFetches = 2;
		this.enableVideoBuffering = true;
		this.unifiedVideoSeekTask = makeUnifiedVideoSeekTask(this);
		this.videoBufferTask = makeVideoBufferTask(this);
		this.scrubVideoBufferTask = makeScrubVideoBufferTask(this);
		this.scrubVideoInputTask = makeScrubVideoInputTask(this);
		this.scrubVideoSeekTask = makeScrubVideoSeekTask(this);
		this.scrubVideoSegmentIdTask = makeScrubVideoSegmentIdTask(this);
		this.scrubVideoSegmentFetchTask = makeScrubVideoSegmentFetchTask(this);
		this.scrubVideoInitSegmentFetchTask = makeScrubVideoInitSegmentFetchTask(this);
		this.loadingState = {
			isLoading: false,
			operation: null,
			message: ""
		};
		this.frameTask = new Task(this, {
			autoRun: EF_INTERACTIVE,
			args: () => [this.desiredSeekTimeMs],
			onError: (error) => {
				console.error("frameTask error", error);
			},
			onComplete: () => {},
			task: async ([_desiredSeekTimeMs], { signal }) => {
				await this.unifiedVideoSeekTask.taskComplete;
				await this.paintTask.taskComplete;
				if (signal.aborted) return;
			}
		});
		this.paintTask = new Task(this, {
			args: () => [this.desiredSeekTimeMs],
			onError: (error) => {
				console.error("paintTask error", error);
			},
			onComplete: () => {},
			task: async ([_seekToMs], { signal }) => {
				const isProductionRendering = this.isInProductionRenderingMode();
				try {
					await this.unifiedVideoSeekTask.taskComplete;
					const videoSample = this.unifiedVideoSeekTask.value;
					if (videoSample) {
						const videoFrame = videoSample.toVideoFrame();
						try {
							this.displayFrame(videoFrame, _seekToMs);
						} finally {
							videoFrame.close();
						}
					}
				} catch (error) {
					console.warn("Unified video pipeline error:", error);
				}
				if (!isProductionRendering) {
					if (!this.rootTimegroup || this.rootTimegroup.currentTimeMs === 0 && this.desiredSeekTimeMs === 0) return;
				} else {
					if (!this.rootTimegroup) return;
					if (!this.isFrameRenderingActive()) return;
				}
				if (signal.aborted) return;
			}
		});
		this.delayedLoadingState = new DelayedLoadingState(250, (isLoading, message) => {
			this.setLoadingState(isLoading, null, message);
		});
	}
	render() {
		return html`
      <canvas ${ref(this.canvasRef)}></canvas>
      ${this.loadingState.isLoading ? html`
        <div class="loading-overlay">
          <div class="loading-content">
            <div class="loading-spinner"></div>
            <div>
              <div>Loading Video...</div>
              <div class="loading-message">${this.loadingState.message}</div>
            </div>
          </div>
        </div>
      ` : ""}
    `;
	}
	get canvasElement() {
		const referencedCanvas = this.canvasRef.value;
		if (referencedCanvas) return referencedCanvas;
		const shadowCanvas = this.shadowRoot?.querySelector("canvas");
		if (shadowCanvas) return shadowCanvas;
		return void 0;
	}
	updated(changedProperties) {
		super.updated(changedProperties);
	}
	/**
	* Start a delayed loading operation for testing
	*/
	startDelayedLoading(operationId, message, options = {}) {
		this.delayedLoadingState.startLoading(operationId, message, options);
	}
	/**
	* Clear a delayed loading operation for testing
	*/
	clearDelayedLoading(operationId) {
		this.delayedLoadingState.clearLoading(operationId);
	}
	/**
	* Set loading state for user feedback
	*/
	setLoadingState(isLoading, operation = null, message = "") {
		this.loadingState = {
			isLoading,
			operation,
			message
		};
	}
	/**
	* Display a video frame on the canvas
	*/
	displayFrame(frame, seekToMs) {
		log("trace: displayFrame start", {
			seekToMs,
			frameFormat: frame.format
		});
		if (!this.canvasElement) {
			log("trace: displayFrame aborted - no canvas element");
			throw new Error(`Frame display failed: Canvas element is not available at time ${seekToMs}ms. The video component may not be properly initialized.`);
		}
		const ctx = this.canvasElement.getContext("2d");
		if (!ctx) {
			log("trace: displayFrame aborted - no canvas context");
			throw new Error(`Frame display failed: Unable to get 2D canvas context at time ${seekToMs}ms. This may indicate a browser compatibility issue or canvas corruption.`);
		}
		if (frame?.codedWidth && frame?.codedHeight) {
			if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
				log("trace: updating canvas dimensions", {
					width: frame.codedWidth,
					height: frame.codedHeight
				});
				this.canvasElement.width = frame.codedWidth;
				this.canvasElement.height = frame.codedHeight;
			}
		}
		if (frame.format === null) {
			log("trace: displayFrame aborted - null frame format");
			throw new Error(`Frame display failed: Video frame has null format at time ${seekToMs}ms. This indicates corrupted or incompatible video data.`);
		}
		log("trace: drawing frame to canvas", frame.timestamp / 1e3);
		ctx.drawImage(frame, 0, 0, this.canvasElement.width, this.canvasElement.height);
		log("trace: frame drawn to canvas", { seekToMs });
		return seekToMs;
	}
	/**
	* Check if we're in production rendering mode (EF_FRAMEGEN active) vs preview mode
	*/
	isInProductionRenderingMode() {
		if (typeof window.EF_RENDERING === "function") return window.EF_RENDERING();
		const workbench = document.querySelector("ef-workbench");
		if (workbench?.rendering) return true;
		if (window.EF_FRAMEGEN?.renderOptions) return true;
		return false;
	}
	/**
	* Check if EF_FRAMEGEN has explicitly started frame rendering (not just initialization)
	*/
	isFrameRenderingActive() {
		if (!window.EF_FRAMEGEN?.renderOptions) return false;
		const renderOptions = window.EF_FRAMEGEN.renderOptions;
		const renderStartTime = renderOptions.encoderOptions.fromMs;
		const currentTime = this.rootTimegroup?.currentTimeMs || 0;
		return currentTime >= renderStartTime;
	}
	/**
	* Legacy getter for fragment index task
	* Still used by EFCaptions - maps to unified video seek task
	*/
	get fragmentIndexTask() {
		return this.unifiedVideoSeekTask;
	}
	/**
	* Clean up resources when component is disconnected
	*/
	disconnectedCallback() {
		super.disconnectedCallback();
		this.delayedLoadingState.clearAllLoading();
	}
};
_decorate([property({
	type: Number,
	attribute: "video-buffer-duration"
})], EFVideo.prototype, "videoBufferDurationMs", void 0);
_decorate([property({
	type: Number,
	attribute: "max-video-buffer-fetches"
})], EFVideo.prototype, "maxVideoBufferFetches", void 0);
_decorate([property({
	type: Boolean,
	attribute: "enable-video-buffering"
})], EFVideo.prototype, "enableVideoBuffering", void 0);
_decorate([state()], EFVideo.prototype, "loadingState", void 0);
EFVideo = _decorate([customElement("ef-video")], EFVideo);
export { EFVideo };
