// URL to your external JSON
var JSON_URL = 'https://raw.githubusercontent.com/apersongithub/Duolingo-Unlimited-Hearts/refs/heads/main/extension-version.json';

(function () {
    'use strict';
    // A unique ID to avoid duplicates
    const newElementId = 'extension-banner';

    // Default fallback JSON (Doesn't need sanitization as it's hardcoded and openly visible)
    const FALLBACK_CONFIG = {
        "BANNER": `
    <div class='thPiC'><img class='_1xOxM'
    src='https://raw.githubusercontent.com/apersongithub/Duolingo-Unlimited-Hearts/refs/heads/main/extras/icon.svg'
    style='border-radius:100px'></div>
<div class='_3jiBp'>
  <h4 class='qyEhl'>Duolingo Max Extension</h4><span class='_3S2Xa'>Created by <a
      href='https://github.com/apersongithub' target='_blank' style='color:#07b3ec'>apersongithub</a></span>
</div>
<div class='_36kJA'>
  <div><a href='https://html-preview.github.io/?url=https://raw.githubusercontent.com/apersongithub/Duolingo-Unlimited-Hearts/refs/heads/main/extras/donations.html'
      target='_blank'><button class='_1ursp _2V6ug _2paU5 _3gQUj _7jW2t rdtAy'><span class='_9lHjd'
          style='color:#d7d62b'>💵 Donate</span></button></a></div>
</div>
  `
    };

    /**
     * Adds the custom element using BANNER from a config object
     */
    function addCustomElement(config, root = document) {
        if (document.getElementById(newElementId)) return;

        const refElement = root.querySelector('.ky51z._26JAQ.MGk8p');
        if (!refElement) return;

        const ul = document.createElement('ul');
        ul.className = 'Y6o36';

        const newLi = document.createElement('li');
        newLi.id = newElementId;
        newLi.className = '_17J_p';
        newLi.innerHTML = config.BANNER;

        ul.appendChild(newLi);
        refElement.parentNode.insertBefore(ul, refElement.nextSibling);

        console.log('Extension banner successfully added!');
    }

    /**
     * Securely fetch JSON config and inject banner only on /settings/super.
     */
    async function loadConfigAndInject() {
        if (!window.location.pathname.includes('/settings/super')) return;

        // Allow-list based sanitizer (no scripts, no event handlers, no javascript: URLs)
        function sanitizeHTML(unsafeHTML) {
            const template = document.createElement('template');
            template.innerHTML = unsafeHTML || '';

            // Expanded but still conservative allow‑list for general content needs
            const ALLOWED_TAGS = new Set([
                'DIV', 'SECTION',
                'H1', 'H2', 'H3', 'H4', 'H5', 'H6',
                'P', 'SPAN', 'SMALL',
                'A', 'BUTTON',
                'UL', 'OL', 'LI',
                'STRONG', 'EM', 'B', 'I', 'U',
                'BR', 'HR',
                'IMG'
            ]);
            const ALLOWED_ATTRS = new Set([
                'class', 'id',
                'href', 'src', 'target', 'rel',
                'style',
                'alt', 'title',
                'role',
                'aria-label', 'aria-hidden', 'aria-describedby', 'aria-expanded', 'aria-controls',
                'width', 'height',
                'tabindex'
            ]);

            // Remove dangerous elements outright
            template.content.querySelectorAll('script, iframe, object, embed, style, link, meta').forEach(el => el.remove());

            const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT);
            let node;
            while ((node = walker.nextNode())) {
                // Strip disallowed tags but keep their children
                if (!ALLOWED_TAGS.has(node.tagName)) {
                    const parent = node.parentNode;
                    if (parent) parent.replaceChild(document.createDocumentFragment().append(...node.childNodes), node);
                    continue;
                }

                // Scrub attributes
                [...node.attributes].forEach(attr => {
                    const name = attr.name.toLowerCase();
                    const value = attr.value.trim();

                    // Remove event handlers or non-allow-listed attributes
                    if (name.startsWith('on') || !ALLOWED_ATTRS.has(name)) {
                        node.removeAttribute(attr.name);
                        return;
                    }

                    if (name === 'href' || name === 'src') {
                        const lower = value.toLowerCase();
                        // Only allow http(s)
                        if (!/^https?:\/\//.test(lower)) {
                            node.removeAttribute(attr.name);
                            return;
                        }
                        // Extra guard
                        if (lower.startsWith('javascript:') || lower.startsWith('data:')) {
                            node.removeAttribute(attr.name);
                            return;
                        }
                    }

                    if (name === 'style') {
                        // Strip dangerous css patterns
                        if (/expression|javascript:|url\s*\(\s*javascript:/i.test(value)) {
                            node.removeAttribute(attr.name);
                        }
                    }
                });
            }

            return template.innerHTML;
        }

        try {
            const response = await fetch(JSON_URL, { cache: 'no-store' });
            if (!response.ok) throw new Error('Failed to fetch JSON');
            const remote = await response.json();

            // We IGNORE any attempt to supply executable code; only sanitized HTML allowed.
            const sanitized = sanitizeHTML(remote && remote.BANNER ? remote.BANNER : FALLBACK_CONFIG.BANNER);
            addCustomElement({ BANNER: sanitized });
        } catch (err) {
            console.warn('Failed to load external JSON, using fallback:', err);
            const sanitizedFallback = sanitizeHTML(FALLBACK_CONFIG.BANNER);
            addCustomElement({ BANNER: sanitizedFallback });
        }
    }

    // Remove "Manage subscription" section if it exists
    function removeManageSubscriptionSection(root = document) {
        const sections = root.querySelectorAll('section._3f-te');
        for (const section of sections) {
            const h2 = section.querySelector('h2._203-l');
            if (h2 && h2.textContent.trim() === 'Manage subscription') {
                section.remove();
                break;
            }
        }
    }

    // Observe DOM for dynamically added "Manage subscription" sections
    const manageSubObserver = new MutationObserver(() => removeManageSubscriptionSection());
    manageSubObserver.observe(document.documentElement, { childList: true, subtree: true });

    // Run immediately
    removeManageSubscriptionSection();
    loadConfigAndInject();

    // Observe DOM for dynamically added content
    const observer = new MutationObserver(() => loadConfigAndInject());
    observer.observe(document.documentElement, { childList: true, subtree: true });
})();

