function createBaseState(options = {}) {
    return {
        mobileMenuOpen: false,
        cartOpen: false,
        scrolled: false,
        navReady: false,
        pendingCartOpenUntil: 0,
        lastCartCount: null,

        init() {
            this.updateScrollState();
            requestAnimationFrame(() => {
                this.navReady = true;
            });
            this.$watch("mobileMenuOpen", () => this.syncBodyLock());
            this.$watch("cartOpen", () => this.syncBodyLock());

            this._themeScrollHandler = () => this.updateScrollState();
            this._themeResizeHandler = () => {
                this.updateScrollState();
                if (typeof this.onResize === "function") {
                    this.onResize();
                }
            };
            this._themeCartIntentHandler = (event) => {
                const target = event.target instanceof Element ? event.target : null;
                const cartTrigger = event.type === "submit"
                    ? target?.closest("[data-cart-add-form]")
                    : target?.closest("[data-cart-add-trigger]");
                if (!cartTrigger) {
                    return;
                }

                this.markCartShouldOpen();
            };
            this._themeCartOpenHandler = () => this.openCart();
            this._themeRefreshCartObserverHandler = () => this.setupCartCountObserver();
            this._themeTurboCartStreamHandler = (event) => {
                const stream = event.target;
                if (!(stream instanceof Element)) {
                    return;
                }

                const action = stream.getAttribute("action");
                const targets = stream.getAttribute("targets");
                const hasRecentAddIntent = this.pendingCartOpenUntil > Date.now();

                if (!hasRecentAddIntent || action !== "update" || targets !== ".cart-items-count") {
                    return;
                }

                requestAnimationFrame(() => {
                    this.openCart(true);
                    this.pendingCartOpenUntil = 0;
                    this.setupCartCountObserver();
                });
            };

            window.addEventListener("scroll", this._themeScrollHandler, {passive: true});
            window.addEventListener("resize", this._themeResizeHandler, {passive: true});
            window.addEventListener("theme:open-cart", this._themeCartOpenHandler);
            document.addEventListener("click", this._themeCartIntentHandler, true);
            document.addEventListener("submit", this._themeCartIntentHandler, true);
            document.addEventListener("turbo:load", this._themeRefreshCartObserverHandler);
            document.addEventListener("turbo:before-stream-render", this._themeTurboCartStreamHandler);

            if (typeof this.onReady === "function") {
                this.onReady();
            }

            this.setupCartCountObserver();
            this.setupCartNotificationObserver();
            this.syncBodyLock();
        },

        updateScrollState() {
            this.scrolled = window.scrollY > 24;
        },

        openCart(openedAfterAdd = false) {
            this.mobileMenuOpen = false;
            this.cartOpen = true;

            if (openedAfterAdd) {
                this._themeSuppressCartNotificationsUntil = Date.now() + 2000;
                this.discardPendingCartNotifications();
            }
        },

        closeCart() {
            this.cartOpen = false;
        },

        toggleMobileMenu() {
            this.mobileMenuOpen = !this.mobileMenuOpen;
            if (this.mobileMenuOpen) {
                this.cartOpen = false;
            }
        },

        syncBodyLock() {
            document.body.classList.toggle("overflow-hidden", this.mobileMenuOpen || this.cartOpen);
        },

        markCartShouldOpen() {
            this.pendingCartOpenUntil = Date.now() + 5000;
        },

        setupCartCountObserver() {
            const countNode = document.querySelector(".cart-items-count");
            if (!countNode) {
                return;
            }

            if (this._themeCartCountObserver) {
                this._themeCartCountObserver.disconnect();
            }

            const readCount = () => {
                const value = Number.parseInt(countNode.textContent?.trim() || "0", 10);
                return Number.isNaN(value) ? 0 : value;
            };

            this.lastCartCount = readCount();
            this._themeCartCountObserver = new MutationObserver(() => {
                const nextCount = readCount();
                const hasRecentAddIntent = this.pendingCartOpenUntil > Date.now();

                if (hasRecentAddIntent && nextCount > (this.lastCartCount ?? 0)) {
                    this.openCart(true);
                    this.pendingCartOpenUntil = 0;
                }

                this.lastCartCount = nextCount;
            });

            this._themeCartCountObserver.observe(countNode, {
                childList: true,
                characterData: true,
                subtree: true,
            });
        },

        setupCartNotificationObserver() {
            const container = document.getElementById("alert");
            if (!container) {
                return;
            }

            this._themeCartNotificationObserver?.disconnect();
            this._themePendingCartNotifications = new Set();
            this._themeSuppressCartNotificationsUntil = 0;
            this._themeCartNotificationObserver = new MutationObserver((mutations) => {
                const now = Date.now();
                const hasRecentAddIntent = this.pendingCartOpenUntil > now;
                const suppressAfterCartOpen = this.cartOpen
                    && this._themeSuppressCartNotificationsUntil > now;

                if (!hasRecentAddIntent && !suppressAfterCartOpen) {
                    return;
                }

                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (!(node instanceof Element)) {
                            return;
                        }

                        const isSuccess = node.matches(".border-emerald-200")
                            || node.querySelector(".border-emerald-200");
                        if (!isSuccess) {
                            return;
                        }

                        if (this.cartOpen && this._themeSuppressCartNotificationsUntil > Date.now()) {
                            node.remove();
                            return;
                        }

                        node.hidden = true;
                        this._themePendingCartNotifications.add(node);
                        window.setTimeout(() => {
                            this._themePendingCartNotifications.delete(node);
                            if (!node.isConnected) {
                                return;
                            }

                            if (this.cartOpen && this._themeSuppressCartNotificationsUntil > Date.now()) {
                                node.remove();
                                return;
                            }

                            node.hidden = false;
                        }, 2000);
                    });
                });
            });

            this._themeCartNotificationObserver.observe(container, {
                childList: true,
            });
        },

        discardPendingCartNotifications() {
            this._themePendingCartNotifications?.forEach((notification) => {
                if (this.cartOpen) {
                    notification.remove();
                }
            });
            this._themePendingCartNotifications?.clear();
        },

        ...options,
    };
}

