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 { TargetController } from "../elements/TargetController.js";
import { createDirectTemporalSubscription, determineTargetType, isControllable } from "./Controllable.js";
import { consume } from "@lit/context";
import { property, state } from "lit/decorators.js";

//#region src/gui/TargetOrContextMixin.ts
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;
	}
};
function TargetOrContextMixin(superClass, contextToProxy) {
	class TargetOrContextClass extends superClass {
		constructor(..._args) {
			super(..._args);
			this.target = "";
			this.targetElement = null;
			this.contextFromParent = null;
		}
		#targetController;
		#contextUnsubscribe;
		#contextRequestHandler;
		#additionalContextUnsubscribes = /* @__PURE__ */ new Map();
		#directTemporalSubscription;
		get effectiveContext() {
			return this.targetElement ?? this.contextFromParent;
		}
		connectedCallback() {
			super.connectedCallback();
			if (this.target) this.#targetController = new TargetController(this);
			this.#contextRequestHandler = (event) => {
				if (this.targetElement && event.type === "context-request") {
					event.stopPropagation();
					this.targetElement.dispatchEvent(new event.constructor(event.type, event));
				}
			};
			this.addEventListener("context-request", this.#contextRequestHandler, true);
		}
		#unsubscribeAll() {
			this.#contextUnsubscribe?.();
			this.#contextUnsubscribe = void 0;
			for (const unsubscribe of this.#additionalContextUnsubscribes.values()) unsubscribe();
			this.#additionalContextUnsubscribes.clear();
			this.#directTemporalSubscription?.unsubscribe();
			this.#directTemporalSubscription = void 0;
		}
		#tryDirectTemporalSubscription() {
			if (!this.targetElement) return false;
			if (determineTargetType(this.targetElement) !== "direct-temporal") return false;
			this.#directTemporalSubscription = createDirectTemporalSubscription(this.targetElement, {
				onPlayingChange: (value) => {
					this.playing = value;
				},
				onLoopChange: (value) => {
					if ("loop" in this) this.loop = value;
				},
				onCurrentTimeMsChange: (value) => {
					if ("currentTimeMs" in this) this.currentTimeMs = value;
				},
				onDurationMsChange: (value) => {
					if ("durationMs" in this) this.durationMs = value;
				},
				onTargetTemporalChange: () => {}
			});
			return true;
		}
		#subscribeToTargetContext() {
			if (!this.targetElement) return;
			this.#unsubscribeAll();
			if (this.#tryDirectTemporalSubscription()) return;
			if (isEFTemporal(this.targetElement)) {
				const target = this.targetElement;
				target.updateComplete.then(() => {
					if (this.targetElement !== target) return;
					if (!this.#tryDirectTemporalSubscription()) target.updateComplete.then(() => {
						if (this.targetElement !== target) return;
						this.#tryDirectTemporalSubscription();
					});
				});
				return;
			}
			const event = new ContextRequestEvent(contextToProxy, this, (value, unsubscribe) => {
				this.contextFromParent = value;
				this.#contextUnsubscribe = unsubscribe;
			}, true);
			this.targetElement.dispatchEvent(event);
			const additionalContexts = [
				[playingContext, "playing"],
				[loopContext, "loop"],
				[currentTimeContext, "currentTimeMs"],
				[durationContext, "durationMs"]
			];
			for (const [context, propertyName] of additionalContexts) {
				const contextEvent = new ContextRequestEvent(context, this, (value, unsubscribe) => {
					if (propertyName in this) this[propertyName] = value;
					this.#additionalContextUnsubscribes.set(context, unsubscribe);
				}, true);
				this.targetElement.dispatchEvent(contextEvent);
			}
		}
		updated(changedProperties) {
			super.updated?.(changedProperties);
			if (changedProperties.has("targetElement") && this.targetElement) {
				if (isEFTemporal(this.targetElement) && !isControllable(this.targetElement)) console.warn("Control element is targeting a non-root temporal element without playbackController. Controls can only target root temporal elements (not nested within a timegroup). Target element:", this.targetElement);
				this.#subscribeToTargetContext();
			}
			if (changedProperties.has("target")) {
				if (this.target && !this.#targetController) this.#targetController = new TargetController(this);
			}
		}
		disconnectedCallback() {
			super.disconnectedCallback();
			this.#unsubscribeAll();
			if (this.#contextRequestHandler) this.removeEventListener("context-request", this.#contextRequestHandler, true);
		}
	}
	__decorate([property({ type: String })], TargetOrContextClass.prototype, "target", void 0);
	__decorate([state()], TargetOrContextClass.prototype, "targetElement", void 0);
	__decorate([consume({
		context: contextToProxy,
		subscribe: true
	})], TargetOrContextClass.prototype, "contextFromParent", void 0);
	return TargetOrContextClass;
}

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