import mermaid from "{{ mermaid_js_url }}";

{% if mermaid_include_elk %}
import elkLayouts from "{{ mermaid_elk_js_url }}"
{% endif %}

{% if mermaid_include_zenuml %}
import zenumlLayouts from "{{ mermaid_zenuml_js_url }}"
{% endif %}

const initStyles = () => {
    const defaultStyle = document.createElement('style');
    defaultStyle.textContent = `{{ common_css }}`;
    document.head.appendChild(defaultStyle);

    const fullscreenStyle = document.createElement('style');
    fullscreenStyle.textContent = `{{ fullscreen_css }}`;
    document.head.appendChild(fullscreenStyle);
}

// Detect if page has dark background
const isDarkTheme = () => {
    // We use a set of heuristics:
    // 1. Check for common dark mode classes or attributes
    // 2. Check computed background color brightness
    if (document.documentElement.classList.contains('dark') ||
        document.documentElement.getAttribute('data-theme') === 'dark' ||
        document.body.classList.contains('dark') ||
        document.body.getAttribute('data-theme') === 'dark') {
        // console.log("Dark theme detected via class/attribute");
        return true;
    }
    if (document.documentElement.classList.contains('light') ||
        document.documentElement.getAttribute('data-theme') === 'light' ||
        document.body.classList.contains('light') ||
        document.body.getAttribute('data-theme') === 'light') {
        // console.log("Light theme detected via class/attribute");
        return false;
    }
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        // console.log("Dark theme detected via prefers-color-scheme");
        return true;
    }
    const bgColor = window.getComputedStyle(document.body).backgroundColor;
    const match = bgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)/);
    if (match) {
        const r = parseInt(match[1]);
        const g = parseInt(match[2]);
        const b = parseInt(match[3]);
        const brightness = (r * 299 + g * 587 + b * 114) / 1000;
        // console.log("Background color brightness:", brightness);
        return brightness < 128;
    }
    // console.log("No dark or light theme detected, defaulting to light theme");
    return false;
};

let darkTheme = isDarkTheme();
let modal = null;
let modalContent = null;
let previousScrollOffset = [window.scrollX, window.scrollY];

