import { efContext } from "./efContext.js";
import { currentTimeContext } from "./currentTimeContext.js";
import { durationContext } from "./durationContext.js";
import { loopContext, playingContext } from "./playingContext.js";
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { isEFTemporal } from "../elements/EFTemporal.js";
import { focusContext } from "./focusContext.js";
import { focusedElementContext } from "./focusedElementContext.js";
import { targetTemporalContext } from "./ContextMixin.js";
import { TargetController } from "../elements/TargetController.js";
import { createDirectTemporalSubscription, determineTargetType } from "./Controllable.js";
import { attachContextRoot } from "../attachContextRoot.js";
import { createContext, provide } from "@lit/context";
import { LitElement, css } from "lit";
import { customElement, property, state } from "lit/decorators.js";

//#region src/gui/EFControls.ts
attachContextRoot();
var ContextRequestEvent = class extends Event {
	constructor(context, contextTarget, callback, subscribe) {
		super("context-request", {
			bubbles: true,
			composed: true
		});
		this.context = context;
		this.contextTarget = contextTarget;
		this.callback = callback;
		this.subscribe = subscribe ?? false;
	}
};
const proxiedContexts = [
	[(proxy, value) => proxy.playing = value, playingContext],
	[(proxy, value) => proxy.loop = value, loopContext],
	[(proxy, value) => proxy.currentTimeMs = value, currentTimeContext],
	[(proxy, value) => proxy.durationMs = value, durationContext],
	[(proxy, value) => proxy.targetTemporal = value, targetTemporalContext],
	[(proxy, value) => proxy.focusedElement = value, focusedElementContext],
	[(proxy, value) => proxy.focusContext.focusedElement = value, focusContext]
];
const testContext = createContext("test");
let EFControls = class EFControls$1 extends LitElement {
	constructor(..._args) {
		super(..._args);
		this.target = "";
		this.targetElement = null;
		this.playing = false;
		this.loop = false;
		this.currentTimeMs = 0;
		this.durationMs = 0;
		this.targetTemporal = null;
		this.focusContext = this;
	}
	static {
		this.styles = css`
    :host {
      display: block;
    }
  `;
	}
	createRenderRoot() {
		return this;
	}
	#targetController = new TargetController(this);
	#contextUnsubscribeMap = /* @__PURE__ */ new Map();
	#directTemporalSubscription = null;
	#unsubscribe() {
		this.#subscribeAbortController?.abort();
		this.#subscribeAbortController = null;
		for (const unsubscribe of this.#contextUnsubscribeMap.values()) unsubscribe();
		this.#contextUnsubscribeMap.clear();
		if (this.#directTemporalSubscription) {
			this.#directTemporalSubscription.unsubscribe();
			this.#directTemporalSubscription = null;
		}
	}
	#subscribeAbortController = null;
	#subscribe() {
		if (!this.targetElement) return;
		this.#subscribeAbortController?.abort();
		this.#subscribeAbortController = new AbortController();
		switch (determineTargetType(this.targetElement)) {
			case "context-provider":
				this.#subscribeToContextProvider();
				break;
			case "direct-temporal":
				this.#subscribeToDirectTemporal();
				break;
			case "none":
				this.#waitForTemporalToInitialize();
				break;
		}
	}
	/**
	* Wait for a temporal element to initialize its playbackController.
	* This handles the case where we target a temporal element before it has
	* completed initialization and created its playbackController.
	*
	* Note: playbackController is created in EFTemporal's connectedCallback via
	* `this.updateComplete.then(() => this.didBecomeRoot())`, so we need to wait
	* past updateComplete for the .then() callback to run.
	*/
	async #waitForTemporalToInitialize() {
		if (!this.targetElement || !isEFTemporal(this.targetElement)) return;
		const temporal = this.targetElement;
		const signal = this.#subscribeAbortController?.signal;
		await temporal.updateComplete;
		if (signal?.aborted) return;
		if (!temporal.playbackController) {
			await new Promise((resolve) => requestAnimationFrame(resolve));
			if (signal?.aborted) return;
			await temporal.updateComplete;
			if (signal?.aborted) return;
		}
		if (temporal.playbackController) this.#subscribeToDirectTemporal();
	}
	/**
	* Subscribe to a context-providing target (like EFPreview).
	* Uses Lit Context dispatch mechanism.
	*/
	#subscribeToContextProvider() {
		if (!this.targetElement) return;
		for (const [callback, context] of proxiedContexts) {
			const event = new ContextRequestEvent(context, this, (value, unsubscribe) => {
				callback(this, value);
				this.#contextUnsubscribeMap.set(context, unsubscribe);
			}, true);
			this.targetElement.dispatchEvent(event);
		}
	}
	/**
	* Subscribe to a direct temporal element's playback controller.
	* Used when targeting ef-timegroup, ef-video, ef-audio directly without ef-preview wrapper.
	*/
	async #subscribeToDirectTemporal() {
		if (!this.targetElement || !isEFTemporal(this.targetElement)) return;
		const temporal = this.targetElement;
		const signal = this.#subscribeAbortController?.signal;
		await temporal.updateComplete;
		if (signal?.aborted) return;
		if (!temporal.playbackController) {
			await new Promise((resolve) => requestAnimationFrame(resolve));
			if (signal?.aborted) return;
			await temporal.updateComplete;
			if (signal?.aborted) return;
		}
		if (!temporal.playbackController) return;
		this.#directTemporalSubscription = createDirectTemporalSubscription(temporal, {
			onPlayingChange: (value) => {
				this.playing = value;
			},
			onLoopChange: (value) => {
				this.loop = value;
			},
			onCurrentTimeMsChange: (value) => {
				this.currentTimeMs = value;
			},
			onDurationMsChange: (value) => {
				this.durationMs = value;
			},
			onTargetTemporalChange: (value) => {
				this.targetTemporal = value;
			},
			onFocusedElementChange: (value) => {
				this.focusedElement = value;
			}
		});
	}
	#resubscribe() {
		this.#unsubscribe();
		this.#subscribe();
	}
	updated(changedProperties) {
		super.updated(changedProperties);
		if (changedProperties.has("targetElement")) this.#resubscribe();
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#unsubscribe();
	}
};
__decorate([property({ type: String })], EFControls.prototype, "target", void 0);
__decorate([provide({ context: efContext }), state()], EFControls.prototype, "targetElement", void 0);
__decorate([provide({ context: playingContext }), state()], EFControls.prototype, "playing", void 0);
__decorate([provide({ context: loopContext }), state()], EFControls.prototype, "loop", void 0);
__decorate([provide({ context: currentTimeContext }), state()], EFControls.prototype, "currentTimeMs", void 0);
__decorate([provide({ context: durationContext }), state()], EFControls.prototype, "durationMs", void 0);
__decorate([provide({ context: targetTemporalContext }), state()], EFControls.prototype, "targetTemporal", void 0);
__decorate([provide({ context: focusedElementContext }), state()], EFControls.prototype, "focusedElement", void 0);
__decorate([provide({ context: focusContext })], EFControls.prototype, "focusContext", void 0);
EFControls = __decorate([customElement("ef-controls")], EFControls);

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