/**
 * WHP local-time conversion.
 *
 * Server-rendered timestamps are UTC. Each timestamp is wrapped in markup
 * carrying the original ISO/UTC value so the browser can rewrite the
 * visible text (and optionally the title attribute) into the user's
 * locale + timezone.
 *
 * Markup conventions:
 *
 *   <span class="local-time" data-utc="2026-05-02T01:34:30Z" data-format="datetime">
 *     2026-05-02 01:34:30 UTC
 *   </span>
 *     -> textContent rewritten; title set to the original UTC text.
 *
 *   <small data-utc-title="2026-05-02T01:34:30Z" title="2026-05-02 01:34:30 UTC">
 *     4d 2h
 *   </small>
 *     -> title attribute rewritten; visible text untouched.
 *
 *   data-format hints (optional): "date", "datetime", "datetime-seconds".
 *   When absent, the helper falls back to the same heuristic the original
 *   inline handler in backups.php used (presence of seconds in the text).
 *
 * Idempotent: each element is marked with data-converted once handled, so
 * repeated runs (DOMContentLoaded + MutationObserver) don't double-apply.
 */
(function () {
    'use strict';

    var FORMAT_OPTIONS = {
        'date':              { year: 'numeric', month: 'short', day: 'numeric' },
        'datetime':          { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' },
        'datetime-seconds':  { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit' }
    };

    function parseUtc(value) {
        if (!value) return null;
        // MySQL DATETIME ("YYYY-MM-DD HH:MM:SS") has no zone — treat as UTC.
        if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value)) {
            value = value.replace(' ', 'T') + 'Z';
        }
        var d = new Date(value);
        return isNaN(d.getTime()) ? null : d;
    }

    function pickFormat(element, fallbackText) {
        var hint = element.getAttribute('data-format');
        if (hint && FORMAT_OPTIONS[hint]) return FORMAT_OPTIONS[hint];
        // Heuristic: if the visible text contains seconds (HH:MM:SS), keep
        // them. Same rule the original backups.php handler used.
        if (fallbackText && /\d{1,2}:\d{2}:\d{2}/.test(fallbackText)) {
            return FORMAT_OPTIONS['datetime-seconds'];
        }
        if (fallbackText && /\d{1,2}:\d{2}/.test(fallbackText)) {
            return FORMAT_OPTIONS['datetime'];
        }
        return FORMAT_OPTIONS['date'];
    }

    function convertTextElements(scope) {
        var nodes = (scope || document).querySelectorAll('.local-time[data-utc]:not([data-converted])');
        nodes.forEach(function (el) {
            var iso = el.getAttribute('data-utc');
            var d = parseUtc(iso);
            if (!d) {
                el.setAttribute('data-converted', 'invalid');
                return;
            }
            var originalText = el.textContent.trim();
            var opts = pickFormat(el, originalText);
            try {
                var local = d.toLocaleString(undefined, opts);
                el.textContent = local;
                // Preserve any existing title; otherwise show the original
                // server time so a hover discloses the source value.
                if (!el.getAttribute('title')) {
                    el.title = 'Server time (UTC): ' + originalText;
                }
                el.setAttribute('data-converted', 'true');
            } catch (e) {
                el.setAttribute('data-converted', 'error');
            }
        });
    }

    function convertTitleAttrs(scope) {
        var nodes = (scope || document).querySelectorAll('[data-utc-title]:not([data-utc-title-converted])');
        nodes.forEach(function (el) {
            var iso = el.getAttribute('data-utc-title');
            var d = parseUtc(iso);
            if (!d) {
                el.setAttribute('data-utc-title-converted', 'invalid');
                return;
            }
            // Title-only conversions default to seconds-precision since
            // tooltips usually show the precise value.
            var hint = el.getAttribute('data-format-title') || 'datetime-seconds';
            var opts = FORMAT_OPTIONS[hint] || FORMAT_OPTIONS['datetime-seconds'];
            try {
                el.title = d.toLocaleString(undefined, opts);
                el.setAttribute('data-utc-title-converted', 'true');
            } catch (e) {
                el.setAttribute('data-utc-title-converted', 'error');
            }
        });
    }

    function refresh(scope) {
        convertTextElements(scope);
        convertTitleAttrs(scope);
    }

    // Expose for explicit re-runs after AJAX inserts. The MutationObserver
    // below handles most cases automatically, but a manual hook is useful
    // for callers that already track their own render lifecycle.
    window.whpRefreshTimes = refresh;

    function init() {
        refresh(document);

        if (typeof MutationObserver === 'undefined') return;

        var observer = new MutationObserver(function (mutations) {
            for (var i = 0; i < mutations.length; i++) {
                var added = mutations[i].addedNodes;
                for (var j = 0; j < added.length; j++) {
                    var n = added[j];
                    if (n.nodeType !== 1) continue;  // ELEMENT_NODE
                    // The added node itself OR any descendant may carry the
                    // markers — refresh the whole subtree to be safe.
                    refresh(n);
                }
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
