const CONSENT_PREFIX = "havelseiten:external:";

function storageGet(key) {
    try {
        return localStorage.getItem(key);
    } catch (error) {
        return null;
    }
}

function storageSet(key, value) {
    try {
        localStorage.setItem(key, value);
    } catch (error) {
        // If storage is unavailable, the current in-page load still works.
    }
}

function consentKey(button) {
    if (button.dataset.consentKey) {
        return `${CONSENT_PREFIX}${button.dataset.consentKey}`;
    }

    if (button.dataset.mapAddress) {
        return `${CONSENT_PREFIX}map:${button.dataset.mapAddress}`;
    }

    if (button.dataset.embedSrc) {
        return `${CONSENT_PREFIX}embed:${button.dataset.embedSrc}`;
    }

    return "";
}

function mapEmbedUrl(lat, lon) {
    const latitude = Number(lat);
    const longitude = Number(lon);
    const bbox = [
        longitude - 0.01,
        latitude - 0.006,
        longitude + 0.01,
        latitude + 0.006
    ].join(",");

    return (
        "https://www.openstreetmap.org/export/embed.html"
        + `?bbox=${encodeURIComponent(bbox)}`
        + "&layer=mapnik"
        + `&marker=${encodeURIComponent(`${latitude},${longitude}`)}`
    );
}

async function geocodeAddress(address) {
    const url = (
        "https://nominatim.openstreetmap.org/search"
        + `?format=json&limit=1&q=${encodeURIComponent(address)}`
    );
    const response = await fetch(url, {
        headers: {
            Accept: "application/json"
        }
    });
    const results = await response.json();

    if (!results.length) {
        throw new Error("Adresse nicht gefunden");
    }

    return results[0];
}

async function loadEmbed(button, remember = true) {
    const iframe = document.createElement("iframe");
    const key = consentKey(button);

    button.disabled = true;
    button.textContent = "Wird geladen...";

    if (button.dataset.mapAddress) {
        const cachedMapUrl = storageGet(`${key}:src`);

        if (cachedMapUrl) {
            iframe.src = cachedMapUrl;
        } else {
            try {
                const place = await geocodeAddress(button.dataset.mapAddress);
                iframe.src = mapEmbedUrl(place.lat, place.lon);
                storageSet(`${key}:src`, iframe.src);
            } catch (error) {
                button.disabled = false;
                button.textContent = "Karte konnte nicht geladen werden";
                return;
            }
        }
    } else {
        iframe.src = button.dataset.embedSrc;
    }

    iframe.className = button.dataset.embedClass || "";
    iframe.title = button.dataset.embedTitle || "Externer Inhalt";
    iframe.loading = "lazy";
    iframe.allow = button.dataset.embedAllow || "";
    iframe.allowFullscreen = true;

    if (remember && key) {
        storageSet(key, "1");
    }

    button.closest(".external-placeholder, .location-placeholder").replaceWith(iframe);
}

function galleryItems() {
    return [...document.querySelectorAll(".gallery-grid a")].map((link) => ({
        alt: link.querySelector("img")?.alt || "",
        height: link.dataset.pswpHeight,
        src: link.href,
        width: link.dataset.pswpWidth
    }));
}

function createLightbox() {
    const lightbox = document.createElement("div");
    lightbox.className = "site-lightbox";
    lightbox.hidden = true;
    lightbox.innerHTML = `
        <button class="site-lightbox-close" type="button" aria-label="Schliessen">×</button>
        <button class="site-lightbox-prev" type="button" aria-label="Vorheriges Bild">‹</button>
        <figure>
            <img alt="">
            <figcaption></figcaption>
        </figure>
        <button class="site-lightbox-next" type="button" aria-label="Naechstes Bild">›</button>
    `;
    document.body.append(lightbox);

    return lightbox;
}

