// @ts-check

import { prop } from "../../utils.js";
import { $el } from "../../ui.js";
import { applyClasses } from "../utils.js";

export class ComfyPopup extends EventTarget {
	element = $el("div.comfyui-popup");

	/**
	 * @param {{
	 *     target: HTMLElement,
	 *      container?: HTMLElement,
	 *      classList?: import("../utils.js").ClassList,
	 * 		ignoreTarget?: boolean,
	 * 		closeOnEscape?: boolean,
	 * 		position?: "absolute" | "relative",
	 * 		horizontal?: "left" | "right"
	 * }} param0
	 * @param  {...HTMLElement} children
	 */
	constructor(
		{
			target,
			container = document.body,
			classList = "",
			ignoreTarget = true,
			closeOnEscape = true,
			position = "absolute",
			horizontal = "left",
		},
		...children
	) {
		super();
		this.target = target;
		this.ignoreTarget = ignoreTarget;
		this.container = container;
		this.position = position;
		this.closeOnEscape = closeOnEscape;
		this.horizontal = horizontal;

		container.append(this.element);

		this.children = prop(this, "children", children, () => {
			this.element.replaceChildren(...this.children);
			this.update();
		});
		this.classList = prop(this, "classList", classList, () => applyClasses(this.element, this.classList, "comfyui-popup", horizontal));
		this.open = prop(this, "open", false, (v, o) => {
			if (v === o) return;
			if (v) {
				this.#show();
			} else {
				this.#hide();
			}
		});
	}

	toggle() {
		this.open = !this.open;
	}

	#hide() {
		this.element.classList.remove("open");
		window.removeEventListener("resize", this.update);
		window.removeEventListener("click", this.#clickHandler, { capture: true });
		window.removeEventListener("keydown", this.#escHandler, { capture: true });

		this.dispatchEvent(new CustomEvent("close"));
		this.dispatchEvent(new CustomEvent("change"));
	}

	#show() {
		this.element.classList.add("open");
		this.update();

		window.addEventListener("resize", this.update);
		window.addEventListener("click", this.#clickHandler, { capture: true });
		if (this.closeOnEscape) {
			window.addEventListener("keydown", this.#escHandler, { capture: true });
		}

		this.dispatchEvent(new CustomEvent("open"));
		this.dispatchEvent(new CustomEvent("change"));
	}

	#escHandler = (e) => {
		if (e.key === "Escape") {
			this.open = false;
			e.preventDefault();
			e.stopImmediatePropagation();
		}
	};

	#clickHandler = (e) => {
		/** @type {any} */
		const target = e.target;
		if (!this.element.contains(target) && this.ignoreTarget && !this.target.contains(target)) {
			this.open = false;
		}
	};

	update = () => {
		const rect = this.target.getBoundingClientRect();
		this.element.style.setProperty("--bottom", "unset");
		if (this.position === "absolute") {
			if (this.horizontal === "left") {
				this.element.style.setProperty("--left", rect.left + "px");
			} else {
				this.element.style.setProperty("--left", rect.right - this.element.clientWidth + "px");
			}
			this.element.style.setProperty("--top", rect.bottom + "px");
			this.element.style.setProperty("--limit", rect.bottom + "px");
		} else {
			this.element.style.setProperty("--left", 0 + "px");
			this.element.style.setProperty("--top", rect.height + "px");
			this.element.style.setProperty("--limit", rect.height + "px");
		}

		const thisRect = this.element.getBoundingClientRect();
		if (thisRect.height < 30) {
			// Move up instead
			this.element.style.setProperty("--top", "unset");
			this.element.style.setProperty("--bottom", rect.height + 5 + "px");
			this.element.style.setProperty("--limit", rect.height + 5 + "px");
		}
	};
}
