jQuery(document).ready(function ($) {

    /**
     * HTML-escape a value before string-concatenation into the DOM.
     *
     * Speed-test API responses and Globalping-relayed location/header strings
     * are not trusted — they MUST flow through this helper before being
     * concatenated into `.html(...)`. Numbers and undefined values are coerced
     * to safe strings.
     */
    function escHtml(value) {
        if (value === null || value === undefined) return '';
        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    }

    /**
     * Return a safe href value — `#` if the URL is not http(s).
     */
    function escUrl(value) {
        if (value === null || value === undefined || value === '') return '#';
        try {
            var u = new URL(String(value));
            if (u.protocol !== 'http:' && u.protocol !== 'https:') return '#';
            return escHtml(u.toString());
        } catch (e) {
            return '#';
        }
    }

    /* ========================================
       Speed Test Form — 3 Figma States
       State 1: Initial (animation paused, static frame)
       State 2: Running (animation plays, "Test running..." text)
       State 3: Results (animation stops, table + summary cards)
       ======================================== */
    var lottiePlayer = document.getElementById('speeinch-speed-animation');

    /**
     * Speed test submit handler.
     */
    var SPEEINCH_LOG = '[SiC]';
    // 120s mirrors the server-side wp_remote_post timeout; gives us headroom.
    var SPEEINCH_AJAX_TIMEOUT = 120000;
    // Debug-mode console output is gated behind a localized flag; production sites
    // never see ajax URLs or response previews in DevTools.
    var SPEEINCH_DEBUG = (typeof speeinch !== 'undefined' && speeinch.debug) === true;
    function debugLog() {
        if (!SPEEINCH_DEBUG) return;
        try { console.log.apply(console, arguments); } catch (e) {}
    }
    function debugError() {
        if (!SPEEINCH_DEBUG) return;
        try { console.error.apply(console, arguments); } catch (e) {}
    }

    $('#speeinch_speed_test_form').on("submit", function (e) {
        e.preventDefault();

        var form = $(this);
        var alert = $('#speeinch_form_response');
        var resultsContainer = $('#speeinch-results-container');
        var btn = $('#speeinch-run-test-btn');
        var progressEl = $('#speeinch-test-progress');
        var startedAt = Date.now();

        // Transition to State 2: Running.
        alert.html('').removeClass('notice notice-success notice-error').hide();
        resultsContainer.hide();
        btn.attr('disabled', true).html('&#9201; ' + 'Test running...');
        progressEl.removeAttr('hidden').show();
        if (lottiePlayer) {
            lottiePlayer.setLooping(true);
            lottiePlayer.play();
        }
        form.find('.submit .spinner').css({ "float": 'left', "visibility": 'visible' });

        debugLog(SPEEINCH_LOG, 'speed test starting', {
            ajaxurl: speeinch.ajaxurl,
            timeoutMs: SPEEINCH_AJAX_TIMEOUT
        });

        $.ajax({
            type: form.attr('method'),
            url: speeinch.ajaxurl,
            data: $(this).serialize(),
            timeout: SPEEINCH_AJAX_TIMEOUT,
            success: function (response, textStatus, xhr) {
                if (lottiePlayer) { lottiePlayer.stop(); }
                form.find('.submit .spinner').css({ "float": 'right', "visibility": 'hidden' });
                progressEl.hide();
                alert.show();

                debugLog(SPEEINCH_LOG, 'speed test response', {
                    status: xhr ? xhr.status : 'unknown',
                    elapsedMs: Date.now() - startedAt,
                    success: !!response.success,
                    bodyLength: xhr && xhr.responseText ? xhr.responseText.length : 0
                });

                if (response.success) {
                    var data = response.data;
                    if (data.locations && data.locations.length > 0) {
                        speeinch_show_globalping_results(data);
                        alert.addClass('notice notice-success');
                        alert.html('<p>Speed test completed from ' + escHtml(data.locations.length) + ' China location(s). Tested: ' + escHtml(data.domain) + '</p>');
                    } else if (data.servers) {
                        speeinch_show_results(data);
                        alert.addClass('notice notice-success');
                        var description = (data.summary && data.summary.description) ? data.summary.description : '';
                        alert.html('<p>' + escHtml(description) + '</p>');
                    } else {
                        alert.addClass('notice notice-success');
                        alert.html('<p>' + escHtml(typeof data === 'string' ? data : 'Speed test completed!') + '</p>');
                    }
                    btn.html('&#9201; Test Complete').attr('disabled', true);
                    $(document).trigger('speeinch_test_complete', [data]);
                } else {
                    alert.addClass('notice notice-error');
                    if (response.data && typeof response.data === 'object' && response.data.reconnect_url) {
                        var msg = response.data.message || 'Connect to enable this feature.';
                        var connectHtml = '<p>' + escHtml(msg) + ' <a class="button button-primary" style="margin-left:8px" href="' + escUrl(response.data.reconnect_url) + '">Connect</a></p>';
                        alert.html(connectHtml);
                    } else {
                        alert.html('<p>' + escHtml(typeof response.data === 'string' ? response.data : 'Speed test failed.') + '</p>');
                    }
                    btn.html('&#9201; Start Speed Test').attr('disabled', false);
                }
            },
            error: function (xhr, textStatus, errorThrown) {
                if (lottiePlayer) { lottiePlayer.stop(); }
                form.find('.submit .spinner').css({ "float": 'right', "visibility": 'hidden' });
                progressEl.hide();
                btn.html('&#9201; Start Speed Test').attr('disabled', false);

                var elapsedSec = Math.round((Date.now() - startedAt) / 1000);
                var status = xhr ? xhr.status : 0;
                debugError(SPEEINCH_LOG, 'speed test FAILED', {
                    httpStatus: status,
                    textStatus: textStatus,
                    errorThrown: errorThrown,
                    elapsedSec: elapsedSec,
                    bodyPreview: xhr && xhr.responseText ? xhr.responseText.slice(0, 500) : ''
                });

                // Category-specific message - users on sandbox hosts (TasteWP,
                // Playground, restricted shared hosts) typically hit status 0 or
                // a timeout; the message points them at the most likely cause.
                var errorMsg = '';
                var serverPayload = null;
                try { serverPayload = JSON.parse(xhr.responseText); } catch (_e) {}

                if (serverPayload && (serverPayload.data || serverPayload.message)) {
                    errorMsg = 'Speed test failed: ' + (serverPayload.data || serverPayload.message);
                } else if (textStatus === 'timeout' || status === 504 || status === 408) {
                    errorMsg = 'Speed test timed out after ' + elapsedSec + 's. China-side probes can be slow when networks are congested. Please try again.';
                } else if (status === 0) {
                    errorMsg = 'Could not reach the speed-test backend (api.speedinchinaplugin.com). ' +
                        'This usually happens on sandbox hosts (e.g. TasteWP, Playground) that block outbound HTTPS, ' +
                        'or when your site is offline. Check the browser DevTools Network tab for details.';
                } else if (status === 403) {
                    errorMsg = 'Speed test rejected by the server (HTTP 403). This usually means the security nonce expired - reload the page and try again.';
                } else if (status === 500 || status === 502) {
                    errorMsg = 'Server error while running the speed test (HTTP ' + status + '). This is most likely a backend issue; please try again in a minute.';
                } else if (status >= 400) {
                    errorMsg = 'Speed test failed with HTTP ' + status + (errorThrown ? ' (' + errorThrown + ')' : '') + '.';
                } else {
                    errorMsg = 'Speed test failed: ' + (errorThrown || textStatus || 'unknown error');
                }

                alert.addClass('notice notice-error').html('<p>' + escHtml(errorMsg) + '</p>').show();
            },
        });
    });

    /* ========================================
       Show Globalping Results — Timing Breakdown
       ======================================== */
    function speeinch_show_globalping_results(data) {
        var container = $('#speeinch-results-container');
        var tbody = $('#speeinch_form_result tbody');
        var summaryList = $('#speeinch-summary-stats');

        tbody.html('');
        summaryList.html('');

        // Build timing table rows
        $.each(data.locations, function (i, loc) {
            var t = loc.timings || {};
            var statusClass = (loc.statusCode >= 200 && loc.statusCode < 400) ? 'dashicons-yes-alt' : 'dashicons-dismiss';

            tbody.append(
                '<tr>' +
                '<td><strong>' + escHtml(loc.location) + '</strong></td>' +
                '<td>' + escHtml(formatMs(t.dns)) + '</td>' +
                '<td>' + escHtml(formatMs(t.tcp)) + '</td>' +
                '<td>' + escHtml(formatMs(t.tls)) + '</td>' +
                '<td>' + escHtml(formatMs(t.firstByte)) + '</td>' +
                '<td>' + escHtml(formatMs(t.download)) + '</td>' +
                '<td><strong>' + escHtml(formatMs(t.total)) + '</strong></td>' +
                '<td><span class="dashicons ' + statusClass + '"></span> ' + escHtml(loc.status) + '</td>' +
                '</tr>'
            );
        });

        // Build optimization suggestions
        if (data.suggestions && data.suggestions.length > 0) {
            var sugHtml = '<div class="speeinch-suggestions" style="margin-top: 20px;">';
            sugHtml += '<h3>📊 Optimization Suggestions</h3>';

            $.each(data.suggestions, function (i, sug) {
                var badge = sug.status === 'good'
                    ? '<span style="background:#22c55e;color:#fff;padding:2px 8px;border-radius:3px;font-size:11px;">GOOD</span>'
                    : '<span style="background:#ef4444;color:#fff;padding:2px 8px;border-radius:3px;font-size:11px;">SLOW</span>';

                sugHtml += '<div style="padding:10px 14px;border-left:4px solid ' + (sug.status === 'good' ? '#22c55e' : '#ef4444') + ';background:' + (sug.status === 'good' ? '#f0fdf4' : '#fef2f2') + ';margin-bottom:6px;border-radius:0 4px 4px 0;">';
                sugHtml += '<strong>' + escHtml(sug.metric) + '</strong> ' + badge + ' <span style="color:#6b7280;">' + escHtml(sug.value_ms) + 'ms (threshold: ' + escHtml(sug.threshold) + 'ms)</span>';
                if (sug.suggestion) {
                    sugHtml += '<div style="margin-top:4px;color:#4b5563;font-size:13px;">' + escHtml(sug.suggestion) + '</div>';
                }
                sugHtml += '</div>';
            });

            sugHtml += '</div>';
            container.append(sugHtml);
        }

        // Summary stats
        var totalLocations = data.locations.length;
        var successCount = data.locations.filter(function (l) { return l.statusCode >= 200 && l.statusCode < 400; }).length;

        summaryList.append(
            '<li><span class="dashicons dashicons-yes-alt"></span><span>' + escHtml(totalLocations) + ' Locations<p>Tested</p></span></li>' +
            '<li><span class="dashicons dashicons-' + (successCount === totalLocations ? 'yes-alt' : 'warning') + '"></span><span>' + escHtml(successCount) + ' of ' + escHtml(totalLocations) + '<p>Successful</p></span></li>'
        );

        container.show();
    }

    function formatMs(val) {
        if (val === null || val === undefined) return '—';
        if (val > 1000) return (val / 1000).toFixed(1) + 's';
        return val + 'ms';
    }

    /* ========================================
       Legacy Results (ViewDNS format)
       ======================================== */
    function speeinch_show_results(results) {
        var container = $('#speeinch-results-container');
        var tbody = $('#speeinch_form_result tbody');
        var summaryList = $('#speeinch-summary-stats');

        tbody.html('');
        summaryList.html('');

        if (results.servers) {
            $.each(results.servers, function (index, result) {
                var statusIcon = result.resultstatus === 'ok'
                    ? '<span class="dashicons dashicons-yes-alt"></span>'
                    : '<span class="dashicons dashicons-dismiss"></span>';

                tbody.append(
                    '<tr>' +
                    '<td>' + escHtml(result.location) + '</td>' +
                    '<td colspan="6">' + escHtml(result.resultvalue) + '</td>' +
                    '<td>' + statusIcon + '</td>' +
                    '</tr>'
                );
            });
        }

        container.show();
    }

    /* ========================================
       Countdown Timer — Next Test Available
       ======================================== */
    var countdownEl = document.getElementById('speeinch-countdown-timer');
    if (countdownEl) {
        var nextRun = parseInt(countdownEl.getAttribute('data-next-run'), 10) * 1000; // to ms

        function updateCountdown() {
            var now = Date.now();
            var diff = nextRun - now;

            if (diff <= 0) {
                // Countdown finished — enable button and refresh
                $('#speeinch-run-test-btn').attr('disabled', false);
                $('.speeinch-cooldown-notice').fadeOut();
                return;
            }

            var days = Math.floor(diff / (1000 * 60 * 60 * 24));
            var hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            var mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
            var secs = Math.floor((diff % (1000 * 60)) / 1000);

            $('#speeinch-cd-days').text(days);
            $('#speeinch-cd-hours').text(hours);
            $('#speeinch-cd-mins').text(mins);
            $('#speeinch-cd-secs').text(secs);

            setTimeout(updateCountdown, 1000);
        }

        updateCountdown();
    }

    /* ========================================
       Update persisted result after test completes
       ======================================== */
    $(document).on('speeinch_test_complete', function (e, data) {
        if (!data || !data.locations) return;
        var $persisted = $('#speeinch-persisted-result');
        if ($persisted.length === 0) return;

        // Update header
        var now = new Date();
        var timeStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + ' ' + String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0');
        $persisted.find('h3 small').html(escHtml(timeStr) + (data.domain ? ' — ' + escHtml(data.domain) : ''));

        // Update stats
        var totalSum = 0;
        $.each(data.locations, function (i, loc) { totalSum += (loc.timings && loc.timings.total) || 0; });
        var avg = Math.round(totalSum / data.locations.length);
        var avgClass = avg < 1000 ? 'speeinch-status-good' : (avg < 3000 ? 'speeinch-status-warning' : 'speeinch-status-bad');
        $persisted.find('.speeinch-stat-value').first().removeClass('speeinch-status-good speeinch-status-warning speeinch-status-bad').addClass(avgClass).text(avg + 'ms');
        $persisted.find('.speeinch-stat-value').eq(1).text(data.locations.length);

        // Update table body
        var tbody = $persisted.find('tbody');
        tbody.html('');
        $.each(data.locations, function (i, loc) {
            var t = loc.timings || {};
            var icon = (loc.statusCode >= 200 && loc.statusCode < 400) ? 'dashicons-yes-alt' : 'dashicons-dismiss';
            var city = loc.city || loc.location || 'Unknown';
            var country = loc.country || '';
            tbody.append('<tr>' +
                '<td>' + escHtml(city) + (country ? ', ' + escHtml(country) : '') + '</td>' +
                '<td>' + (t.dns !== undefined ? escHtml(Math.round(t.dns) + 'ms') : '—') + '</td>' +
                '<td>' + (t.tcp !== undefined ? escHtml(Math.round(t.tcp) + 'ms') : '—') + '</td>' +
                '<td>' + (t.tls !== undefined ? escHtml(Math.round(t.tls) + 'ms') : '—') + '</td>' +
                '<td>' + (t.firstByte !== undefined ? escHtml(Math.round(t.firstByte) + 'ms') : '—') + '</td>' +
                '<td><strong>' + (t.total !== undefined ? escHtml(Math.round(t.total) + 'ms') : '—') + '</strong></td>' +
                '<td><span class="dashicons ' + icon + '"></span> HTTP ' + escHtml(loc.statusCode || '?') + '</td>' +
                '</tr>');
        });

        $persisted.show();
    });
});
