/**
 * Consolety Guest Posts JavaScript
 *
 * @package Consolety
 * @since 1.0.0
 */

/* global jQuery, consoletyGuestPosts, wp, tinymce, ConsoletyPartnerCards */

(function($) {
    'use strict';

    // CRITICAL: Check if localized data exists before proceeding
    // If this object is missing, the script was loaded incorrectly
    if (typeof consoletyGuestPosts === 'undefined') {
        console.error('Consolety: consoletyGuestPosts not defined. Script may not be properly enqueued.');
        // Show user-friendly error
        $(document).ready(function() {
            $('.vp-loading').hide();
            $('.vp-empty-state').show().find('h3').text('Loading error - please refresh the page');
        });
        return; // Exit early - don't crash the rest of the page
    }

    const GP = {
        nonce: consoletyGuestPosts.nonce,
        ajaxUrl: consoletyGuestPosts.ajaxUrl,
        i18n: consoletyGuestPosts.i18n || {},
        data: { my_submissions: [], pending_review: [], received: [] }
    };

    /**
     * Map error codes to user-friendly messages
     */
    function mapErrorCode(code, fallbackMessage) {
        const messages = {
            'UNAUTHORIZED': 'Session expired. Please refresh the page.',
            'UNAUTHENTICATED': 'Connection expired. Please reconnect via Dashboard.',
            'VALIDATION_ERROR': fallbackMessage || 'Please check your input.',
            'INVALID_INPUT': fallbackMessage || 'Invalid input provided.',
            'INSUFFICIENT_POINTS': 'Not enough points for this action.',
            'INSUFFICIENT_CREDITS': fallbackMessage || 'Not enough points to submit this guest post.',
            'CONNECTION_REQUIRED': 'You need to connect with this site first. Go to the Network tab to send a connection request.',
            'HOST_CLOSED': 'This site is not accepting guest posts at this time.',
            'HOST_NOT_FOUND': 'This partner site could not be found.',
            'PARTNER_INACTIVE': 'This partner is no longer active in the network.',
            'API_ERROR': fallbackMessage || 'Server error. Please try again.',
            'SERVER_ERROR': fallbackMessage || 'Server error. Please try again.',
            'REQUEST_FAILED': 'Network error. Please check your connection.',
            'WP_ERROR': fallbackMessage || 'WordPress error occurred.',
            'FETCH_FAILED': 'Could not fetch data from server.'
        };
        return messages[code] || fallbackMessage || 'An unexpected error occurred.';
    }

    /**
     * Get user-friendly error message from XHR object
     */
    function getXhrErrorMessage(xhr) {
        const httpStatus = xhr.status;

        // Try to parse JSON response
        try {
            const json = JSON.parse(xhr.responseText);
            if (json.data && json.data.code) {
                return mapErrorCode(json.data.code, json.data.message);
            }
            if (json.data && json.data.message) {
                return json.data.message;
            }
        } catch (e) {
            // Not JSON, continue with HTTP status
        }

        // Map HTTP status codes
        if (httpStatus === 401) return 'Connection expired. Please reconnect via Dashboard.';
        if (httpStatus === 403) return 'Session expired. Please refresh the page.';
        if (httpStatus === 500) return 'Server error. Please try again later.';
        if (httpStatus === 0) return 'Network error. Please check your connection.';

        return 'Connection error. Please try again.';
    }

    /**
     * Handle AJAX errors with smart diagnostics
     * Detects nonce failures (403 + "-1" response) and auto-reloads (once only)
     */
    function handleAjaxError(xhr, status, error, context) {
        const responseText = (xhr.responseText || '').trim();
        const httpStatus = xhr.status;

        console.error('[VP Guest Posts] AJAX Error:', {
            context: context,
            httpStatus: httpStatus,
            status: status,
            error: error,
            responseText: responseText.substring(0, 200)
        });

        // Strict nonce failure detection: WP returns exactly "-1" or "0" with 403
        const isNonceFailure = httpStatus === 403 && (responseText === '-1' || responseText === '0');

        if (isNonceFailure) {
            // Prevent reload loops: only reload once per page session
            const reloadKey = 'vp_nonce_reload_' + window.location.href;
            if (sessionStorage.getItem(reloadKey)) {
                console.error('[VP Guest Posts] Nonce failure persists after reload. Manual refresh needed.');
                showNotice(GP.i18n.sessionExpiredManual || 'Session expired. Please refresh the page manually.', 'error');
                return true;
            }

            console.warn('[VP Guest Posts] Nonce/session failure detected. Reloading page (once)...');
            sessionStorage.setItem(reloadKey, '1');
            showNotice(GP.i18n.sessionExpired || 'Session expired. Reloading page...', 'warning');
            setTimeout(function() {
                window.location.reload();
            }, 1500);
            return true; // Handled
        }

        // Clear reload guard on non-nonce errors
        sessionStorage.removeItem('vp_nonce_reload_' + window.location.href);

        return false;
    }

    /**
     * Escape HTML entities for safe text content
     */
    function escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    /**
     * Extract links from HTML content using DOM parsing.
     * Handles bold, italic, span-wrapped anchor text that regex cannot match.
     * The temporary div is never attached to the DOM (safe for parsing).
     */
    function extractLinksFromHtml(html) {
        if (!html) return [];
        var container = document.createElement('div');
        container.innerHTML = html; // Safe: container is never attached to DOM
        var anchors = container.querySelectorAll('a[href]');
        var links = [];
        for (var i = 0; i < anchors.length; i++) {
            var href = anchors[i].getAttribute('href');
            if (href && /^https?:\/\//i.test(href)) {
                links.push({
                    url: href,
                    anchor: anchors[i].textContent.trim() || href
                });
            }
        }
        return links;
    }

    /**
     * Show a temporary notice to the user
     * SECURITY: Always escapes message to prevent XSS
     */
    function showNotice(message, type) {
        const noticeClass = type === 'error' ? 'notice-error' : (type === 'success' ? 'notice-success' : 'notice-warning');
        const $notice = $('<div class="notice ' + noticeClass + ' is-dismissible vp-ajax-notice"><p>' + escapeHtml(message) + '</p></div>');

        // Remove any existing VP notices
        $('.vp-ajax-notice').remove();

        // If a modal is open, show inside the modal so it's not hidden behind the overlay
        var $modalNotice = $('.vp-gp-modal:visible .vp-modal-notice-area');
        if ($modalNotice.length) {
            $modalNotice.empty().append($notice).show();
            $notice[0].scrollIntoView({ behavior: 'smooth', block: 'start' });
        } else {
            // Insert at top of content area
            $('.vp-dashboard .vp-header').after($notice);
        }

        // Auto-dismiss after 5 seconds (unless it's a reload notice)
        if (type !== 'warning') {
            setTimeout(function() {
                $notice.fadeOut(function() { $(this).remove(); });
            }, 5000);
        }
    }

    // Tab Switching
    $('.vp-primary-tab').on('click', function() {
        const tab = $(this).data('tab');
        $('.vp-primary-tab').removeClass('active');
        $(this).addClass('active');
        $('.vp-tab-panel').removeClass('active');
        $('#tab-' + tab).addClass('active');
    });

    // Filters
    $('#filter-status').on('change', renderSubmissions);
    $('#filter-search').on('input', debounce(renderSubmissions, 300));
    $('#btn-clear-filters').on('click', function() {
        $('#filter-status').val('');
        $('#filter-search').val('');
        renderSubmissions();
    });

    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func(...args), wait);
        };
    }

    // Load Data
    function loadGuestPosts() {
        $('#submissions-loading, #pending-loading, #published-loading').show();
        $('#submissions-empty, #pending-empty, #published-empty').hide();

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_list', nonce: GP.nonce },
            success: function(response) {
                if (response.success) {
                    const data = response.data?.data || response.data || {};
                    GP.data = {
                        my_submissions: data.my_submissions || [],
                        pending_review: data.pending_review || [],
                        received: data.received || []
                    };
                    renderAll();
                } else {
                    showError('submissions');
                    showError('pending');
                    showError('published');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'loadGuestPosts')) {
                    showError('submissions');
                    showError('pending');
                    showError('published');
                }
            }
        });
    }

    function showError(type) {
        $('#' + type + '-loading').hide();
        $('#' + type + '-empty').show().find('h3').text('Failed to load');
    }

    function loadPartners(callback) {
        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_partners', nonce: GP.nonce },
            success: function(response) {
                if (response.success && response.data) {
                    const partners = response.data || [];
                    if (partners.length > 0) {
                        if (typeof ConsoletyPartnerCards !== 'undefined') {
                            ConsoletyPartnerCards.init(partners);
                        }
                    } else {
                        $('#partner-selection-wrap').hide();
                        $('#partner-empty').show();
                    }
                } else {
                    // API returned error response
                    console.error('Consolety: Failed to load partners', response);
                    $('#partner-selection-wrap').hide();
                    const errorMsg = mapErrorCode(response.data?.code, response.data?.message || 'Failed to load partners');
                    $('#partner-empty').show().find('h3').text(errorMsg);
                }
                if (callback) callback();
            },
            error: function(xhr, status, error) {
                // AJAX request failed (network error, 403, 500, etc.)
                if (handleAjaxError(xhr, status, error, 'loadPartners')) {
                    return; // Nonce failure - page will reload
                }
                $('#partner-selection-wrap').hide();
                $('#partner-empty').show().find('h3').text(getXhrErrorMessage(xhr));
                // CRITICAL: Still call callback so modal opens (user can retry)
                if (callback) callback();
            }
        });
    }

    // Render Functions
    function renderAll() {
        renderSubmissions();
        renderPending();
        renderPublished();
        updateCounts();
    }

    function renderSubmissions() {
        const $tbody = $('#submissions-tbody');
        const $loading = $('#submissions-loading');
        const $empty = $('#submissions-empty');

        const filterStatus = $('#filter-status').val();
        const filterSearch = $('#filter-search').val().toLowerCase();

        let posts = GP.data.my_submissions || [];

        if (filterStatus) posts = posts.filter(p => p.status === filterStatus);
        if (filterSearch) {
            posts = posts.filter(p =>
                (p.title && p.title.toLowerCase().includes(filterSearch)) ||
                (p.host?.domain && p.host.domain.toLowerCase().includes(filterSearch))
            );
        }

        $loading.hide();

        if (posts.length === 0) {
            const noResults = filterStatus || filterSearch ? 'No orders match your filters' : 'No orders yet';
            $empty.show().find('h3').text(noResults);
            $tbody.html('');
            return;
        }

        $empty.hide();
        let html = '';
        posts.forEach(function(p) {
            const isTerminated = ['withdrawn', 'rejected', 'expired'].includes(p.status);
            const rowClass = isTerminated ? 'class="vp-row-terminated"' : '';
            const orderId = 'GP-' + p.id;
            html += '<tr ' + rowClass + ' data-credits="' + (p.credits_reserved || 0) + '">' +
                '<td class="vp-order-id"><code>' + orderId + '</code></td>' +
                '<td><strong>' + escapeHtml(p.title) + '</strong>' + (p.feedback ? '<br><small class="vp-feedback"><span class="dashicons dashicons-edit" style="margin-right:8px;"></span>Has feedback</small>' : '') + '</td>' +
                '<td>' + escapeHtml(p.host?.domain || 'Unknown') + '</td>' +
                '<td>' + getStatusBadge(p) + '</td>' +
                '<td>' + formatDate(p.submitted_at) + '</td>' +
                '<td>' + getSubmissionActions(p) + '</td>' +
                '</tr>';
        });
        $tbody.html(html);
    }

    function getStatusBadge(p) {
        if (p.status === 'approved' && p.host?.domain) {
            const domain = p.host.domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
            return '<span class="vp-status-badge vp-status-approved"><span class="dashicons dashicons-yes-alt" style="color:#10b981;margin-right:6px;"></span>Live on ' + escapeHtml(domain) + '</span>';
        }

        const badges = {
            'draft': { class: 'vp-status-draft', icon: '<span class="dashicons dashicons-edit"></span>', label: 'Draft' },
            'pending_review': { class: 'vp-status-pending', icon: '<span class="dashicons dashicons-clock"></span>', label: 'Pending Review' },
            'revision_requested': { class: 'vp-status-revision', icon: '<span class="dashicons dashicons-editor-help"></span>', label: 'Needs Revision' },
            'approved': { class: 'vp-status-approved', icon: '<span class="dashicons dashicons-yes-alt"></span>', label: 'Published' },
            'rejected': { class: 'vp-status-rejected', icon: '<span class="dashicons dashicons-no"></span>', label: 'Rejected' },
            'withdrawn': { class: 'vp-status-withdrawn', icon: '<span class="dashicons dashicons-dismiss"></span>', label: 'Withdrawn' }
        };
        const badge = badges[p.status] || { class: 'vp-status-draft', icon: '<span class="dashicons dashicons-edit"></span>', label: p.status };
        return '<span class="vp-status-badge ' + badge.class + '">' + badge.icon + ' ' + badge.label + '</span>';
    }

    function renderPending() {
        const $tbody = $('#pending-tbody');
        const $loading = $('#pending-loading');
        const $empty = $('#pending-empty');

        const allPending = GP.data.pending_review || [];
        const readyToReview = allPending.filter(p => p.status === 'pending_review');

        $loading.hide();

        if (allPending.length === 0) {
            $empty.show();
            $tbody.html('');
            return;
        }

        $empty.hide();

        let html = '';

        // Posts ready for review (pending_review)
        readyToReview.forEach(function(p) {
            html += '<tr>' +
                '<td><strong>' + escapeHtml(p.title) + '</strong></td>' +
                '<td>' + escapeHtml(p.submitter?.domain || 'Unknown') + '</td>' +
                '<td>' + p.word_count + '</td>' +
                '<td>' + formatDate(p.submitted_at) + '</td>' +
                '<td><button class="vp-btn vp-btn-sm vp-btn-primary btn-review" data-id="' + p.id + '">Review</button></td>' +
                '</tr>';
        });

        // Posts awaiting revision (revision_requested) — show status so host knows what's happening
        const awaitingRevision = allPending.filter(p => p.status === 'revision_requested');
        awaitingRevision.forEach(function(p) {
            html += '<tr style="opacity:0.7;">' +
                '<td><strong>' + escapeHtml(p.title) + '</strong></td>' +
                '<td>' + escapeHtml(p.submitter?.domain || 'Unknown') + '</td>' +
                '<td>' + p.word_count + '</td>' +
                '<td>' + formatDate(p.submitted_at) + '</td>' +
                '<td><span class="vp-status-badge" style="background:#fef3c7;color:#92400e;padding:4px 10px;border-radius:4px;font-size:12px;">Awaiting revision</span></td>' +
                '</tr>';
        });

        if (html === '') {
            $tbody.html('<tr><td colspan="5" style="text-align:center;color:var(--vp-text-muted);padding:40px;">No posts ready for review</td></tr>');
        } else {
            $tbody.html(html);
        }
    }

    function renderPublished() {
        const $tbody = $('#published-tbody');
        const $loading = $('#published-loading');
        const $empty = $('#published-empty');
        const all = GP.data.received || [];
        const posts = all.filter(p => p.status === 'approved');

        $loading.hide();

        if (posts.length === 0) {
            $empty.show();
            $tbody.html('');
            return;
        }

        $empty.hide();
        let html = '';
        posts.forEach(function(p) {
            html += '<tr>' +
                '<td><strong>' + escapeHtml(p.title) + '</strong></td>' +
                '<td>' + escapeHtml(p.submitter?.domain || 'Unknown') + '</td>' +
                '<td>' + formatDate(p.published_at) + '</td>' +
                '<td>' + (p.published_url && isValidHttpUrl(p.published_url) ? '<a href="' + escapeHtml(p.published_url) + '" target="_blank" class="vp-btn vp-btn-sm vp-btn-outline">View</a>' : (p.published_url ? escapeHtml(p.published_url) : '-')) + '</td>' +
                '</tr>';
        });
        $tbody.html(html);
    }

    function getSubmissionActions(p) {
        let html = '<div class="vp-action-btns">';

        if (p.status === 'draft') {
            html += '<button class="vp-btn vp-btn-sm vp-btn-edit btn-edit" data-id="' + p.id + '">Edit</button>';
            html += '<button class="vp-btn vp-btn-sm vp-btn-withdraw btn-withdraw" data-id="' + p.id + '">Delete</button>';
        } else if (p.status === 'revision_requested') {
            html += '<button class="vp-btn vp-btn-sm vp-btn-edit btn-edit" data-id="' + p.id + '">Edit & Resubmit</button>';
            html += '<button class="vp-btn vp-btn-sm vp-btn-withdraw btn-withdraw" data-id="' + p.id + '">Withdraw</button>';
        } else if (p.status === 'pending_review') {
            html += '<button class="vp-btn vp-btn-sm vp-btn-withdraw btn-withdraw" data-id="' + p.id + '">Withdraw</button>';
        } else if (p.status === 'approved' && p.published_url) {
            html += isValidHttpUrl(p.published_url)
                ? '<a href="' + escapeHtml(p.published_url) + '" target="_blank" class="vp-btn vp-btn-sm vp-btn-outline">View Post</a>'
                : '<span class="vp-btn vp-btn-sm vp-btn-outline">' + escapeHtml(p.published_url) + '</span>';
        }

        if (p.status === 'rejected' || p.status === 'withdrawn') {
            html += '<button class="vp-btn vp-btn-sm vp-btn-dismiss btn-dismiss" data-id="' + p.id + '" title="Dismiss"><span class="dashicons dashicons-no-alt"></span></button>';
        }

        html += '</div>';
        return html;
    }

    function updateCounts() {
        const activeSubmissions = (GP.data.my_submissions || []).filter(p => !['withdrawn', 'rejected', 'expired'].includes(p.status));
        $('#count-submissions').text(activeSubmissions.length);
        $('#count-pending').text(GP.data.pending_review?.length || 0);
        const published = (GP.data.received || []).filter(p => p.status === 'approved');
        $('#count-published').text(published.length);
    }

    // Modals
    function openModal(id) {
        $('#' + id).fadeIn(200);
        $('body').addClass('vp-modal-open');
    }
    function closeModal() {
        $('.vp-gp-modal').fadeOut(200);
        $('body').removeClass('vp-modal-open');
        setTimeout(resetForm, 250);
    }

    // Close on X button click
    $(document).on('click', '.vp-gp-modal-close', closeModal);

    // Close on backdrop click - but ONLY if clicking the overlay itself
    $(document).on('click', '.vp-gp-modal-overlay', function(e) {
        if (e.target === this) {
            closeModal();
        }
    });

    $(document).on('keydown', function(e) { if (e.key === 'Escape') closeModal(); });

    $('#btn-new-guest-post').on('click', function() {
        loadPartners();
        openModal('modal-new-post');
    });

    // Link Detection
    function extractLinks() {
        let content = '';
        if (typeof tinymce !== 'undefined' && tinymce.get('gp-content')) {
            content = tinymce.get('gp-content').getContent();
        } else {
            content = $('#gp-content').val();
        }

        const $list = $('#links-list');
        const links = extractLinksFromHtml(content);

        if (links.length === 0) {
            $list.html('<p class="vp-no-links">No links detected yet. Add links in the editor above.</p>');
        } else {
            let html = '';
            links.forEach(function(l) {
                html += '<div class="vp-link-item">' +
                    '<span class="vp-link-anchor">"' + escapeHtml(l.anchor) + '"</span>' +
                    '<span class="vp-link-url">&rarr; ' + escapeHtml(l.url) + '</span>' +
                    '</div>';
            });
            $list.html(html);
        }

        const text = content.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
        const words = text ? text.split(' ').length : 0;

        // Get partner requirements for min words validation
        const partnerId = $('#gp-partner').val();
        let minWords = 500; // Default
        if (typeof ConsoletyPartnerCards !== 'undefined' && partnerId && ConsoletyPartnerCards.partnerRequirements) {
            const req = ConsoletyPartnerCards.partnerRequirements[partnerId];
            if (req && req.min_words) {
                minWords = req.min_words;
            }
        }

        // Update word count display with visual feedback
        const $wordCount = $('#word-count');
        $wordCount.text(words + ' / ' + minWords + ' words');

        if (words < minWords) {
            $wordCount.removeClass('vp-word-count-ok').addClass('vp-word-count-low');
        } else {
            $wordCount.removeClass('vp-word-count-low').addClass('vp-word-count-ok');
        }
    }

    // TinyMCE Hook
    function initTinyMCE() {
        if (typeof tinymce !== 'undefined' && tinymce.get('gp-content')) {
            const editor = tinymce.get('gp-content');
            editor.on('keyup change NodeChange input paste', extractLinks);
            return true;
        }
        return false;
    }

    if (!initTinyMCE()) {
        const mcePoll = setInterval(function() {
            if (initTinyMCE()) clearInterval(mcePoll);
        }, 500);
    }

    // Submit Post
    $('#form-new-post').on('submit', function(e) {
        e.preventDefault();
        submitPost(true);
    });

    $('#btn-save-draft').on('click', function() { submitPost(false); });

    // Edit existing post
    $(document).on('click', '.btn-edit', function() {
        const id = $(this).data('id');
        const $btn = $(this);
        $btn.prop('disabled', true).text('Loading...');

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_show', nonce: GP.nonce, post_id: id },
            success: function(response) {
                if (response.success && response.data) {
                    openEditModal(response.data);
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'loadPostForEdit')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            },
            complete: function() { $btn.prop('disabled', false).text('Edit'); }
        });
    });

    function openEditModal(post) {
        GP.editingPostId = post.id;
        GP.editingPost = post;

        const isRevision = post.status === 'revision_requested';
        $('#modal-new-post .vp-gp-modal-header h2').html(isRevision ? '<span class="dashicons dashicons-edit" style="margin-right:6px;"></span>Edit & Resubmit' : '<span class="dashicons dashicons-edit" style="margin-right:6px;"></span>Edit Draft');

        $('#gp-title').val(post.title);

        // Show feedback and revision count if revision requested
        $('#modal-new-post .vp-feedback-box').remove();
        $('#modal-new-post .vp-revision-counter').remove();

        if (isRevision) {
            // Show revision counter (e.g., "Revision 1 of 3")
            const revisionCount = post.revision_count || 1;
            const maxRevisions = post.max_revisions || 3;
            const revisionsRemaining = maxRevisions - revisionCount;

            let counterClass = 'vp-revision-ok';
            if (revisionsRemaining <= 1) {
                counterClass = 'vp-revision-warning';
            }
            if (revisionsRemaining === 0) {
                counterClass = 'vp-revision-danger';
            }

            const revisionHtml = '<div class="vp-revision-counter ' + counterClass + '">' +
                '<span class="dashicons dashicons-backup"></span> ' +
                (GP.i18n?.revisionCounter || 'Revision {current} of {max}')
                    .replace('{current}', revisionCount)
                    .replace('{max}', maxRevisions) +
                (revisionsRemaining === 0 ? ' - ' + (GP.i18n?.lastRevision || 'This is your last revision!') : '') +
            '</div>';
            $('#modal-new-post .vp-gp-modal-header').after(revisionHtml);

            // Show feedback from host
            if (post.feedback) {
                const feedbackHtml = '<div class="vp-feedback-box">' +
                    '<strong><span class="dashicons dashicons-edit" style="margin-right:8px;"></span>' +
                    (GP.i18n?.hostFeedback || 'Host Feedback:') + '</strong><br>' +
                    '<p style="margin:8px 0 0;">' + escapeHtml(post.feedback) + '</p>' +
                '</div>';
                $('#modal-new-post .vp-form-group.vp-form-editor').before(feedbackHtml);
            }
        }

        $('#btn-submit').text(isRevision ? 'Resubmit for Review' : 'Submit for Review');
        $('#btn-save-draft').text('Save Changes');

        $('#gp-partner').val(post.host?.id || post.host_site_id).prop('disabled', true);

        loadPartners();
        openModal('modal-new-post');

        const contentToSet = post.content || '';
        let retries = 0;

        function setTinyMCEContent() {
            if (typeof tinymce !== 'undefined' && tinymce.get('gp-content') && tinymce.get('gp-content').initialized) {
                tinymce.get('gp-content').setContent(contentToSet);
                extractLinks();
                return;
            }
            if (++retries < 15) setTimeout(setTinyMCEContent, 200);
            else $('#gp-content').val(contentToSet);
        }

        setTimeout(setTinyMCEContent, 300);
    }

    function submitPost(shouldSubmit) {
        if (typeof tinymce !== 'undefined' && tinymce.get('gp-content')) {
            tinymce.get('gp-content').save();
        }

        const isEditing = GP.editingPostId;
        const content = $('#gp-content').val();
        const partnerId = $('#gp-partner').val();

        // Word count validation (only when submitting, not saving draft)
        if (shouldSubmit) {
            const text = content.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim();
            const wordCount = text ? text.split(' ').length : 0;

            // Get partner requirements
            let minWords = 500; // Default
            if (typeof ConsoletyPartnerCards !== 'undefined' && partnerId && ConsoletyPartnerCards.partnerRequirements) {
                const req = ConsoletyPartnerCards.partnerRequirements[partnerId];
                if (req && req.min_words) {
                    minWords = req.min_words;
                }
            }

            if (wordCount < minWords) {
                showNotice(
                    (GP.i18n && GP.i18n.wordCountError
                        ? GP.i18n.wordCountError.replace('{min}', minWords).replace('{current}', wordCount)
                        : 'Your post has ' + wordCount + ' words but the minimum requirement is ' + minWords + ' words.'),
                    'error'
                );
                return;
            }
        }

        const data = {
            action: isEditing ? 'consolety_guest_posts_update' : 'consolety_guest_posts_create',
            nonce: GP.nonce,
            title: $('#gp-title').val(),
            content: content,
            submit: shouldSubmit ? 1 : 0
        };

        if (isEditing) {
            data.post_id = GP.editingPostId;
        } else {
            data.host_site_id = partnerId;
        }

        $('#btn-submit, #btn-save-draft').prop('disabled', true);

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: data,
            success: function(response) {
                if (response.success) {
                    closeModal();
                    loadGuestPosts();
                    showNotice(response.data?.message || 'Saved!', 'success');
                    resetForm();
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'submitGuestPost')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            },
            complete: function() { $('#btn-submit, #btn-save-draft').prop('disabled', false); }
        });
    }

    function resetForm() {
        GP.editingPostId = null;
        GP.editingPost = null;
        $('#form-new-post')[0].reset();
        $('#gp-partner').prop('disabled', false);
        $('#modal-new-post .vp-feedback-box').remove();
        $('#modal-new-post .vp-gp-modal-header h2').html('<span class="dashicons dashicons-edit" style="margin-right:8px;"></span>Submit Guest Post');
        $('#btn-submit').text('Submit for Review');
        $('#btn-save-draft').text('Save Draft');
        if (typeof tinymce !== 'undefined' && tinymce.get('gp-content')) {
            tinymce.get('gp-content').setContent('');
        }
        extractLinks();
    }

    // Note: resetForm is now called in closeModal() - no duplicate handler needed

    // Review
    $(document).on('click', '.btn-review', function() {
        const id = $(this).data('id');
        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_show', nonce: GP.nonce, post_id: id },
            success: function(response) {
                if (response.success) {
                    const p = response.data;
                    $('#review-post-id').val(p.id);
                    $('#review-title').text(p.title);
                    $('#review-from').text(p.submitter?.domain || 'Unknown');
                    $('#review-words').text(p.word_count);
                    // XSS Protection: sanitize with strict config (no style attrs, no data-attrs)
                    $('#review-body').html(typeof DOMPurify !== 'undefined' ? DOMPurify.sanitize(p.content, window.VP_DOMPURIFY_CONFIG || {}) : escapeHtml(p.content));

                    // Show sanitization report if Hub detected and stripped unsafe content
                    $('.vp-sanitization-notice').remove();
                    if (p.sanitization_report && p.sanitization_report.was_modified) {
                        var reportHtml = '<div class="vp-sanitization-notice">' +
                            '<span class="dashicons dashicons-shield" style="color:#f59e0b;margin-right:6px;"></span>' +
                            '<strong>Content was cleaned:</strong> ' +
                            escapeHtml(p.sanitization_report.changes_summary) +
                            '</div>';
                        $('#review-body').before(reportHtml);
                    }

                    // Extract links using DOM parser (handles bold/italic anchor text)
                    const links = extractLinksFromHtml(p.content);

                    if (links.length > 0) {
                        let linkHtml = '<strong><span class="dashicons dashicons-admin-links" style="margin-right:6px;"></span>Links in this post:</strong><br>';
                        links.forEach(function(l) {
                            // XSS Protection: validate protocol + escape URL in href attribute
                            const linkDisplay = isValidHttpUrl(l.url)
                                ? '<a href="' + escapeHtml(l.url) + '" target="_blank" rel="noopener noreferrer">' + escapeHtml(l.url) + '</a>'
                                : escapeHtml(l.url);
                            linkHtml += '<div style="margin-top:8px;"><span style="color:#10b981;">"' + escapeHtml(l.anchor) + '"</span> &rarr; ' + linkDisplay + '</div>';
                        });
                        $('#review-links').html(linkHtml).show();
                    } else {
                        $('#review-links').hide();
                    }

                    if (p.author_bio) {
                        // XSS Protection: escape author bio content
                        $('#review-bio').html('<strong>Author:</strong> ' + escapeHtml(p.author_bio)).show();
                    } else {
                        $('#review-bio').hide();
                    }

                    $('#revision-feedback, #reject-reason').val('');
                    openModal('modal-review');
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'showReview')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            }
        });
    });

    // Featured Image Media Library Integration
    let featuredImageFrame = null;

    $('#btn-select-featured-image').on('click', function(e) {
        e.preventDefault();

        if (featuredImageFrame) {
            featuredImageFrame.open();
            return;
        }

        featuredImageFrame = wp.media({
            title: GP.i18n.selectFeaturedImage,
            button: { text: GP.i18n.useAsFeaturedImage },
            multiple: false,
            library: { type: 'image' }
        });

        featuredImageFrame.on('select', function() {
            const attachment = featuredImageFrame.state().get('selection').first().toJSON();
            $('#approve-featured-image-id').val(attachment.id);
            const previewUrl = attachment.sizes?.medium?.url || attachment.sizes?.thumbnail?.url || attachment.url;
            $('#featured-image-img').attr('src', previewUrl);
            $('#featured-image-preview').show();
            $('#btn-select-featured-image').html('<span class="dashicons dashicons-format-image"></span> ' + GP.i18n.changeImage);
        });

        featuredImageFrame.open();
    });

    $('#btn-remove-featured-image').on('click', function(e) {
        e.preventDefault();
        $('#approve-featured-image-id').val('');
        $('#featured-image-preview').hide();
        $('#featured-image-img').attr('src', '');
        $('#btn-select-featured-image').html('<span class="dashicons dashicons-format-image"></span> ' + GP.i18n.selectImage);
    });

    // Reset featured image when review modal closes
    $(document).on('click', '#modal-review .vp-gp-modal-overlay, #modal-review .vp-gp-modal-close', function() {
        $('#approve-featured-image-id').val('');
        $('#featured-image-preview').hide();
        $('#featured-image-img').attr('src', '');
        $('#btn-select-featured-image').html('<span class="dashicons dashicons-format-image"></span> ' + GP.i18n.selectImage);
    });

    $('#btn-approve').on('click', function() {
        const id = $('#review-post-id').val();
        const categoryId = $('#approve-category').val();
        const featuredImageId = $('#approve-featured-image-id').val();
        $(this).prop('disabled', true).text('Publishing...');

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: {
                action: 'consolety_guest_posts_approve',
                nonce: GP.nonce,
                post_id: id,
                category_id: categoryId,
                featured_image_id: featuredImageId
            },
            success: function(response) {
                if (response.success) {
                    closeModal();
                    loadGuestPosts();
                    var earned = response.data?.credits_earned;
                    var msg = 'Guest post published!';
                    if (earned && earned > 0) {
                        msg += ' +' + earned + ' points earned';
                    }
                    showNotice(msg, 'success');
                    // Refresh balance in header if available
                    if (response.data?.new_balance !== undefined) {
                        $('.vp-credits-value').text(response.data.new_balance);
                    }
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'approvePost')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            },
            complete: function() { $('#btn-approve').prop('disabled', false).text('Approve & Publish'); }
        });
    });

    $('#btn-revision').on('click', function() {
        const id = $('#review-post-id').val();
        const feedback = $('#revision-feedback').val();
        if (!feedback) { alert('Please provide feedback'); return; }

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_request_revision', nonce: GP.nonce, post_id: id, feedback: feedback },
            success: function(response) {
                if (response.success) {
                    closeModal();
                    loadGuestPosts();
                    showNotice('Revision requested', 'success');
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'requestRevision')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            }
        });
    });

    $('#btn-reject').on('click', function() {
        const id = $('#review-post-id').val();
        const reason = $('#reject-reason').val().trim();

        // Validation: required
        if (!reason) {
            showNotice('Please provide a rejection reason.', 'error');
            return;
        }

        // Validation: min 50 chars (match backend)
        if (reason.length < 50) {
            showNotice('Rejection reason must be at least 50 characters. Currently: ' + reason.length + ' characters.', 'error');
            return;
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('Rejecting...');

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_reject', nonce: GP.nonce, post_id: id, reason: reason },
            success: function(response) {
                if (response.success) {
                    closeModal();
                    loadGuestPosts();
                    showNotice('Post rejected. Credits returned to submitter.', 'success');
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'rejectPost')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
            },
            complete: function() {
                $btn.prop('disabled', false).text('Reject');
            }
        });
    });

    // Character counter for rejection reason
    $('#reject-reason').on('input', function() {
        const len = $(this).val().trim().length;
        const $counter = $('#reject-char-count');
        $counter.text(len);

        if (len >= 50) {
            $counter.parent().css('color', '#10b981'); // Green when valid
        } else {
            $counter.parent().css('color', '#ef4444'); // Red when invalid
        }
    });

    // Withdraw
    $(document).on('click', '.btn-withdraw', function() {
        const $row = $(this).closest('tr');
        const hasCredits = parseInt($row.data('credits')) > 0;
        const msg = hasCredits
            ? 'Withdraw this submission? Your reserved points will be returned.'
            : 'Withdraw this draft?';
        if (!confirm(msg)) return;

        const id = $(this).data('id');
        const $btn = $(this);
        $btn.prop('disabled', true).text('...');

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_withdraw', nonce: GP.nonce, post_id: id },
            success: function(response) {
                if (response.success) {
                    loadGuestPosts();
                    const notice = hasCredits ? 'Withdrawn. Credits returned.' : 'Draft deleted.';
                    showNotice(notice, 'success');
                } else {
                    const code = response.data?.code || 'API_ERROR';
                    showNotice(mapErrorCode(code, response.data?.message), 'error');
                    $btn.prop('disabled', false).text('Withdraw');
                }
            },
            error: function(xhr, status, error) {
                if (!handleAjaxError(xhr, status, error, 'withdrawPost')) {
                    showNotice(getXhrErrorMessage(xhr), 'error');
                }
                $btn.prop('disabled', false).text('Withdraw');
            }
        });
    });

    // Dismiss rejected/withdrawn posts
    $(document).on('click', '.btn-dismiss', function() {
        const id = $(this).data('id');
        const $card = $(this).closest('tr');
        $card.css('opacity', '0.5');

        $.ajax({
            url: GP.ajaxUrl,
            type: 'POST',
            data: { action: 'consolety_guest_posts_dismiss', nonce: GP.nonce, post_id: id },
            success: function(response) {
                if (response.success) {
                    $card.slideUp(200, function() { loadGuestPosts(); });
                } else {
                    $card.css('opacity', '1');
                    showNotice(response.data?.message || 'Failed to dismiss', 'error');
                }
            },
            error: function() {
                $card.css('opacity', '1');
                showNotice('Failed to dismiss post', 'error');
            }
        });
    });

    // Utilities
    function escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    function isValidHttpUrl(url) {
        if (!url) return false;
        try {
            const parsed = new URL(url);
            return ['http:', 'https:'].includes(parsed.protocol);
        } catch {
            return false;
        }
    }

    function formatDate(iso) {
        if (!iso) return '-';
        return new Date(iso).toLocaleDateString();
    }

    // NOTE: showNotice() is defined earlier in this file (around line 89) with proper escapeHtml()
    // Do NOT add another showNotice() here - that would cause XSS vulnerability!

    // Init
    loadGuestPosts();

    // Check if coming from Network page with pre-selected partner (via URL parameters)
    (function checkAndOpenModal() {
        const urlParams = new URLSearchParams(window.location.search);
        const partnerId = urlParams.get('partner_id');
        const partnerDomain = urlParams.get('partner_domain');
        const partnerClicks = urlParams.get('partner_clicks') || 0;

        if (partnerId && partnerDomain) {
            // Coming from Network page - load partners FIRST, then open modal
            loadPartners(function() {
                // Open modal EERST - dit maakt de DOM elementen zichtbaar
                openModal('modal-new-post');

                // DEFINITIEVE FIX: Forceer DOM state NA modal is geopend
                // jQuery .hide() werkt niet goed op elementen in een display:none parent
                // Door te wachten tot modal open is, is de DOM zeker beschikbaar
                setTimeout(function() {
                    if (typeof ConsoletyPartnerCards !== 'undefined') {
                        // Forceer context mode state
                        ConsoletyPartnerCards.isContextMode = true;
                        ConsoletyPartnerCards.selectedPartnerId = partnerId;

                        // Forceer DOM manipulaties
                        $('#partner-label-wrap').hide();
                        $('#partner-context-wrap').show();
                        $('#partner-selection-wrap').hide();
                        $('#context-partner-domain').text(partnerDomain);
                        $('#context-partner-stats').text(
                            ConsoletyPartnerCards.formatNumber(parseInt(partnerClicks)) + ' clicks/month'
                        );
                        $('#gp-partner').val(partnerId);

                        // Toon requirements als beschikbaar
                        ConsoletyPartnerCards.displayRequirements(partnerId);

                        // BELANGRIJK: Bind events zodat "Change" knop werkt
                        ConsoletyPartnerCards.bindEvents();
                    }
                }, 100);
            });
        }
    })();

})(jQuery);
