import { efContext } from "./efContext.js";
import { currentTimeContext } from "./currentTimeContext.js";
import { durationContext } from "./durationContext.js";
import { playingContext } from "./playingContext.js";
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { quantizeToFrameTimeMs } from "./EFTimelineRuler.js";
import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
import { consume } from "@lit/context";
import { LitElement, css, html } from "lit";
import { customElement, eventOptions, property, state } from "lit/decorators.js";
import { createRef, ref } from "lit/directives/ref.js";

//#region src/gui/EFScrubber.ts
const BASE_PIXELS_PER_SECOND = 100;
function timeToPixels(timeMs, durationMs, _containerWidth, zoomScale) {
	if (durationMs <= 0) return 0;
	const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;
	return timeMs / 1e3 * pixelsPerSecond;
}
function pixelsToTime(pixels, durationMs, _containerWidth, zoomScale) {
	if (durationMs <= 0) return 0;
	return pixels / (BASE_PIXELS_PER_SECOND * zoomScale) * 1e3;
}
let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efContext) {
	constructor(..._args) {
		super(..._args);
		this.playing = false;
		this.contextCurrentTimeMs = NaN;
		this.contextDurationMs = 0;
		this.orientation = "horizontal";
		this.currentTimeMs = NaN;
		this.durationMs = 0;
		this.zoomScale = 1;
		this.containerWidth = 0;
		this.scrubProgress = 0;
		this.isMoving = false;
		this.scrubberRef = createRef();
		this.capturedPointerId = null;
		this.boundHandlePointerMove = (e) => {
			if (this.isMoving && e.pointerId === this.capturedPointerId) {
				e.preventDefault();
				e.stopPropagation();
				this.updateProgress(e);
			}
		};
		this.boundHandlePointerUp = (e) => {
			const scrubberEl = this.scrubberRef.value || this._scrubberElement;
			if (e.pointerId === this.capturedPointerId && scrubberEl) {
				e.preventDefault();
				e.stopPropagation();
				try {
					scrubberEl.releasePointerCapture(e.pointerId);
				} catch (_err) {}
				this.capturedPointerId = null;
				this.isMoving = false;
				if (this.isScrubbingRef) this.isScrubbingRef.current = false;
			}
		};
		this.boundHandlePointerCancel = (e) => {
			const scrubberEl = this.scrubberRef.value || this._scrubberElement;
			if (e.pointerId === this.capturedPointerId && scrubberEl) {
				try {
					scrubberEl.releasePointerCapture(e.pointerId);
				} catch (_err) {}
				this.capturedPointerId = null;
				this.isMoving = false;
				if (this.isScrubbingRef) this.isScrubbingRef.current = false;
			}
		};
		this.boundHandleContextMenu = (e) => {
			if (this.isMoving) {
				e.preventDefault();
				e.stopPropagation();
			}
		};
	}
	static {
		this.styles = [css`
    :host {
      --ef-scrubber-height: 4px;
      --ef-scrubber-background: var(--ef-color-border, rgba(255, 255, 255, 0.2));
      --ef-scrubber-progress-color: var(--ef-color-primary, #fff);
      --ef-scrubber-handle-size: 12px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    :host([orientation="vertical"]) {
      width: 100%;
      height: 100%;
      position: absolute;
      inset: 0;
      pointer-events: auto;
    }

    .scrubber {
      width: 100%;
      height: var(--ef-scrubber-height);
      background: var(--ef-scrubber-background);
      position: relative;
      cursor: pointer;
      border-radius: 2px;
      touch-action: none;
      user-select: none;
    }

    :host([orientation="vertical"]) .scrubber {
      width: 100%;
      height: 100%;
      background: transparent;
      cursor: ew-resize;
    }

    .progress {
      position: absolute;
      height: 100%;
      background: var(--ef-scrubber-progress-color);
      border-radius: 2px;
    }

    :host([orientation="vertical"]) .progress {
      display: none;
    }

    .handle {
      position: absolute;
      width: var(--ef-scrubber-handle-size);
      height: var(--ef-scrubber-handle-size);
      background: var(--ef-scrubber-progress-color);
      border-radius: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      cursor: grab;
    }

    :host([orientation="vertical"]) .handle {
      display: none;
    }

    .playhead {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 2px;
      background: var(--ef-scrubber-progress-color);
      pointer-events: auto;
      cursor: ew-resize;
      z-index: 30;
    }

    ::part(playhead) {
      z-index: 30;
    }

    .playhead-handle {
      position: absolute;
      top: 0;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 12px;
      height: 12px;
      background: var(--ef-scrubber-progress-color);
      border-radius: 50%;
    }

    .raw-preview {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 2px;
      background: color-mix(in srgb, var(--ef-color-primary) 20%, transparent);
      pointer-events: none;
      z-index: 20;
    }

    /* Add CSS Shadow Parts */
    ::part(scrubber) { }
    ::part(progress) { }
    ::part(handle) { }
    `];
	}
	get context() {
		return this.effectiveContext;
	}
	get effectiveCurrentTimeMs() {
		if (!Number.isNaN(this.currentTimeMs)) return this.currentTimeMs;
		if (!Number.isNaN(this.contextCurrentTimeMs)) return this.contextCurrentTimeMs;
		return 0;
	}
	get effectiveDurationMs() {
		return this.durationMs || this.contextDurationMs || 0;
	}
	get isTimelineMode() {
		return this.orientation === "vertical" && this.zoomScale > 0;
	}
	updateProgress(e) {
		const scrubberEl = this.scrubberRef.value || this._scrubberElement;
		if (!scrubberEl) return;
		const duration = this.effectiveDurationMs;
		if (duration <= 0) return;
		if (this.isTimelineMode) {
			const scrollContainer = this.scrollContainerRef?.current || scrubberEl.parentElement;
			if (!scrollContainer) return;
			const scrollContainerRect = scrollContainer.getBoundingClientRect();
			const scrollLeft = scrollContainer.scrollLeft || 0;
			let pixelOffset = 0;
			if (this.trackContentRef?.current) pixelOffset = this.trackContentRef.current.getBoundingClientRect().left - scrollContainerRect.left + scrollContainer.scrollLeft;
			const pixelPosition = scrollLeft + (e.clientX - scrollContainerRect.left - pixelOffset);
			const effectiveWidth = this.containerWidth > 0 ? this.containerWidth : scrollContainerRect.width;
			if (effectiveWidth <= 0) return;
			let rawTime = pixelsToTime(pixelPosition, duration, effectiveWidth, this.zoomScale);
			rawTime = Math.max(0, Math.min(rawTime, duration));
			let quantizedTime = this.fps && this.fps > 0 ? quantizeToFrameTimeMs(rawTime, this.fps) : rawTime;
			quantizedTime = Math.max(0, Math.min(quantizedTime, duration));
			this.scrubProgress = quantizedTime / duration;
			if (this.onSeek) this.onSeek(quantizedTime);
			else {
				this.dispatchEvent(new CustomEvent("seek", {
					detail: quantizedTime,
					bubbles: true,
					composed: true
				}));
				if (this.context) this.context.currentTimeMs = quantizedTime;
			}
		} else {
			const rect = scrubberEl.getBoundingClientRect();
			const x = e.clientX - rect.left;
			const progress = Math.max(0, Math.min(1, x / rect.width));
			this.scrubProgress = progress;
			const timeMs = progress * duration;
			if (this.onSeek) this.onSeek(timeMs);
			else {
				this.dispatchEvent(new CustomEvent("seek", {
					detail: timeMs,
					bubbles: true,
					composed: true
				}));
				if (this.context) this.context.currentTimeMs = timeMs;
			}
		}
	}
	handlePointerDown(e) {
		const scrubberEl = this.scrubberRef.value || this._scrubberElement;
		if (!scrubberEl) return;
		this.isMoving = true;
		if (this.isScrubbingRef) this.isScrubbingRef.current = true;
		e.preventDefault();
		e.stopPropagation();
		this.capturedPointerId = e.pointerId;
		try {
			scrubberEl.setPointerCapture(e.pointerId);
		} catch (err) {
			console.warn("Failed to set pointer capture:", err);
		}
		this.updateProgress(e);
	}
	render() {
		const duration = this.effectiveDurationMs;
		const currentTime = this.effectiveCurrentTimeMs;
		if (duration <= 0) return html``;
		if (this.isTimelineMode) {
			const scrubberEl = this.scrubberRef.value || this._scrubberElement;
			const effectiveWidth = this.containerWidth > 0 ? this.containerWidth : scrubberEl?.parentElement?.getBoundingClientRect().width || 0;
			const positionPixels = effectiveWidth > 0 ? timeToPixels(currentTime, duration, effectiveWidth, this.zoomScale) : 0;
			const rawScrubPositionPixels = this.rawScrubTimeMs !== null && this.rawScrubTimeMs !== void 0 && effectiveWidth > 0 ? timeToPixels(this.rawScrubTimeMs, duration, effectiveWidth, this.zoomScale) : null;
			return html`
        ${rawScrubPositionPixels !== null && rawScrubPositionPixels !== positionPixels ? html`<div
              class="raw-preview"
              style="left: ${rawScrubPositionPixels}px"
            ></div>` : html``}
        <div
          ${ref(this.scrubberRef)}
          part="scrubber"
          class="scrubber"
          @pointerdown=${this.handlePointerDown}
          @contextmenu=${this.boundHandleContextMenu}
        >
          <div
            part="playhead"
            class="playhead"
            style="left: ${positionPixels}px"
            @pointerdown=${this.handlePointerDown}
          >
            <div class="playhead-handle"></div>
          </div>
        </div>
      `;
		} else {
			const currentProgress = duration > 0 ? currentTime / duration : 0;
			const displayProgress = this.isMoving ? this.scrubProgress : currentProgress;
			return html`
        <div
          ${ref(this.scrubberRef)}
          part="scrubber"
          class="scrubber"
          @pointerdown=${this.handlePointerDown}
          @contextmenu=${this.boundHandleContextMenu}
        >
          <div part="progress" class="progress" style="width: ${displayProgress * 100}%"></div>
          <div part="handle" class="handle" style="left: ${displayProgress * 100}%"></div>
        </div>
      `;
		}
	}
	connectedCallback() {
		super.connectedCallback();
		window.addEventListener("pointerup", this.boundHandlePointerUp, { passive: false });
		window.addEventListener("pointermove", this.boundHandlePointerMove, { passive: false });
		window.addEventListener("pointercancel", this.boundHandlePointerCancel, { passive: false });
		this.addEventListener("contextmenu", this.boundHandleContextMenu, { passive: false });
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		window.removeEventListener("pointerup", this.boundHandlePointerUp);
		window.removeEventListener("pointermove", this.boundHandlePointerMove);
		window.removeEventListener("pointercancel", this.boundHandlePointerCancel);
		this.removeEventListener("contextmenu", this.boundHandleContextMenu);
	}
};
__decorate([consume({
	context: playingContext,
	subscribe: true
})], EFScrubber.prototype, "playing", void 0);
__decorate([consume({
	context: currentTimeContext,
	subscribe: true
})], EFScrubber.prototype, "contextCurrentTimeMs", void 0);
__decorate([consume({
	context: durationContext,
	subscribe: true
})], EFScrubber.prototype, "contextDurationMs", void 0);
__decorate([property({
	type: String,
	attribute: "orientation"
})], EFScrubber.prototype, "orientation", void 0);
__decorate([property({
	type: Number,
	attribute: "current-time-ms"
})], EFScrubber.prototype, "currentTimeMs", void 0);
__decorate([property({
	type: Number,
	attribute: "duration-ms"
})], EFScrubber.prototype, "durationMs", void 0);
__decorate([property({
	type: Number,
	attribute: "zoom-scale"
})], EFScrubber.prototype, "zoomScale", void 0);
__decorate([property({
	type: Number,
	attribute: "container-width"
})], EFScrubber.prototype, "containerWidth", void 0);
__decorate([property({
	type: Number,
	attribute: "fps"
})], EFScrubber.prototype, "fps", void 0);
__decorate([property({
	type: Number,
	attribute: "raw-scrub-time-ms"
})], EFScrubber.prototype, "rawScrubTimeMs", void 0);
__decorate([property({ attribute: false })], EFScrubber.prototype, "scrollContainerRef", void 0);
__decorate([property({ attribute: false })], EFScrubber.prototype, "trackContentRef", void 0);
__decorate([property({ attribute: false })], EFScrubber.prototype, "onSeek", void 0);
__decorate([property({ attribute: false })], EFScrubber.prototype, "isScrubbingRef", void 0);
__decorate([state()], EFScrubber.prototype, "scrubProgress", void 0);
__decorate([state()], EFScrubber.prototype, "isMoving", void 0);
__decorate([eventOptions({
	passive: false,
	capture: false
})], EFScrubber.prototype, "handlePointerDown", null);
EFScrubber = __decorate([customElement("ef-scrubber")], EFScrubber);

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