function initThemeReveal() {
    const elements = document.querySelectorAll("[data-theme-reveal]");

    if (!elements.length) {
        return;
    }

    const reveal = (element) => {
        element.classList.remove("opacity-0", "translate-y-8", "translate-y-10");
        element.classList.add("opacity-100", "translate-y-0");
    };

    if (!("IntersectionObserver" in window)) {
        elements.forEach(reveal);
        return;
    }

    const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
            if (!entry.isIntersecting) {
                return;
            }

            reveal(entry.target);
            observer.unobserve(entry.target);
        });
    }, {
        threshold: 0.2,
    });

    elements.forEach((element) => observer.observe(element));
}

document.addEventListener("turbo:load", initThemeReveal);
window.addEventListener("DOMContentLoaded", initThemeReveal);

function createVideoPlayerState() {
    return {
        isPaused: true,

        init() {
            this.syncPlaybackState();

            if (!("IntersectionObserver" in window)) {
                return;
            }

            this._videoVisibilityObserver = new IntersectionObserver((entries) => {
                entries.forEach((entry) => {
                    if (!entry.isIntersecting) {
                        this.$refs.video.pause();
                    }
                });
            });

            this._videoVisibilityObserver.observe(this.$refs.video);
        },

        destroy() {
            this._videoVisibilityObserver?.disconnect();
        },

        play() {
            const playback = this.$refs.video.play();

            if (playback instanceof Promise) {
                playback.catch(() => this.handlePause());
            }
        },

        handlePlay() {
            this.isPaused = false;
        },

        handlePause() {
            this.isPaused = true;
        },

        syncPlaybackState() {
            if (this.$refs.video.paused) {
                this.handlePause();
                return;
            }

            this.handlePlay();
        },
    };
}

function createNotificationState() {
    return {
        close() {
            this.$root.remove();
        },
    };
}

export default function registerTheme(Alpine) {
    Alpine.data("heritageLayout", () => createBaseState());
    Alpine.data("heritageNotification", () => createNotificationState());
    Alpine.data("heritageVideo", () => createVideoPlayerState());

    Alpine.data("heritageShopLayout", () => createBaseState({
        updateScrollState() {
            this.scrolled = window.scrollY > 40;
        },
    }));
}