function initGallery() {
    const items = galleryItems();

    if (!items.length) {
        return;
    }

    const lightbox = createLightbox();
    const image = lightbox.querySelector("img");
    const caption = lightbox.querySelector("figcaption");
    let currentIndex = 0;
    let touchStartX = 0;

    function show(index) {
        currentIndex = (index + items.length) % items.length;
        const item = items[currentIndex];
        image.src = item.src;
        image.alt = item.alt;
        caption.textContent = item.alt;
        caption.hidden = !item.alt;
        lightbox.hidden = false;
        document.body.classList.add("lightbox-open");
    }

    function close() {
        lightbox.hidden = true;
        image.removeAttribute("src");
        document.body.classList.remove("lightbox-open");
    }

    function next() {
        show(currentIndex + 1);
    }

    function prev() {
        show(currentIndex - 1);
    }

    document.querySelectorAll(".gallery-grid a").forEach((link, index) => {
        link.addEventListener("click", (event) => {
            event.preventDefault();
            show(index);
        });
    });

    lightbox.querySelector(".site-lightbox-close").addEventListener("click", close);
    lightbox.querySelector(".site-lightbox-next").addEventListener("click", next);
    lightbox.querySelector(".site-lightbox-prev").addEventListener("click", prev);

    lightbox.addEventListener("click", (event) => {
        if (event.target === lightbox) {
            close();
        }
    });

    lightbox.addEventListener("touchstart", (event) => {
        touchStartX = event.changedTouches[0].clientX;
    }, { passive: true });

    lightbox.addEventListener("touchend", (event) => {
        const delta = event.changedTouches[0].clientX - touchStartX;

        if (Math.abs(delta) < 40) {
            return;
        }

        if (delta < 0) {
            next();
        } else {
            prev();
        }
    }, { passive: true });

    document.addEventListener("keydown", (event) => {
        if (lightbox.hidden) {
            return;
        }

        if (event.key === "Escape") {
            close();
        } else if (event.key === "ArrowRight") {
            next();
        } else if (event.key === "ArrowLeft") {
            prev();
        }
    });
}

function initSubmenus() {
    const mobileQuery = window.matchMedia("(max-width: 800px)");

    document.querySelectorAll(".dropdown").forEach((dropdown) => {
        const button = dropdown.querySelector(".dropdown-label");

        if (!button) {
            return;
        }

        const startsOpen = (
            document.body.classList.contains("mobile-submenus-open")
            && mobileQuery.matches
        );

        dropdown.classList.toggle("is-open", startsOpen);
        button.setAttribute("aria-expanded", startsOpen ? "true" : "false");
        button.addEventListener("click", (event) => {
            if (!mobileQuery.matches) {
                return;
            }

            event.preventDefault();
            const isOpen = dropdown.classList.toggle("is-open");
            button.setAttribute("aria-expanded", isOpen ? "true" : "false");
        });

        dropdown.addEventListener("mouseenter", () => {
            if (mobileQuery.matches) {
                return;
            }

            dropdown.classList.add("is-open");
            button.setAttribute("aria-expanded", "true");
        });

        dropdown.addEventListener("mouseleave", () => {
            if (mobileQuery.matches) {
                return;
            }

            dropdown.classList.remove("is-open");
            button.setAttribute("aria-expanded", "false");
        });

        dropdown.addEventListener("focusin", () => {
            if (mobileQuery.matches) {
                return;
            }

            dropdown.classList.add("is-open");
            button.setAttribute("aria-expanded", "true");
        });

        dropdown.addEventListener("focusout", (event) => {
            if (
                mobileQuery.matches
                || dropdown.contains(event.relatedTarget)
            ) {
                return;
            }

            dropdown.classList.remove("is-open");
            button.setAttribute("aria-expanded", "false");
        });
    });
}

document.querySelectorAll(".external-load-button").forEach((button) => {
    const key = consentKey(button);

    if (button.dataset.autoLoad === "true" || (key && storageGet(key) === "1")) {
        loadEmbed(button, false);
    }
});

document.addEventListener("click", (event) => {
    const externalButton = event.target.closest(".external-load-button");

    if (externalButton) {
        loadEmbed(externalButton);
    }

    const galleryButton = event.target.closest(".gallery-load-button");

    if (galleryButton) {
        const section = galleryButton.closest(".gallery-section");
        const grid = section?.querySelector(".gallery-grid");

        if (grid) {
            grid.hidden = false;
        }

        galleryButton.closest(".gallery-placeholder")?.remove();
    }
});

initSubmenus();
initGallery();