const runMermaid = async (rerun) => {
    console.log("Running mermaid diagrams, rerun =", rerun);
    // clear all existing mermaid charts
    let all_mermaids = document.querySelectorAll(".mermaid");

    if (rerun) {
        all_mermaids.forEach((el) => {
            if(!el.hasAttribute("data-original-code")) {
                // store original code
                // console.log(`Storing original code for first run: `, el.innerHTML);
                el.setAttribute('data-original-code', el.innerHTML);
            }
            if(el.getAttribute("data-processed") === "true") {
                // remove and restore original
                el.removeAttribute("data-processed");
                // console.log(`Restoring original code for re-run: `, el.getAttribute('data-original-code'));
                el.innerHTML = el.getAttribute('data-original-code');
            } else {
                // store original code
                // console.log(`Storing original code for re-run: `, el.innerHTML);
                el.setAttribute('data-original-code', el.innerHTML);
            }
        });
        await mermaid.run();
    }

    all_mermaids = document.querySelectorAll(".mermaid");
    const mermaids_processed = document.querySelectorAll(".mermaid[data-processed='true']");

    if ("{{ add_zoom }}" === "True") {
        const mermaids_to_add_zoom = {{ d3_node_count }} === -1 ? all_mermaids.length : {{ d3_node_count }};
        if(mermaids_to_add_zoom > 0) {
            var svgs = d3.selectAll("{{ d3_selector }}");
            if(all_mermaids.length !== mermaids_processed.length) {
                setTimeout(() => runMermaid(false), 200);
                return;
            } else if(svgs.size() !== mermaids_to_add_zoom) {
                setTimeout(() => runMermaid(false), 200);
                return;
            } else {
                svgs.each(function() {
                    var svg = d3.select(this);
                    svg.html("<g class='wrapper'>" + svg.html() + "</g>");
                    var inner = svg.select("g");
                    var zoom = d3.zoom().on("zoom", function(event) {
                        inner.attr("transform", event.transform);
                    });
                    svg.call(zoom);
                });
            }
        }
    } else if(all_mermaids.length !== mermaids_processed.length) {
        // Wait for mermaid to process all diagrams
        setTimeout(() => runMermaid(false), 200);
        return;
    }

    // Stop here if not adding fullscreen capability
    if ("{{ add_fullscreen }}" !== "True") return;

    if (modal !== null ) {
        // Destroy existing modal
        modal.remove();
        modal = null;
        modalContent = null;
    }

    modal = document.createElement('div');
    modal.className = 'mermaid-fullscreen-modal' + (darkTheme ? ' dark-theme' : '');
    modal.setAttribute('role', 'dialog');
    modal.setAttribute('aria-modal', 'true');
    modal.setAttribute('aria-label', 'Fullscreen diagram viewer');
    modal.innerHTML = `
        <button class="mermaid-fullscreen-close${darkTheme ? ' dark-theme' : ''}" aria-label="Close fullscreen">✕</button>
        <div class="mermaid-container-fullscreen${darkTheme ? ' dark-theme' : ''}"></div>
    `;
    document.body.appendChild(modal);

    modalContent = modal.querySelector('.mermaid-container-fullscreen');
    const closeBtn = modal.querySelector('.mermaid-fullscreen-close');

    const closeModal = () => {
        modal.classList.remove('active');
        modalContent.innerHTML = '';
        document.body.style.overflow = ''
        window.scrollTo({left: previousScrollOffset[0], top: previousScrollOffset[1], behavior: 'instant'});
    };

    closeBtn.addEventListener('click', closeModal);
    modal.addEventListener('click', (e) => {
        if (e.target === modal) closeModal();
    });
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && modal.classList.contains('active')) {
            closeModal();
        }
    });

    document.querySelectorAll('.mermaid').forEach((mermaidDiv) => {
        if (mermaidDiv.parentNode.classList.contains('mermaid-container') ||
            mermaidDiv.closest('.mermaid-fullscreen-modal')) {
            // Already processed, adjust button class if needed
            const existingBtn = mermaidDiv.parentNode.querySelector('.mermaid-fullscreen-btn');
            if (existingBtn) {
                existingBtn.className = 'mermaid-fullscreen-btn' + (darkTheme ? ' dark-theme' : '');
            }
            return;
        }

        const container = document.createElement('div');
        container.className = 'mermaid-container';
        mermaidDiv.parentNode.insertBefore(container, mermaidDiv);
        container.appendChild(mermaidDiv);

        const fullscreenBtn = document.createElement('button');
        fullscreenBtn.className = 'mermaid-fullscreen-btn' + (darkTheme ? ' dark-theme' : '');
        fullscreenBtn.setAttribute('aria-label', 'View diagram in fullscreen');
        fullscreenBtn.textContent = '{{ button_text }}';
        fullscreenBtn.style.opacity = '{{ button_opacity }}%';

        // Calculate dynamic position based on diagram's margin and padding
        const diagramStyle = window.getComputedStyle(mermaidDiv);
        const marginTop = parseFloat(diagramStyle.marginTop) || 0;
        const marginRight = parseFloat(diagramStyle.marginRight) || 0;
        const paddingTop = parseFloat(diagramStyle.paddingTop) || 0;
        const paddingRight = parseFloat(diagramStyle.paddingRight) || 0;
        fullscreenBtn.style.top = `${marginTop + paddingTop + 4}px`;
        fullscreenBtn.style.right = `${marginRight + paddingRight + 4}px`;

        fullscreenBtn.addEventListener('click', () => {
            previousScrollOffset = [window.scroll, window.scrollY];
            const clone = mermaidDiv.cloneNode(true);
            modalContent.innerHTML = '';
            modalContent.appendChild(clone);

            const svg = clone.querySelector('svg');
            if (svg) {
                svg.removeAttribute('width');
                svg.removeAttribute('height');
                svg.style.width = '100%';
                svg.style.height = 'auto';
                svg.style.maxWidth = '100%';
                svg.style.sdisplay = 'block';

                if ("{{ add_zoom }}" === "True") {
                    setTimeout(() => {
                        const g = svg.querySelector('g');
                        if (g) {
                            var svgD3 = d3.select(svg);
                            svgD3.html("<g class='wrapper'>" + svgD3.html() + "</g>");
                            var inner = svgD3.select("g");
                            var zoom = d3.zoom().on("zoom", function(event) {
                                inner.attr("transform", event.transform);
                            });
                            svgD3.call(zoom);
                        }
                    }, 100);
                }
            }

            modal.classList.add('active');
            document.body.style.overflow = 'hidden';
        });
        container.appendChild(fullscreenBtn);
    });
};

const load = async () => {
    initStyles();

    await runMermaid(true);

    const reRunIfThemeChanges = async () => {
        const newDarkTheme = isDarkTheme();
        if (newDarkTheme !== darkTheme) {
            darkTheme = newDarkTheme;
            console.log("Theme change detected, re-running mermaid with", darkTheme ? "dark" : "default", "theme");
            await mermaid.initialize(
                {...JSON.parse(
                    `{{ mermaid_init_config }}`
                ),
                ...{ darkMode: darkTheme, theme: darkTheme ? 'dark' : 'default' },
                }
            );
            await runMermaid(true);
        }
    };

    // Update theme classes when theme changes
    const themeObserver = new MutationObserver(reRunIfThemeChanges);
    themeObserver.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ['class', 'style', 'data-theme']
    });
    themeObserver.observe(document.body, {
        attributes: true,
        attributeFilter: ['class', 'style', 'data-theme']
    });
};

{% if mermaid_include_elk %}
mermaid.registerLayoutLoaders(elkLayouts);
{% endif %}

{% if mermaid_include_zenuml %}
mermaid.registerExternalDiagrams([zenumlLayouts]);
{% endif %}

console.log("Initializing mermaid with", darkTheme ? "dark" : "default", "theme");
mermaid.initialize(
    {...JSON.parse(
        `{{ mermaid_init_config }}`
    ),
    ...{ darkMode: darkTheme, theme: darkTheme ? 'dark' : 'default' },
    }
);

window.addEventListener("load", load);
window.runMermaid = runMermaid;