window.addEventListener('load', () => {
    // Default values in case fetch fails
    let EXTENSION_NAME = "Duolingo Max Extension";
    let EXTENSION_URL = "https://github.com/apersongithub/Duolingo-Unlimited-Hearts/";

    // Get current extension version from the injected banner
    let CURRENT_VERSION = chrome.runtime.getManifest().version; // fallback

    // Fallback defaults aligned with options page
    const DEFAULT_SETTINGS = {
        enableNotifications: true,
        major: { weeks: 0, days: 3, hours: 0, minutes: 0 },
        minor: { weeks: 1, days: 0, hours: 0, minutes: 0 }
    };

    // Helper to calculate total milliseconds for ignore duration
    function getIgnoreMs(duration) {
        return (
            ((duration.weeks * 7 * 24 * 60 * 60) +
                (duration.days * 24 * 60 * 60) +
                (duration.hours * 60 * 60) +
                (duration.minutes * 60)) * 1000
        );
    }

    // Load user settings saved from options page
    const getSettings = () => new Promise(resolve => {
        try {
            if (chrome && chrome.storage && chrome.storage.sync) {
                chrome.storage.sync.get('settings', data => {
                    resolve((data && data.settings) || DEFAULT_SETTINGS);
                });
            } else {
                resolve(DEFAULT_SETTINGS);
            }
        } catch (_) {
            resolve(DEFAULT_SETTINGS);
        }
    });

    getSettings().then(settings => {
        // Respect user toggle
        if (!settings.enableNotifications) return;

        // Check if user ignored the alert in the last configured time
        const ignoreKeyMajor = 'duo_extension_update_ignore_until_major';
        const ignoreKeyMinor = 'duo_extension_update_ignore_until_minor';
        const ignoreUntilMajor = localStorage.getItem(ignoreKeyMajor);
        const ignoreUntilMinor = localStorage.getItem(ignoreKeyMinor);
        const now = Date.now();

        // Fetch latest version from remote JSON and compare versions
        fetch(JSON_URL)
            .then(response => response.json())
            .then(data => {
                const latestVersion = data.version;
                const releaseDate = data.releaseDate; // "2025-08-28"
                const releaseNotes = data.releaseNotes || "";
                EXTENSION_NAME = data.EXTENSION_NAME || EXTENSION_NAME;
                EXTENSION_URL = data.EXTENSION_URL || EXTENSION_URL;

                const currentParts = CURRENT_VERSION.split('.').map(Number);
                const latestParts = latestVersion.split('.').map(Number);

                // Calculate days ago
                const releaseDateObj = new Date(releaseDate);
                const diffTime = Math.abs(now - releaseDateObj);
                const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));

                // Compare versions
                function compareVersions(a, b) {
                    for (let i = 0; i < Math.max(a.length, b.length); i++) {
                        const numA = a[i] || 0;
                        const numB = b[i] || 0;
                        if (numA < numB) return -1;
                        if (numA > numB) return 1;
                    }
                    return 0;
                }

                const cmp = compareVersions(currentParts, latestParts);

                const formatDuration = (d) => {
                    let minutes = Math.max(0, Number(d.minutes) || 0);
                    let hours = Math.max(0, Number(d.hours) || 0);
                    let days = Math.max(0, Number(d.days) || 0);
                    let weeks = Math.max(0, Number(d.weeks) || 0);

                    // Normalize smaller units into larger ones
                    hours += Math.floor(minutes / 60);
                    minutes %= 60;

                    days += Math.floor(hours / 24);
                    hours %= 24;

                    weeks += Math.floor(days / 7);
                    days %= 7;

                    const parts = [];
                    if (weeks) parts.push(`${weeks} ${weeks === 1 ? 'week' : 'weeks'}`);
                    if (days) parts.push(`${days} ${days === 1 ? 'day' : 'days'}`);
                    if (hours) parts.push(`${hours} ${hours === 1 ? 'hour' : 'hours'}`);
                    if (minutes) parts.push(`${minutes} ${minutes === 1 ? 'minute' : 'minutes'}`);

                    if (parts.length === 0) return 'the configured period';
                    if (parts.length === 1) return parts[0];
                    return `${parts.slice(0, -1).join(', ')} and ${parts[parts.length - 1]}`;
                };

                if (cmp < 0) {
                    // Major update
                    if (currentParts[0] < latestParts[0]) {
                        if (!ignoreUntilMajor || now > parseInt(ignoreUntilMajor, 10)) {
                            const ignoreMsMajor = getIgnoreMs(settings.major);
                            // Only show the "Note" if extension version is v3.1 or higher
                            const showNote = (
                                currentParts[0] > 3 ||
                                (currentParts[0] === 3 && currentParts[1] >= 1)
                            );
                            const note = showNote ? "\n\n Note: You can disable these notifications in the options page." : "";
                            if (confirm(`❗It's been ${diffDays} day(s) since a major update was released for ${EXTENSION_NAME}❗\n\n ⚠️ Please update for continued support ⚠️ \n\n Press OK to go to update page, or Cancel to ignore for ${formatDuration(settings.major)}.${note}`)) {
                                window.location.href = EXTENSION_URL;
                            } else {
                                localStorage.setItem(ignoreKeyMajor, (now + ignoreMsMajor).toString());
                            }
                        }
                    }
                    // Minor update (e.g. x.1)
                    else if (
                        (currentParts[0] === latestParts[0]) &&
                        (currentParts[1] < latestParts[1])
                    ) {
                        if (!ignoreUntilMinor || now > parseInt(ignoreUntilMinor, 10)) {
                            const ignoreMsMinor = getIgnoreMs(settings.minor);
                            // Only show the "Note" if extension version is v3.1 or higher
                            const showNote = (
                                currentParts[0] > 3 ||
                                (currentParts[0] === 3 && currentParts[1] >= 1)
                            );
                            const note = showNote ? "\n\n Note: You can disable these notifications in the options page." : "";
                            if (confirm(`ℹ️ A minor update (${latestVersion}) is available for ${EXTENSION_NAME}. \n\n Release notes: \n${releaseNotes} \n\n Press OK to go to update page, or Cancel to ignore for ${formatDuration(settings.minor)}.${note}`)) {
                                window.location.href = EXTENSION_URL;
                            } else {
                                localStorage.setItem(ignoreKeyMinor, (now + ignoreMsMinor).toString());
                            }
                        }
                    }
                } else if (cmp > 0) {
                    // Current version is higher than latest
                    alert(`🔨 You are using a beta version of ${EXTENSION_NAME}. Expect bugs and instability. Please report any issues on GitHub. \n\n IF YOU ARE NOT USING A BETA, IT IS A CACHE ISSUE. IGNORE THIS MESSAGE AND IT WILL GO AWAY WITHIN A FEW MINUTES`);
                }
                // If cmp === 0, do nothing (up to date)
            })
            .catch(() => {
                // Fail silently if unable to fetch version
            });
    });
});
