/**
 * ETYKIETOWNIK — frontend logic for label creation in WooCommerce order admin.
 *
 * States: idle → options → awaiting_payment → paid → generating → completed | error
 * Everything inline in the meta box. No popups. No navigation.
 *
 * @package ParcelSelector
 * @since   3.4.0
 */
(function($) {
    'use strict';

    var cfg     = window.parcselectLabelConfig || {};
    var i18n    = cfg.i18n || {};
    var $wrap   = null;
    var orderId = 0;
    var pollTimer = null;
    var countdownTimer = null;

    // Debug logging — only active when WP_DEBUG or ?etyk_debug=1.
    var DEBUG = !!(cfg.debug || (window.location.search.indexOf('etyk_debug=1') !== -1));
    function log() { if (DEBUG) { console.log.apply(console, ['[ETYKIETOWNIK]'].concat(Array.prototype.slice.call(arguments))); } }
    function warn() { if (DEBUG) { console.warn.apply(console, ['[ETYKIETOWNIK]'].concat(Array.prototype.slice.call(arguments))); } }

    $(document).ready(function() {
        $wrap = $('#ps-label-wrap');
        if (!$wrap.length) {
            return;
        }

        orderId = parseInt($wrap.data('order-id'), 10);
        var status = $wrap.data('status') || '';
        log('Init: order=' + orderId + ', status=' + status);

        // Resume from persisted state.
        if (status === 'awaiting_payment') {
            resumePayment();
        } else if (status === 'paid' || status === 'generating') {
            showGenerating();
            startPolling();
        } else if (status === 'error') {
            resumeError();
        }

        bindEvents();
    });

    function bindEvents() {
        // Size options visible immediately — no toggle button needed.

        // Size change — GREEN confirmed + immediately show existing crypto payment.
        $(document).on('change', 'input[name="parcselect_size"]', function() {
            var size = $(this).val();
            var price = $(this).closest('.etyk-size-btn').data('price');
            log('Size selected: ' + size + ' price=' + price + ' PLN');

            // Mark selected as GREEN confirmed.
            $('.etyk-size-btn').removeClass('active etyk-size-confirmed').css({'border-color':'#e5e7eb','background':'#fff'});
            $(this).closest('.etyk-size-btn').addClass('etyk-size-confirmed');

            // Clear any stale payment session from previous selection.
            $('#etyk-step-payment').empty().hide();

            // Get receiver data from hidden fields.
            var name  = $('#etyk-recv-name').val().trim();
            var email = $('#etyk-recv-email').val().trim();
            var phone = $('#etyk-recv-phone').val().trim().replace(/[\s\-\(\)]/g, '');
            var phoneDigits = phone.replace(/^\+?48/, '').replace(/\D/g, '');
            if (phoneDigits.length === 9) { $('#etyk-recv-phone').val(phoneDigits); }
            var weight = parseFloat($('#etyk-weight').val()) || 0.2;

            // Show spinner, then load crypto payment.
            var $pay = $('#etyk-step-payment');
            $pay.html('<div style="text-align:center;padding:16px 0;"><span class="spinner is-active" style="float:none;margin:0 auto;"></span><br><small style="color:#64748b;font-size:11px;margin-top:6px;display:inline-block;">' + (i18n.loadingPayment || 'Loading payment options...') + '</small></div>').slideDown(200);
            setTimeout(function() {
                showCryptoPayment(size, price, weight, name, email, phoneDigits || phone);
            }, 300);

            log('→ Crypto payment triggered directly');
        });

        // Back button removed — sizes always visible, no step navigation needed.

        // Weight slider — update display only (price is per gabaryt, no AJAX needed).
        $(document).on('input', '#etyk-weight', function() {
            var val = parseFloat($(this).val()).toFixed(1);
            $('#etyk-weight-display').text(val + ' kg');
            log('Weight slider: ' + val + ' kg');
        });

        // (Crypto selection is now handled by showCryptoPayment — triggered directly after size selection above.)

        // Copy address.
        $(document).on('click', '.etyk-copy-btn', function() {
            var text = $(this).data('copy');
            var $btn = $(this);
            if (navigator.clipboard) {
                navigator.clipboard.writeText(text).then(function() {
                    $btn.text(i18n.copied || 'Copied!');
                    setTimeout(function() { $btn.text(i18n.copy || 'Copy'); }, 2000);
                });
            }
        });

        // Print.
        $(document).on('click', '.etyk-print-btn', function() {
            var url = $(this).data('url');
            var iframe = document.createElement('iframe');
            iframe.style.display = 'none';
            iframe.src = url;
            document.body.appendChild(iframe);
            iframe.onload = function() {
                iframe.contentWindow.print();
            };
        });

        // Inline setup — toggle form visibility.
        $(document).on('click', '.etyk-inline-toggle', function(e) {
            e.preventDefault();
            var target = $(this).data('target');
            $('#' + target).slideToggle(200);
        });

        // Inline setup — save options via AJAX.
        $(document).on('click', '.etyk-inline-save', function() {
            var $btn = $(this);
            var $form = $btn.closest('.etyk-inline-form');
            var $status = $form.find('.etyk-inline-status');
            var options = {};

            $form.find('.etyk-inline-field').each(function() {
                var key = $(this).data('option');
                var val = $(this).val().trim();
                if (key && val) {
                    options[key] = val;
                }
            });

            if (!Object.keys(options).length) {
                $status.text('Fill in at least one field').css('color', '#d63638');
                return;
            }

            $btn.prop('disabled', true);
            $status.text('Saving...').css('color', '#666');

            $.post(cfg.ajaxUrl, {
                action: 'parcselect_label_save_inline',
                nonce: cfg.nonce,
                options: JSON.stringify(options)
            }, function(res) {
                if (res.success) {
                    $status.text('Saved! Refreshing...').css('color', '#00a32a');
                    setTimeout(function() { location.reload(); }, 500);
                } else {
                    $status.text('Error: ' + (res.data || 'unknown')).css('color', '#d63638');
                    $btn.prop('disabled', false);
                }
            }).fail(function() {
                $status.text('Request failed').css('color', '#d63638');
                $btn.prop('disabled', false);
            });
        });

        // Reset (try again after error/expired).
        $(document).on('click', '#etyk-reset-btn', function() {
            var $btn = $(this);
            $btn.prop('disabled', true).text('...');
            $.post(cfg.ajaxUrl, {
                action:   'parcselect_label_reset_session',
                nonce:    cfg.nonce,
                order_id: orderId
            }, function() {
                location.reload();
            }).fail(function() {
                location.reload();
            });
        });

        // INTERNAL_PAYMENT — manual confirm for testing.
        $(document).on('click', '#etyk-internal-confirm', function() {
            var $btn = $(this);
            if (!confirm('INTERNAL_PAYMENT: Confirm payment manually and generate label?')) return;
            $btn.prop('disabled', true).text('Processing...');
            $.post(cfg.ajaxUrl, {
                action:   'parcselect_label_internal_confirm',
                nonce:    cfg.nonce,
                order_id: orderId
            }, function(res) {
                if (res.success) {
                    if (res.data.status === 'completed') {
                        location.reload();
                    } else {
                        showError(res.data.message || 'Generation failed');
                    }
                } else {
                    alert(res.data || 'Error');
                    $btn.prop('disabled', false).text('INTERNAL_PAYMENT: Confirm');
                }
            }).fail(function() {
                alert('Request failed');
                $btn.prop('disabled', false).text('INTERNAL_PAYMENT: Confirm');
            });
        });
    }

    // =========================================================================
    // STEP 3: CRYPTO PAYMENT SELECTION
    // =========================================================================
    function showCryptoPayment(size, pricePLN, weight, recvName, recvEmail, recvPhone) {
        log('showCryptoPayment() — Step 1: creating session...');

        var $area = $('#etyk-step-payment');
        $area.html('<div style="text-align:center;padding:20px"><span class="spinner is-active" style="float:none"></span><br><small>Preparing payment...</small></div>').slideDown(200);

        // FIRST: create session on server (saves size, weight, receiver edits, price, status=awaiting_payment).
        $.post(cfg.ajaxUrl, {
            action:     'parcselect_label_create_session',
            nonce:      cfg.nonce,
            order_id:   orderId,
            size:       size,
            weight:     weight,
            recv_name:  recvName,
            recv_email: recvEmail,
            recv_phone: recvPhone
        }, function(sessionRes) {
            log('create_session response:', JSON.stringify(sessionRes));
            if (!sessionRes.success) {
                $area.html('<div style="padding:12px;background:#fef2f2;border:1px solid #fecaca;border-radius:8px;color:#991b1b;font-weight:600">' + esc(sessionRes.data || 'Session creation failed') + '</div>');
                return;
            }

            var sessionPricePLN = sessionRes.data.price_pln || pricePLN;
            log('Session created OK. Price locked: ' + sessionPricePLN + ' PLN. Now loading crypto options...');

            // THEN: get crypto options with locked price.
            loadCryptoOptions(sessionPricePLN);

        }).fail(function(xhr, st, err) {
            warn('create_session FAIL:', err);
            $area.html('<div style="padding:12px;color:red">Session creation failed. Please try again.</div>');
        });

        function loadCryptoOptions(lockedPrice) {
        $.post(cfg.ajaxUrl, {
            action:    'parcselect_label_get_crypto_options',
            nonce:     cfg.nonce,
            order_id:  orderId,
            size:      size,
            weight:    weight,
            price_pln: lockedPrice
        }, function(res) {
            log('crypto_options response:', JSON.stringify(res).substring(0, 300));

            if (!res.success) {
                var errMsg = (typeof res.data === 'string') ? res.data : (res.data && res.data.message ? res.data.message : 'Payment options unavailable');
                warn('crypto_options FAILED:', errMsg);
                $area.html('<div style="padding:12px;background:#fef2f2;border:1px solid #fecaca;border-radius:8px;text-align:center"><p style="margin:0;color:#991b1b;font-weight:600">' + esc(errMsg) + '</p><p style="margin:4px 0 0;font-size:11px;color:#666">Go to WooCommerce → Settings → Payments → PS CryptoPay</p></div>');
                return;
            }

            var d = res.data;
            // Support both old format (html) and new format (selector_html + cards)
            var selectorHtml = d.selector_html || d.html || '';
            var cards = d.cards || {};
            var coinsData = d.coins_data || [];

            if (!selectorHtml && coinsData.length === 0) {
                $area.html('<div style="padding:12px;background:#fef2f2;border:1px solid #fecaca;border-radius:8px;text-align:center"><p style="margin:0;color:#991b1b">No crypto wallets configured.</p></div>');
                return;
            }

            var html = selectorHtml;
            html += '<div id="etyk-card-area" style="margin-top:12px"></div>';
            html += '<button type="button" id="etyk-back-to-receiver" class="button" style="margin-top:10px">\u2190 ' + esc(i18n.back || 'Back') + '</button>';
            $area.html(html);

            // Store data for QR generation.
            $area.data('wallets', d.wallets || {});
            $area.data('rates', d.rates || {});
            $area.data('cards', cards);

            log('Crypto selector rendered: ' + coinsData.length + ' coins');

                // Bind coin selection → render NATIVE PS CryptoPay payment UI.
                $area.on('change', 'input[name="parcselect_crypto"], input[name="pscp_crypto"]', function() {
                    var coin   = $(this).val();
                    var wallets = $area.data('wallets') || {};
                    var rates  = $area.data('rates') || {};
                    var wallet = $(this).data('wallet') || wallets[coin] || '';
                    var amount = $(this).data('amount') || rates[coin] || '';

                    if (!wallet) {
                        warn('No wallet for ' + coin);
                        return;
                    }

                    log('Coin selected: ' + coin.toUpperCase() + ' — loading native PS CryptoPay UI...');
                    $('#etyk-card-area').html('<div style="text-align:center;padding:20px"><span class="spinner is-active" style="float:none"></span></div>');

                    // Get conversion details for rate info.
                    var coinsData = d.coins_data || [];
                    var coinInfo = null;
                    for (var i = 0; i < coinsData.length; i++) {
                        if (coinsData[i].symbol === coin) { coinInfo = coinsData[i]; break; }
                    }

                    // Call render_payment — saves _pscp_* meta + renders thankyou_page() HTML.
                    $.post(cfg.ajaxUrl, {
                        action:       'parcselect_label_render_payment',
                        nonce:        cfg.nonce,
                        order_id:     orderId,
                        coin:         coin,
                        wallet:       wallet,
                        amount:       amount,
                        rate:         coinInfo ? coinInfo.rate : 0,
                        sources:      coinInfo ? coinInfo.sources : 0,
                        source_names: coinInfo ? coinInfo.source_names : '',
                        price_fiat:   d.price_fiat || 13.99,
                        currency:     d.currency || 'PLN'
                    }, function(payRes) {
                        log('render_payment response:', payRes.success ? 'OK' : 'FAIL');
                        if (payRes.success && payRes.data.html) {
                            // Insert NATIVE PS CryptoPay payment UI — identical to checkout.
                            $('#etyk-card-area').html(payRes.data.html);
                            log('=== NATIVE PS CRYPTOPAY UI RENDERED === Coin: ' + coin.toUpperCase());

                            // Start polling for payment confirmation.
                            startLabelPaymentPolling();
                        } else {
                            $('#etyk-card-area').html('<div style="padding:12px;color:#991b1b;background:#fef2f2;border-radius:8px">' + esc(payRes.data || 'Payment UI failed to load') + '</div>');
                        }
                    }).fail(function() {
                        $('#etyk-card-area').html('<div style="padding:12px;color:red">Failed to load payment UI.</div>');
                    });
                });

                function startLabelPaymentPolling() {
                    if (pollTimer) clearInterval(pollTimer);
                    var pollCount = 0;
                    var maxPolls = 60; // 60 × 10s = 10 min max for payment.
                    var genCount = 0;
                    var maxGen = 60;   // 60 × 5s = 5 min max for label generation.
                    log('Starting payment polling (every 10s, max ' + maxPolls + ')...');

                    pollTimer = setInterval(function() {
                        pollCount++;
                        if (pollCount > maxPolls) {
                            clearInterval(pollTimer);
                            warn('Payment polling timeout (' + maxPolls + ' polls)');
                            $('#etyk-card-area').html(
                                '<div class="etyk-status-card etyk-status-card--warning">' +
                                '<strong>' + (i18n.expired || 'EXPIRED') + '</strong> — ' +
                                (i18n.error || 'Payment not detected in time. Refresh to check again.') +
                                '</div>'
                            );
                            return;
                        }

                        $.post(cfg.ajaxUrl, {
                            action:   'parcselect_label_check_payment',
                            nonce:    cfg.nonce,
                            order_id: orderId
                        }, function(res) {
                            if (!res.success) return;
                            var status = res.data.status;
                            log('Poll #' + pollCount + ': status=' + status);

                            if (status === 'paid' || status === 'generating') {
                                clearInterval(pollTimer);
                                $('#etyk-card-area').html(
                                    '<div class="etyk-status-card etyk-status-card--success">' +
                                    '<strong>' + (i18n.paymentOk || 'Payment confirmed!') + '</strong>' +
                                    '<span class="etyk-spinner"></span> ' +
                                    (i18n.generating || 'Generating label...') +
                                    '</div>'
                                );
                                log('=== PAYMENT CONFIRMED === Generating label...');

                                // Poll for label completion (5s, max 5 min).
                                pollTimer = setInterval(function() {
                                    genCount++;
                                    if (genCount > maxGen) {
                                        clearInterval(pollTimer);
                                        warn('Label generation timeout');
                                        location.reload();
                                        return;
                                    }
                                    $.post(cfg.ajaxUrl, {
                                        action:   'parcselect_label_check_payment',
                                        nonce:    cfg.nonce,
                                        order_id: orderId
                                    }, function(r2) {
                                        if (r2.success && r2.data.status === 'completed') {
                                            clearInterval(pollTimer);
                                            log('=== LABEL READY === Tracking: ' + (r2.data.tracking_number || ''));
                                            location.reload();
                                        } else if (r2.success && r2.data.status === 'error') {
                                            clearInterval(pollTimer);
                                            warn('Label generation error:', r2.data.error);
                                            location.reload();
                                        }
                                    });
                                }, 5000);
                            }
                            if (status === 'completed') {
                                clearInterval(pollTimer);
                                log('=== LABEL READY (instant) ===');
                                location.reload();
                            }
                            if (status === 'error') {
                                clearInterval(pollTimer);
                                warn('Error during generation');
                                location.reload();
                            }
                        });
                    }, 10000);
                }

                // Back to receiver.
                $area.on('click', '#etyk-back-to-receiver', function() {
                    log('← Back to Step 2');
                    $area.slideUp(200);
                    $('#etyk-step-receiver').slideDown(200);
                });

        }).fail(function(xhr, status, err) {
            warn('crypto_options FAIL:', err);
            $area.html('<div class="etyk-status-card etyk-status-card--error"><strong>Failed to load payment options.</strong> Please try again.</div>');
        });
        } // end loadCryptoOptions
    } // end showCryptoPayment

    // =========================================================================
    // FETCH PRICE (legacy — kept for backward compat)
    // =========================================================================
    function fetchPrice() {
        var size   = $('input[name="parcselect_size"]:checked').val() || 'A';
        var weight = parseFloat($('#etyk-weight').val()) || 1.0;
        log('fetchPrice() size=' + size + ' weight=' + weight);

        $('#etyk-price-row').show();
        $('#etyk-price').text(i18n.fetchingPrice || 'Calculating...');
        $('#etyk-price-sol').text('');
        $('#etyk-submit').prop('disabled', true);

        log('AJAX POST to', cfg.ajaxUrl, 'action=parcselect_label_get_price');
        $.post(cfg.ajaxUrl, {
            action: 'parcselect_label_get_price',
            nonce:  cfg.nonce,
            size:   size,
            weight: weight
        }, function(res) {
            log('fetchPrice response:', JSON.stringify(res));
            if (res.success) {
                var d = res.data;
                $('#etyk-price').text(d.price_display);
                if (d.sol_amount && d.sol_amount !== '?') {
                    $('#etyk-price-sol').text('(\u2248 ' + d.sol_amount + ' SOL)');
                }
                $('#etyk-submit').prop('disabled', false);
                log('Price loaded: ' + d.price_display + ' — submit ENABLED');
            } else {
                warn('fetchPrice FAILED:', res.data);
                $('#etyk-price').text(i18n.error || 'Error');
            }
        }).fail(function(xhr, status, err) {
            warn('fetchPrice AJAX FAIL:', status, err, xhr.responseText);
            $('#etyk-price').text(i18n.error || 'Error');
        });
    }

    // =========================================================================
    // CREATE SESSION — show QR code
    // =========================================================================
    function createSession() {
        var size   = $('input[name="parcselect_size"]:checked').val() || 'A';
        var weight = parseFloat($('#etyk-weight').val()) || 1.0;
        log('createSession() size=' + size + ' weight=' + weight + ' orderId=' + orderId);

        // Show generating state immediately.
        $('#etyk-submit').prop('disabled', true).text(i18n.generating || 'Generating label...');
        $('#etyk-options').append('<div class="etyk-spinner-inline" style="text-align:center;padding:12px 0"><span class="spinner is-active" style="float:none;margin:0 auto"></span><br><small>' + esc(i18n.generating || 'Generating shipping label...') + '</small></div>');

        log('AJAX POST to', cfg.ajaxUrl, 'action=parcselect_label_create_session');
        $.post(cfg.ajaxUrl, {
            action:   'parcselect_label_create_session',
            nonce:    cfg.nonce,
            order_id: orderId,
            size:     size,
            weight:   weight
        }, function(res) {
            log('createSession response:', JSON.stringify(res));
            if (res.success) {
                log('SUCCESS! status=' + (res.data.status || 'unknown'));
                if (res.data.status === 'completed') {
                    log('Label completed! Tracking: ' + (res.data.tracking_number || 'N/A') + ' — reloading page...');
                    location.reload();
                } else if (res.data.qr_uri) {
                    log('Legacy Solana flow — rendering QR');
                    renderPaymentQR(res.data);
                } else {
                    log('Unknown success state — reloading');
                    location.reload();
                }
            } else {
                warn('createSession FAILED:', res.data);
                $('.etyk-spinner-inline').remove();
                alert(res.data || i18n.error || 'Label generation failed');
                $('#etyk-submit').prop('disabled', false).text('Generate label');
            }
        }).fail(function(xhr, status, err) {
            warn('createSession AJAX FAIL:', status, err, xhr.responseText);
            $('.etyk-spinner-inline').remove();
            alert(i18n.error || 'Connection error');
            $('#etyk-submit').prop('disabled', false).text('Generate label');
        });
    }

    // =========================================================================
    // RENDER QR CODE
    // =========================================================================
    function renderPaymentQR(data) {
        var $info = $wrap.find('.etyk-info').clone();
        $wrap.empty().append($info);

        var timeout = data.timeout_remaining || data.timeout || 1800;
        var mins = Math.floor(timeout / 60);
        var secs = timeout % 60;
        var timerStr = String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0');

        var html = '<div class="etyk-state etyk-payment">';
        html += '<h3 style="margin:12px 0 8px;">' + esc(i18n.payLabel || 'Pay for label') + ' \u2014 ' + esc(data.price_display) + '</h3>';
        html += '<div id="etyk-qr" style="margin:12px auto;width:180px;height:180px;"></div>';
        html += '<div class="etyk-pay-details">';
        html += '<p><strong>' + esc(i18n.amount || 'Amount:') + '</strong> ' + esc(data.sol_amount) + ' SOL</p>';
        html += '<p><strong>' + esc(i18n.address || 'Address:') + '</strong> <code style="font-size:11px;word-break:break-all;">' + esc(data.sol_address) + '</code> ';
        html += '<button type="button" class="button button-small etyk-copy-btn" data-copy="' + esc(data.sol_address) + '">' + esc(i18n.copy || 'Copy') + '</button></p>';
        html += '<p class="etyk-countdown"><strong>' + esc(i18n.timeLeft || 'Time left:') + '</strong> <span id="etyk-timer">' + timerStr + '</span></p>';
        html += '</div>';
        html += '<div class="etyk-status-indicator">';
        html += '<span class="etyk-pulse"></span> ' + esc(i18n.awaitingPayment || 'Waiting for payment...');
        html += '</div>';
        // INTERNAL_PAYMENT button — manual confirm for testing.
        html += '<div style="margin-top:12px;padding-top:12px;border-top:1px dashed #ddd;text-align:center;">';
        html += '<button type="button" id="etyk-internal-confirm" class="button" style="background:#f0f6fc;border-color:#2271b1;color:#2271b1;">INTERNAL_PAYMENT: Confirm</button>';
        html += '<p style="font-size:11px;color:#999;margin-top:4px;">Test mode — skips blockchain verification</p>';
        html += '</div>';
        html += '</div>';

        $wrap.append(html);

        // Generate QR code.
        if (typeof QRCode !== 'undefined' && data.qr_uri) {
            new QRCode(document.getElementById('etyk-qr'), {
                text: data.qr_uri,
                width: 180,
                height: 180,
                colorDark: '#1e293b',
                colorLight: '#ffffff',
                correctLevel: QRCode.CorrectLevel.H
            });
        }

        startCountdown(timeout);
        startPolling();
    }

    // =========================================================================
    // RESUME PAYMENT (page reload while awaiting)
    // =========================================================================
    function resumePayment() {
        $.post(cfg.ajaxUrl, {
            action:   'parcselect_label_check_status',
            nonce:    cfg.nonce,
            order_id: orderId
        }, function(res) {
            if (!res.success) return;
            var d = res.data;

            if (d.status === 'completed') {
                showCompleted(d);
            } else if (d.status === 'paid' || d.status === 'generating') {
                showGenerating();
                startPolling();
            } else if (d.status === 'awaiting_payment' && d.qr_uri) {
                // Full resume with QR code from persisted meta.
                renderPaymentQR(d);
            } else if (d.status === 'error') {
                showError(d.error_message);
            } else {
                // Fallback — just show waiting indicator + polling.
                var $area = $wrap.find('#etyk-payment-area');
                if ($area.length) {
                    $area.html(
                        '<div class="etyk-status-indicator">' +
                        '<span class="etyk-pulse"></span> ' + esc(i18n.awaitingPayment || 'Waiting for payment...') +
                        '</div>'
                    );
                }
                startPolling();
            }
        });
    }

    // =========================================================================
    // RESUME ERROR (page reload after error)
    // =========================================================================
    function resumeError() {
        $.post(cfg.ajaxUrl, {
            action:   'parcselect_label_check_status',
            nonce:    cfg.nonce,
            order_id: orderId
        }, function(res) {
            if (!res.success) return;
            showError(res.data.error_message || 'Unknown error');
        });
    }

    // =========================================================================
    // SHOW GENERATING STATE
    // =========================================================================
    function showGenerating() {
        var $area = $wrap.find('.etyk-payment, #etyk-payment-area');
        if ($area.length) {
            $area.html(
                '<div class="etyk-status-indicator etyk-generating">' +
                '<span class="etyk-spinner"></span> ' + esc(i18n.generating || 'Generating label...') +
                '</div>'
            );
        }
    }

    // =========================================================================
    // SHOW ERROR STATE
    // =========================================================================
    function showError(message) {
        stopPolling();
        stopCountdown();

        var $info = $wrap.find('.etyk-info').clone();
        $wrap.empty().append($info);

        var html = '<div class="etyk-state etyk-error" style="text-align:center;padding:16px;">';
        html += '<div style="color:#d63638;font-weight:700;font-size:14px;margin-bottom:8px;">Error</div>';
        html += '<p style="color:#666;font-size:13px;">' + esc(message || 'Something went wrong') + '</p>';
        html += '<button type="button" id="etyk-reset-btn" class="button">Try again</button>';
        html += '</div>';

        $wrap.append(html);
    }

    // =========================================================================
    // SHOW COMPLETED STATE
    // =========================================================================
    function showCompleted(data) {
        stopPolling();
        stopCountdown();

        var $info = $wrap.find('.etyk-info').clone();
        $wrap.empty().append($info);

        var html = '<div class="etyk-state etyk-completed">';
        html += '<div class="etyk-success-badge">' + esc(i18n.completed || 'Label ready!') + '</div>';
        html += '<table class="etyk-details">';
        if (data.tracking_number) {
            html += '<tr><td>' + esc(i18n.trackingNumber || 'Tracking:') + '</td><td><strong>' + esc(data.tracking_number) + '</strong></td></tr>';
        }
        if (data.size) {
            html += '<tr><td>Size:</td><td>' + esc(data.size) + ' | ' + esc(data.weight) + ' kg</td></tr>';
        }
        if (data.price_display) {
            html += '<tr><td>Price:</td><td>' + esc(data.price_display) + ' (' + esc(data.sol_amount) + ' SOL)</td></tr>';
        }
        if (data.txid) {
            var short = data.txid.length > 20 ? data.txid.substr(0,12) + '...' + data.txid.substr(-8) : data.txid;
            html += '<tr><td>TX:</td><td><code style="font-size:11px;">' + esc(short) + '</code></td></tr>';
        }
        html += '</table>';
        if (data.label_url) {
            html += '<div class="etyk-actions">';
            html += '<a href="' + esc(data.label_url) + '" class="button button-primary" target="_blank">' + esc(i18n.downloadPdf || 'Download label (PDF)') + '</a> ';
            html += '<button type="button" class="button etyk-print-btn" data-url="' + esc(data.label_url) + '">' + esc(i18n.print || 'Print') + '</button>';
            html += '</div>';
        }
        html += '</div>';

        $wrap.append(html);
    }

    // =========================================================================
    // POLLING
    // =========================================================================
    function startPolling() {
        stopPolling();
        pollTimer = setInterval(function() {
            $.post(cfg.ajaxUrl, {
                action:   'parcselect_label_check_status',
                nonce:    cfg.nonce,
                order_id: orderId
            }, function(res) {
                if (!res.success) return;
                var d = res.data;

                if (d.status === 'paid' || d.status === 'generating') {
                    showGenerating();
                } else if (d.status === 'completed') {
                    showCompleted(d);
                } else if (d.status === 'error') {
                    showError(d.error_message);
                }
            });
        }, 10000);
    }

    function stopPolling() {
        if (pollTimer) {
            clearInterval(pollTimer);
            pollTimer = null;
        }
    }

    // =========================================================================
    // COUNTDOWN
    // =========================================================================
    function startCountdown(seconds) {
        stopCountdown();
        var rem = seconds;
        var $el = null;

        function tick() {
            $el = $('#etyk-timer');
            if (!$el.length) return;
            if (rem <= 0) {
                $el.text(i18n.expired || 'EXPIRED');
                return;
            }
            rem--;
            var m = Math.floor(rem / 60);
            var s = rem % 60;
            $el.text(String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0'));
            countdownTimer = setTimeout(tick, 1000);
        }

        tick();
    }

    function stopCountdown() {
        if (countdownTimer) {
            clearTimeout(countdownTimer);
            countdownTimer = null;
        }
    }

    // =========================================================================
    // UTILITY
    // =========================================================================
    function esc(str) {
        if (!str && str !== 0) return '';
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(String(str)));
        return div.innerHTML;
    }

})(jQuery);
