export class AutocompleteManager {
    constructor(inputSelectorOrElement, options = {}) {
        this.container = null;
        this.activeIndex = -1;
        this.isOpen = false;
        this.debounceTimer = null;
        this.currentSuggestions = [];
        this.handleInput = async () => {
            if (this.debounceTimer) {
                clearTimeout(this.debounceTimer);
            }
            this.debounceTimer = window.setTimeout(async () => {
                const query = this.input?.value.trim() || "";
                if (query.length < this.options.minChars) {
                    this.close();
                    return;
                }
                await this.updateSuggestions(query);
            }, this.options.debounce);
        };
        this.handleKeyDown = (e) => {
            if (!this.isOpen) {
                if (e.key === "ArrowDown" && this.currentSuggestions.length > 0) {
                    e.preventDefault();
                    this.open();
                }
                return;
            }
            switch (e.key) {
                case "ArrowDown":
                    e.preventDefault();
                    this.moveActive(1);
                    break;
                case "ArrowUp":
                    e.preventDefault();
                    this.moveActive(-1);
                    break;
                case "Enter":
                    e.preventDefault();
                    if (this.activeIndex >= 0) {
                        this.selectSuggestion(this.activeIndex);
                    }
                    break;
                case "Escape":
                    this.close();
                    break;
                case "Tab":
                    this.close();
                    break;
            }
        };
        this.handleBlur = () => {
            setTimeout(() => this.close(), 150);
        };
        this.input =
            typeof inputSelectorOrElement === "string"
                ? document.querySelector(inputSelectorOrElement)
                : inputSelectorOrElement;
        this.options = {
            suggestions: options.suggestions ?? [],
            fetchSuggestions: options.fetchSuggestions ?? (async () => []),
            minChars: options.minChars ?? 1,
            maxResults: options.maxResults ?? 10,
            debounce: options.debounce ?? 200,
            highlight: options.highlight !== false,
            containerClass: options.containerClass ?? "autocomplete",
            itemClass: options.itemClass ?? "autocomplete__item",
            highlightClass: options.highlightClass ?? "autocomplete__highlight",
            activeClass: options.activeClass ?? "autocomplete__item--active",
            onSelect: options.onSelect ?? (() => { }),
        };
        if (!this.input) {
            console.warn("[Stylescape] AutocompleteManager input not found");
            return;
        }
        this.init();
    }
    setSuggestions(suggestions) {
        this.options.suggestions = suggestions;
    }
    open() {
        if (!this.container || this.currentSuggestions.length === 0)
            return;
        this.container.style.display = "block";
        this.isOpen = true;
        this.input?.setAttribute("aria-expanded", "true");
    }
    close() {
        if (!this.container)
            return;
        this.container.style.display = "none";
        this.isOpen = false;
        this.activeIndex = -1;
        this.input?.setAttribute("aria-expanded", "false");
        this.clearActive();
    }
    destroy() {
        this.close();
        this.container?.remove();
        this.input?.removeEventListener("input", this.handleInput);
        this.input?.removeEventListener("keydown", this.handleKeyDown);
        this.input?.removeEventListener("blur", this.handleBlur);
        this.input = null;
        this.container = null;
    }
    init() {
        if (!this.input)
            return;
        this.createContainer();
        this.input.setAttribute("role", "combobox");
        this.input.setAttribute("aria-autocomplete", "list");
        this.input.setAttribute("aria-expanded", "false");
        this.input.setAttribute("aria-haspopup", "listbox");
        this.input.addEventListener("input", this.handleInput);
        this.input.addEventListener("keydown", this.handleKeyDown);
        this.input.addEventListener("blur", this.handleBlur);
        this.input.addEventListener("focus", () => {
            if (this.currentSuggestions.length > 0)
                this.open();
        });
    }
    createContainer() {
        this.container = document.createElement("div");
        this.container.className = this.options.containerClass;
        this.container.setAttribute("role", "listbox");
        this.container.style.display = "none";
        this.container.style.position = "absolute";
        const wrapper = document.createElement("div");
        wrapper.style.position = "relative";
        if (this.input) {
            this.input.parentNode?.insertBefore(wrapper, this.input);
            wrapper.appendChild(this.input);
        }
        wrapper.appendChild(this.container);
    }
    async updateSuggestions(query) {
        let suggestions;
        if (this.options.fetchSuggestions &&
            this.options.suggestions.length === 0) {
            suggestions = await this.options.fetchSuggestions(query);
        }
        else {
            const lowerQuery = query.toLowerCase();
            suggestions = this.options.suggestions.filter((s) => s.toLowerCase().includes(lowerQuery));
        }
        this.currentSuggestions = suggestions.slice(0, this.options.maxResults);
        this.renderSuggestions(query);
        if (this.currentSuggestions.length > 0) {
            this.open();
        }
        else {
            this.close();
        }
    }
    renderSuggestions(query) {
        if (!this.container)
            return;
        this.container.innerHTML = "";
        this.activeIndex = -1;
        this.currentSuggestions.forEach((suggestion, index) => {
            const item = document.createElement("div");
            item.className = this.options.itemClass;
            item.setAttribute("role", "option");
            item.setAttribute("data-index", String(index));
            if (this.options.highlight) {
                item.innerHTML = this.highlightMatch(suggestion, query);
            }
            else {
                item.textContent = suggestion;
            }
            item.addEventListener("mousedown", (e) => {
                e.preventDefault();
                this.selectSuggestion(index);
            });
            item.addEventListener("mouseenter", () => {
                this.setActive(index);
            });
            this.container?.appendChild(item);
        });
    }
    highlightMatch(text, query) {
        const regex = new RegExp(`(${this.escapeRegex(query)})`, "gi");
        return text.replace(regex, `<span class="${this.options.highlightClass}">$1</span>`);
    }
    escapeRegex(str) {
        return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    }
    moveActive(delta) {
        const newIndex = this.activeIndex + delta;
        const maxIndex = this.currentSuggestions.length - 1;
        if (newIndex < 0) {
            this.setActive(maxIndex);
        }
        else if (newIndex > maxIndex) {
            this.setActive(0);
        }
        else {
            this.setActive(newIndex);
        }
    }
    setActive(index) {
        this.clearActive();
        this.activeIndex = index;
        const item = this.container?.querySelector(`[data-index="${index}"]`);
        if (item) {
            item.classList.add(this.options.activeClass);
            item.setAttribute("aria-selected", "true");
            item.scrollIntoView({ block: "nearest" });
        }
    }
    clearActive() {
        this.container
            ?.querySelectorAll(`.${this.options.activeClass}`)
            .forEach((el) => {
            el.classList.remove(this.options.activeClass);
            el.setAttribute("aria-selected", "false");
        });
    }
    selectSuggestion(index) {
        const value = this.currentSuggestions[index];
        if (!value || !this.input)
            return;
        this.input.value = value;
        this.close();
        const item = this.container?.querySelector(`[data-index="${index}"]`);
        this.options.onSelect(value, item);
        this.input.dispatchEvent(new Event("change", { bubbles: true }));
    }
}
export default AutocompleteManager;
//# sourceMappingURL=AutocompleteManager.js.map