import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
import { panZoomTransformContext } from "../gui/panZoomTransformContext.js";
import { provide } from "@lit/context";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";

//#region src/elements/EFPanZoom.ts
let EFPanZoom = class EFPanZoom$1 extends LitElement {
	constructor(..._args) {
		super(..._args);
		this.x = 0;
		this.y = 0;
		this.scale = 1;
		this.autoFit = false;
		this.panZoomTransform = {
			x: 0,
			y: 0,
			scale: 1
		};
		this._isDragging = false;
		this._dragStartPointerPos = null;
		this._dragStartTransform = null;
		this._capturedPointerId = null;
		this._onDocumentWheelCapture = (e) => {
			let panZoom = null;
			if (e.target instanceof Element) {
				panZoom = e.target.closest("ef-pan-zoom");
				if (!panZoom && e.target.closest("ef-canvas-selection-overlay")) {
					const rect = this.getBoundingClientRect();
					if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) panZoom = this;
				}
			}
			if (panZoom === this) e.preventDefault();
		};
		this._onPointerDown = (e) => {
			if (e.button !== 0) return;
			this._isDragging = true;
			this._capturedPointerId = e.pointerId;
			this._dragStartPointerPos = {
				x: e.clientX,
				y: e.clientY
			};
			this._dragStartTransform = {
				x: this.x,
				y: this.y,
				scale: this.scale
			};
			try {
				this.setPointerCapture(e.pointerId);
			} catch (err) {}
		};
		this._onPointerMove = (e) => {
			if (!this._isDragging || !this._dragStartPointerPos || !this._dragStartTransform) return;
			const deltaX = e.clientX - this._dragStartPointerPos.x;
			const deltaY = e.clientY - this._dragStartPointerPos.y;
			this._updateTransform({
				x: this._dragStartTransform.x - deltaX,
				y: this._dragStartTransform.y - deltaY
			});
		};
		this._onPointerUp = (e) => {
			if (!this._isDragging) return;
			if (this._capturedPointerId !== null) try {
				this.releasePointerCapture(e.pointerId);
			} catch (err) {}
			this._isDragging = false;
			this._capturedPointerId = null;
			this._dragStartPointerPos = null;
			this._dragStartTransform = null;
		};
		this._onWheel = (e) => {
			e.preventDefault();
			e.stopPropagation();
			if (e.metaKey || e.ctrlKey) {
				const containerRect = this.getBoundingClientRect();
				const pointerX = e.clientX - containerRect.left;
				const pointerY = e.clientY - containerRect.top;
				const currentX = this.x;
				const currentY = this.y;
				const currentScale = this.scale;
				const canvasX = (pointerX - currentX) / currentScale;
				const canvasY = (pointerY - currentY) / currentScale;
				const delta = e.deltaY > 0 ? .95 : 1.05;
				const newScale = Math.max(.1, Math.min(5, currentScale * delta));
				const newX = pointerX - canvasX * newScale;
				const newY = pointerY - canvasY * newScale;
				this._updateTransform({
					x: newX,
					y: newY,
					scale: newScale
				});
			} else {
				const deltaX = -e.deltaX;
				const deltaY = -e.deltaY;
				this._updateTransform({
					x: this.x + deltaX,
					y: this.y + deltaY
				});
			}
		};
	}
	static {
		this.styles = [css`
      :host {
        display: block;
        overflow: hidden;
        position: relative;
        touch-action: none;
      }
      .content-wrapper {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        transform-origin: 0 0;
      }
    `];
	}
	connectedCallback() {
		super.connectedCallback();
		document.addEventListener("wheel", this._onDocumentWheelCapture, {
			passive: false,
			capture: true
		});
		this.addEventListener("wheel", this._onWheel, { passive: false });
		this.addEventListener("pointerdown", this._onPointerDown);
		this.addEventListener("pointermove", this._onPointerMove);
		this.addEventListener("pointerup", this._onPointerUp);
		this.addEventListener("pointercancel", this._onPointerUp);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		document.removeEventListener("wheel", this._onDocumentWheelCapture, { capture: true });
		this.removeEventListener("wheel", this._onWheel);
		this.removeEventListener("pointerdown", this._onPointerDown);
		this.removeEventListener("pointermove", this._onPointerMove);
		this.removeEventListener("pointerup", this._onPointerUp);
		this.removeEventListener("pointercancel", this._onPointerUp);
		if (this._isDragging && this._capturedPointerId !== null) try {
			this.releasePointerCapture(this._capturedPointerId);
		} catch (err) {}
	}
	_updateTransform(updates) {
		const newTransform = {
			x: updates.x !== void 0 ? updates.x : this.x,
			y: updates.y !== void 0 ? updates.y : this.y,
			scale: updates.scale !== void 0 ? Math.max(.1, Math.min(5, updates.scale)) : this.scale
		};
		if (newTransform.x !== this.x || newTransform.y !== this.y || newTransform.scale !== this.scale) {
			this.x = newTransform.x;
			this.y = newTransform.y;
			this.scale = newTransform.scale;
			this.panZoomTransform = { ...newTransform };
			this.dispatchEvent(new CustomEvent("transform-changed", {
				detail: { ...newTransform },
				bubbles: true,
				composed: true
			}));
		}
	}
	firstUpdated(changedProperties) {
		super.firstUpdated(changedProperties);
		this.panZoomTransform = {
			x: this.x,
			y: this.y,
			scale: this.scale
		};
		if (this.autoFit) requestAnimationFrame(() => {
			this.fitToContent();
		});
	}
	/**
	* Convert screen coordinates (e.g., mouse event clientX/clientY) to canvas coordinates.
	* This handles all pan/zoom transformations automatically.
	*
	* @param screenX - X coordinate in screen space (e.g., event.clientX)
	* @param screenY - Y coordinate in screen space (e.g., event.clientY)
	* @returns Object with x, y in canvas coordinate space
	*
	* @example
	* handleClick(e: MouseEvent) {
	*   const canvasPos = panZoom.screenToCanvas(e.clientX, e.clientY);
	*   console.log(`Clicked at canvas position: ${canvasPos.x}, ${canvasPos.y}`);
	* }
	*/
	screenToCanvas(screenX, screenY) {
		const rect = this.getBoundingClientRect();
		return {
			x: (screenX - rect.left - this.x) / this.scale,
			y: (screenY - rect.top - this.y) / this.scale
		};
	}
	/**
	* Convert canvas coordinates to screen coordinates.
	* Useful for positioning overlays or tooltips relative to canvas elements.
	*
	* @param canvasX - X coordinate in canvas space
	* @param canvasY - Y coordinate in canvas space
	* @returns Object with x, y in screen coordinate space
	*
	* @example
	* const screenPos = panZoom.canvasToScreen(element.x, element.y);
	* tooltip.style.left = `${screenPos.x}px`;
	* tooltip.style.top = `${screenPos.y}px`;
	*/
	canvasToScreen(canvasX, canvasY) {
		const rect = this.getBoundingClientRect();
		return {
			x: rect.left + canvasX * this.scale + this.x,
			y: rect.top + canvasY * this.scale + this.y
		};
	}
	/**
	* Reset the pan-zoom transform to its default values (x: 0, y: 0, scale: 1).
	* This method can be called programmatically to reset the view.
	*
	* @example
	* const panZoomRef = useRef(null);
	* <button onClick={() => panZoomRef.current.reset()}>Reset View</button>
	*/
	reset() {
		this._updateTransform({
			x: 0,
			y: 0,
			scale: 1
		});
	}
	/**
	* Fit content to the container, centering it and scaling to fit.
	* Uses a padding factor to leave some margin around the content.
	*
	* @param padding - Padding factor (0-1), e.g., 0.1 = 10% padding on each side. Default: 0.05
	*/
	fitToContent(padding = .05) {
		const containerRect = this.getBoundingClientRect();
		if (containerRect.width === 0 || containerRect.height === 0) return;
		const slottedContent = (this.shadowRoot?.querySelector(".content-wrapper"))?.querySelector("slot")?.assignedElements()[0];
		if (!slottedContent) return;
		const contentRect = slottedContent.getBoundingClientRect();
		const contentWidth = contentRect.width / this.scale;
		const contentHeight = contentRect.height / this.scale;
		if (contentWidth === 0 || contentHeight === 0) return;
		const availableWidth = containerRect.width * (1 - 2 * padding);
		const availableHeight = containerRect.height * (1 - 2 * padding);
		const scaleX = availableWidth / contentWidth;
		const scaleY = availableHeight / contentHeight;
		const newScale = Math.min(scaleX, scaleY);
		const scaledWidth = contentWidth * newScale;
		const scaledHeight = contentHeight * newScale;
		const newX = (containerRect.width - scaledWidth) / 2;
		const newY = (containerRect.height - scaledHeight) / 2;
		this._updateTransform({
			x: newX,
			y: newY,
			scale: newScale
		});
	}
	render() {
		return html`
      <div
        class="content-wrapper"
        style="transform: translate(${this.x}px, ${this.y}px) scale(${this.scale});"
      >
        <slot></slot>
      </div>
    `;
	}
};
__decorate([property({
	type: Number,
	reflect: true
})], EFPanZoom.prototype, "x", void 0);
__decorate([property({
	type: Number,
	reflect: true
})], EFPanZoom.prototype, "y", void 0);
__decorate([property({
	type: Number,
	reflect: true
})], EFPanZoom.prototype, "scale", void 0);
__decorate([property({
	type: Boolean,
	attribute: "auto-fit"
})], EFPanZoom.prototype, "autoFit", void 0);
__decorate([provide({ context: panZoomTransformContext })], EFPanZoom.prototype, "panZoomTransform", void 0);
EFPanZoom = __decorate([customElement("ef-pan-zoom")], EFPanZoom);

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