<?php
if (!defined('WPINC')) {
    die;
}
?>

<div class="aysa-dashboard-wrapper">
    <div class="aysa-dashboard-container">
        <div class="aysa-dashboard-header">
            <div class="aysa-dashboard-title">
                <h1>Off-Page Optimization</h1>
                <p>Link Building Marketplace</p>
            </div>
            <div class="aysa-dashboard-user">
                <?php
                if (class_exists('Aysa_Credits_Component')) {
                    Aysa_Credits_Component::display();
                } else {
                    echo '<div class="aysa-credits-component"><span class="aysa-credits-value">Credits: <span class="aysa-credits-amount"><span class="aysa-loading-spinner"></span></span></span></div>';
                }
                ?>
            </div>
        </div>

        <div class="aysa-offpage-content">
            <div class="lb-main-tabs">
                <button type="button" class="button lb-main-tab is-active" data-main-tab="link-building">Link Building</button>
                <button type="button" class="button lb-main-tab" data-main-tab="link-exchange">Link Exchange</button>
                <button type="button" class="button lb-main-tab" data-main-tab="draft-articles">Draft Articles</button>
                <button type="button" class="button lb-main-tab" data-main-tab="published-articles">Published Articles</button>
                <button type="button" class="button lb-main-tab" data-main-tab="backlink-audit">Backlink audit</button>
                <button type="button" class="button lb-main-tab" data-main-tab="google-business-profile">Google Business Profile</button>
            </div>

            <div id="lb-view-link-building">
                <div class="lb-headline-row">
                    <h3>Ordering publication</h3>
                    <div class="lb-credit-wrap">
                        <div class="aysa-credits-component lb-credit-pill">
                            <span class="aysa-credits-value">Credits: <span class="aysa-credits-amount" id="lb-credit-value">-</span></span>
                        </div>
                        <div class="aysa-credits-component lb-credit-pill">
                            <span class="aysa-credits-value">Included links this month: <span class="lb-included-links-amount" id="lb-included-links-value">-</span></span>
                        </div>
                        <button type="button" class="button" id="lb-refresh-lb-credits">Refresh</button>
                    </div>
                </div>

                <div class="lb-filters-shell">
                    <h4>Basic filters</h4>

                    <div class="lb-top-grid">
                        <div class="lb-card">
                            <h5>Type of offers</h5>
                            <p>Select the type of offers you are interested in.</p>
                            <div class="lb-offer-types">
                                <label><input type="checkbox" class="lb-offer-check" value="sponsored_articles"> Sponsored articles</label>
                                <label><input type="checkbox" class="lb-offer-check" value="link_insertion"> Link placements</label>
                                <label><input type="checkbox" class="lb-offer-check" value="brand_mention"> Brand mentions</label>
                                <label><input type="checkbox" class="lb-offer-check" value="banners"> Banner placements</label>
                            </div>
                        </div>
                        <div class="lb-card">
                            <h5>Keyword search</h5>
                            <p>Use keywords and portal filters to narrow results.</p>
                            <input type="text" id="lb-keyword-search" placeholder="Enter keywords">
                        </div>
                        <div class="lb-card lb-note">
                            <strong>Marketplace mode</strong>
                            <span>Domains are loaded automatically from secure server-side credentials.</span>
                        </div>
                    </div>

                    <div class="lb-filter-grid">
                        <input type="text" id="lb-domain-query" placeholder="Domain, website name, tag">
                        <input type="text" id="lb-country" placeholder="Country" value="Romania">
                        <input type="text" id="lb-portal-type" placeholder="Type of portal">
                        <input type="text" id="lb-region" placeholder="Region">

                        <input type="text" id="lb-theme" placeholder="Theme">
                        <select id="lb-dofollow">
                            <option value="">Dofollow links</option>
                            <option value="yes">Yes</option>
                            <option value="no">No</option>
                        </select>
                        <input type="number" id="lb-price-from" placeholder="Price from" min="0" step="0.01">
                        <input type="number" id="lb-price-to" placeholder="Price to" min="0" step="0.01">

                        <input type="number" id="lb-min-dr" placeholder="Min. Domain Rating" min="0" step="1">
                        <input type="number" id="lb-min-ahrefs" placeholder="Min. AHREFS traffic" min="0" step="1">
                        <input type="number" id="lb-min-trust" placeholder="Min. Trust Flow" min="0" step="1">
                        <select id="lb-billing-type">
                            <option value="">Billing type</option>
                            <option value="one_time">One time</option>
                            <option value="monthly">Monthly</option>
                        </select>
                    </div>

                    <div class="lb-actions-row">
                        <button type="button" class="button button-primary" id="lb-search-btn">Search</button>
                        <button type="button" class="button" id="lb-advanced-btn">Advanced filters</button>
                        <button type="button" class="button" id="lb-saved-btn">Saved searches</button>
                    </div>
                </div>

                <div class="lb-diagnostics" id="lb-marketplace-diagnostics">
                    <div>
                        <strong>Marketplace diagnostics</strong>
                        <span id="lb-marketplace-diagnostics-status">Checking credentials and upstream connectivity...</span>
                    </div>
                    <button type="button" class="button" id="lb-refresh-marketplace-diagnostics">Refresh diagnostics</button>
                </div>

                <div class="lb-status" id="lb-status">Loading domains...</div>

                <div class="lb-results-wrap" id="lb-results-wrap"></div>

                <div class="lb-actions-row" style="justify-content:flex-end;margin-top:12px;">
                    <button type="button" class="button" id="lb-refresh-orders">Refresh tracking</button>
                </div>
                <div class="lb-results-wrap" id="lb-orders-wrap"></div>

                <div class="lb-actions-row" style="justify-content:space-between;margin-top:16px;">
                    <strong>Link issues</strong>
                    <button type="button" class="button" id="lb-refresh-link-issues">Refresh link issues</button>
                </div>
                <div class="lb-status" id="lb-link-issues-status">Auto-check runs hourly via cron.</div>
                <div class="lb-results-wrap" id="lb-link-issues-wrap"></div>
            </div>

            <div id="lb-view-link-exchange" style="display:none;">
                <div class="lb-headline-row">
                    <h3>Link Exchange Marketplace</h3>
                    <div class="lb-actions-row">
                        <button type="button" class="button" id="lb-exchange-refresh-portals">Refresh eligible sites</button>
                        <button type="button" class="button" id="lb-exchange-refresh-requests">Refresh requests</button>
                    </div>
                </div>
                <div class="lb-diagnostics">
                    <div>
                        <strong>Exchange rules</strong>
                        <span>Strict 1:1 exchange, manual requests, plugin-active sites only, authority bucket + topic match required.</span>
                    </div>
                </div>
                <div class="lb-exchange-profile" id="lb-exchange-profile"></div>
                <div class="lb-filter-grid lb-exchange-filter-grid">
                    <input type="text" id="lb-exchange-search" placeholder="Search domain or topic">
                    <input type="text" id="lb-exchange-country" placeholder="Country filter">
                    <input type="text" id="lb-exchange-language" placeholder="Language filter">
                    <input type="text" id="lb-exchange-topic" placeholder="Topic filter">
                </div>
                <div class="lb-status" id="lb-exchange-status">Loading compatible sites...</div>
                <div class="lb-results-wrap" id="lb-exchange-results-wrap"></div>

                <div class="lb-headline-row" style="margin-top:18px;">
                    <h3>Exchange Inbox</h3>
                </div>
                <div class="lb-status" id="lb-exchange-requests-status">Loading exchange requests...</div>
                <div class="lb-results-wrap" id="lb-exchange-requests-wrap"></div>
                <div class="lb-exchange-detail" id="lb-exchange-detail" style="display:none;">
                    <div class="lb-draft-preview-head">
                        <h4 id="lb-exchange-detail-title">Exchange detail</h4>
                        <div class="lb-actions-row">
                            <button type="button" class="button" id="lb-exchange-accept-btn">Accept</button>
                            <button type="button" class="button" id="lb-exchange-reject-btn">Reject</button>
                            <button type="button" class="button" id="lb-exchange-publish-btn">Activate my link</button>
                            <button type="button" class="button" id="lb-exchange-verify-btn">Refresh verification</button>
                            <button type="button" class="button" id="lb-exchange-dispute-btn">Dispute</button>
                        </div>
                    </div>
                    <div class="lb-draft-preview-meta" id="lb-exchange-detail-meta"></div>
                    <div class="lb-filter-grid" style="margin:12px 0;" id="lb-exchange-activation-controls">
                        <select id="lb-exchange-source-post"></select>
                        <button type="button" class="button" id="lb-exchange-refresh-sources-btn">Refresh source pages</button>
                    </div>
                    <div class="lb-results-wrap" id="lb-exchange-timeline-wrap"></div>
                </div>
            </div>

            <div id="lb-view-draft-articles" style="display:none;">
                <div class="lb-headline-row">
                    <h3>Draft Articles For Publishing</h3>
                    <div class="lb-actions-row">
                        <button type="button" class="button" id="lb-refresh-draft-articles">Refresh drafts</button>
                    </div>
                </div>
                <div class="lb-status" id="lb-draft-articles-status">Loading draft articles...</div>
                <div class="lb-results-wrap" id="lb-draft-articles-wrap"></div>
                <div class="lb-draft-preview" id="lb-draft-preview" style="display:none;">
                    <div class="lb-draft-preview-head">
                        <h4 id="lb-draft-preview-title">Draft preview</h4>
                        <div class="lb-actions-row">
                            <button type="button" class="button button-primary" id="lb-save-publisher-draft">Save draft</button>
                            <button type="button" class="button" id="lb-approve-publisher-draft">Approve for publishing</button>
                        </div>
                    </div>
                    <div class="lb-draft-preview-meta" id="lb-draft-preview-meta"></div>
                    <div class="lb-draft-preview-links" id="lb-draft-preview-links"></div>
                    <div class="lb-draft-preview-form">
                        <div class="lb-form-row">
                            <label for="lb-draft-edit-title">Title</label>
                            <input type="text" id="lb-draft-edit-title" placeholder="Draft title">
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-draft-edit-excerpt">Excerpt</label>
                            <textarea id="lb-draft-edit-excerpt" rows="4" placeholder="Short summary"></textarea>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-draft-edit-body">Body</label>
                            <textarea id="lb-draft-edit-body" rows="18" placeholder="Draft HTML/body"></textarea>
                        </div>
                    </div>
                    <div class="lb-draft-preview-body" id="lb-draft-preview-body"></div>
                </div>
            </div>

            <div id="lb-view-published-articles" style="display:none;">
                <div class="lb-headline-row">
                    <h3>Published Articles</h3>
                    <div class="lb-actions-row">
                        <button type="button" class="button" id="lb-refresh-published-articles">Refresh published</button>
                    </div>
                </div>
                <div class="lb-status" id="lb-published-articles-status">Loading published articles...</div>
                <div class="lb-results-wrap" id="lb-published-articles-wrap"></div>
            </div>

            <div id="lb-view-backlink-audit" style="display:none;">
                <div class="lb-headline-row">
                    <h3>Backlink audit</h3>
                    <div class="lb-actions-row">
                        <button type="button" class="button button-primary" id="lb-run-backlink-audit">Run audit now</button>
                    </div>
                </div>
                <div class="lb-status" id="lb-backlink-audit-status">Use Run audit now to evaluate backlink risk.</div>
                <div class="lb-audit-cards">
                    <div class="lb-audit-card"><strong id="lb-audit-total">0</strong><span>Total backlinks</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-refdomains">0</strong><span>Referring domains</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-follow-rate">0%</strong><span>Follow ratio</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-broken">0</strong><span>Broken links</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-low">0</strong><span>Low risk</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-medium">0</strong><span>Medium risk</span></div>
                    <div class="lb-audit-card"><strong id="lb-audit-high">0</strong><span>High risk</span></div>
                </div>
                <div class="lb-audit-filters">
                    <select id="lb-audit-risk-filter">
                        <option value="">All risks</option>
                        <option value="high">High</option>
                        <option value="medium">Medium</option>
                        <option value="low">Low</option>
                    </select>
                    <select id="lb-audit-follow-filter">
                        <option value="">All link attrs</option>
                        <option value="follow">Follow only</option>
                        <option value="nofollow">Nofollow only</option>
                    </select>
                    <select id="lb-audit-anchor-filter">
                        <option value="">All anchor types</option>
                        <option value="money">Money</option>
                        <option value="brand">Brand</option>
                        <option value="naked">Naked URL</option>
                        <option value="generic">Generic</option>
                        <option value="compound">Compound</option>
                        <option value="other">Other</option>
                    </select>
                    <select id="lb-audit-health-filter">
                        <option value="">All health</option>
                        <option value="broken">Broken only</option>
                        <option value="new">New only</option>
                        <option value="lost">Lost only</option>
                    </select>
                    <input type="text" id="lb-audit-search" placeholder="Search domain, URL, anchor..." />
                </div>
                <div class="lb-results-wrap" id="lb-backlink-audit-wrap"></div>
            </div>

            <div id="lb-view-google-business-profile" style="display:none;">
                <div class="lb-headline-row">
                    <h3>Google Business Profile</h3>
                    <div class="lb-actions-row">
                        <button type="button" class="button button-primary" id="gbp-sync-accounts">Sync accounts</button>
                        <button type="button" class="button button-primary" id="gbp-sync-locations">Sync locations</button>
                        <button type="button" class="button" id="gbp-jump-create-location">Create first location</button>
                        <button type="button" class="button" id="gbp-refresh-overview">Reload</button>
                    </div>
                </div>
                <div class="lb-diagnostics">
                    <div>
                        <strong>Connection</strong>
                        <span id="gbp-connection-status-text">Google Business Profile uses the existing Google OAuth connection.</span>
                    </div>
                    <div class="lb-actions-row">
                        <button type="button" class="button" id="gbp-connect-google">Connect / Reconnect Google</button>
                    </div>
                </div>
                <div class="lb-status" id="gbp-status">Loading Google Business Profile overview...</div>
                <div class="lb-audit-cards">
                    <div class="lb-audit-card"><strong id="gbp-card-accounts">0</strong><span>Accounts</span></div>
                    <div class="lb-audit-card"><strong id="gbp-card-locations">0</strong><span>Locations</span></div>
                    <div class="lb-audit-card"><strong id="gbp-card-reviews">0</strong><span>Reviews</span></div>
                    <div class="lb-audit-card"><strong id="gbp-card-rating">0</strong><span>Avg rating</span></div>
                    <div class="lb-audit-card"><strong id="gbp-card-jobs">0</strong><span>Jobs</span></div>
                    <div class="lb-audit-card"><strong id="gbp-card-capabilities">-</strong><span>Capabilities</span></div>
                </div>

                <div class="lb-filter-grid" style="margin:12px 0;">
                    <select id="gbp-active-location-select">
                        <option value="">Primary location</option>
                    </select>
                    <button type="button" class="button" id="gbp-set-primary-location">Set primary location</button>
                    <button type="button" class="button" id="gbp-sync-reviews">Sync reviews</button>
                    <button type="button" class="button" id="gbp-refresh-performance">Refresh performance</button>
                    <button type="button" class="button" id="gbp-refresh-verification">Refresh verification</button>
                </div>

                <div class="lb-results-wrap" id="gbp-connection-wrap"></div>
                <div class="lb-results-wrap" id="gbp-locations-wrap"></div>
                <div class="lb-results-wrap" id="gbp-performance-wrap"></div>
                <div class="lb-results-wrap" id="gbp-reviews-wrap"></div>

                <div class="lb-section-grid" style="margin-top:16px;">
                    <div class="lb-card-panel">
                        <h4>Business Info</h4>
                        <div class="lb-form-row"><label for="gbp-info-title">Title</label><input type="text" id="gbp-info-title" /></div>
                        <div class="lb-form-row"><label for="gbp-info-phone">Phone</label><input type="text" id="gbp-info-phone" /></div>
                        <div class="lb-form-row"><label for="gbp-info-website">Website</label><input type="url" id="gbp-info-website" /></div>
                        <div class="lb-form-row"><label for="gbp-info-language">Language</label><input type="text" id="gbp-info-language" /></div>
                        <div class="lb-form-row"><label for="gbp-info-category">Primary category name</label><input type="text" id="gbp-info-category" /></div>
                        <div class="lb-form-row"><label for="gbp-info-description">Profile description</label><textarea id="gbp-info-description" rows="4"></textarea></div>
                        <button type="button" class="button button-primary" id="gbp-save-business-info">Save business info</button>
                    </div>
                    <div class="lb-card-panel">
                        <h4>Hours & Policies</h4>
                        <div class="lb-form-row"><label for="gbp-regular-hours-json">Regular hours JSON</label><textarea id="gbp-regular-hours-json" rows="6"></textarea></div>
                        <div class="lb-form-row"><label for="gbp-special-hours-json">Special hours JSON</label><textarea id="gbp-special-hours-json" rows="6"></textarea></div>
                        <button type="button" class="button button-primary" id="gbp-save-hours">Save hours</button>
                    </div>
                </div>

                <div class="lb-section-grid" style="margin-top:16px;">
                    <div class="lb-card-panel">
                        <h4>Attributes & Services</h4>
                        <div class="lb-form-row"><label for="gbp-attributes-json">Attributes JSON</label><textarea id="gbp-attributes-json" rows="6"></textarea></div>
                        <div class="lb-form-row"><label for="gbp-services-json">Services JSON</label><textarea id="gbp-services-json" rows="6"></textarea></div>
                        <div class="lb-actions-row">
                            <button type="button" class="button button-primary" id="gbp-save-attributes">Save attributes</button>
                            <button type="button" class="button button-primary" id="gbp-save-services">Save services</button>
                        </div>
                        <p class="lb-hint">Menus are shown only when the profile type/API supports them. Q&amp;A is unsupported by Google API.</p>
                    </div>
                    <div class="lb-card-panel">
                        <h4>Posts & Media</h4>
                        <div class="lb-form-row"><label for="gbp-post-json">Local post JSON</label><textarea id="gbp-post-json" rows="6"></textarea></div>
                        <div class="lb-form-row"><label for="gbp-media-json">Media JSON</label><textarea id="gbp-media-json" rows="6"></textarea></div>
                        <div class="lb-actions-row">
                            <button type="button" class="button button-primary" id="gbp-create-post">Create post</button>
                            <button type="button" class="button button-primary" id="gbp-upload-media">Upload media</button>
                        </div>
                    </div>
                </div>

                <div class="lb-section-grid" style="margin-top:16px;">
                    <div class="lb-card-panel">
                        <h4>Verification</h4>
                        <div class="lb-form-row"><label for="gbp-verification-json">Verification payload JSON</label><textarea id="gbp-verification-json" rows="6"></textarea></div>
                        <div class="lb-actions-row">
                            <button type="button" class="button" id="gbp-get-verification-status">Get status</button>
                            <button type="button" class="button button-primary" id="gbp-start-verification">Start verification</button>
                        </div>
                        <div id="gbp-verification-wrap" class="lb-results-wrap" style="margin-top:8px;"></div>
                    </div>
                    <div class="lb-card-panel">
                        <h4>Location Create / Delete</h4>
                        <div class="lb-form-row"><label for="gbp-create-account-name">Account</label><input type="text" id="gbp-create-account-name" /></div>
                        <div class="lb-form-row"><label for="gbp-create-location-json">Create location JSON</label><textarea id="gbp-create-location-json" rows="6"></textarea></div>
                        <div class="lb-actions-row">
                            <button type="button" class="button button-primary" id="gbp-create-location">Create location</button>
                            <button type="button" class="button" id="gbp-delete-location">Delete selected location</button>
                        </div>
                    </div>
                </div>

                <div class="lb-card-panel" style="margin-top:16px;">
                    <h4>Q&amp;A</h4>
                    <p class="lb-hint">Unsupported by Google API since November 3, 2025. This section is informational only.</p>
                </div>

                <div class="lb-card-panel" style="margin-top:16px;">
                    <h4>Jobs / History</h4>
                    <div class="lb-results-wrap" id="gbp-jobs-wrap"></div>
                </div>
            </div>
        </div>
    </div>
</div>

<div class="lb-modal" id="lb-article-modal" style="display:none;">
    <div class="lb-modal-backdrop" data-close="1"></div>
    <div class="lb-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="lb-article-modal-title">
        <div class="lb-modal-head">
            <h3 id="lb-article-modal-title">Order sponsored article</h3>
            <button type="button" class="lb-modal-close" id="lb-article-close">&times;</button>
        </div>
        <div class="lb-modal-body">
            <div class="lb-modal-summary">
                <div><strong>Portal:</strong> <span id="lb-modal-portal">-</span></div>
                <div><strong>Service:</strong> <span id="lb-modal-service-name">SEO article</span></div>
                <div><strong>Net price:</strong> <span id="lb-modal-price-eur">-</span></div>
                <div><strong>Credits to reserve:</strong> <span id="lb-modal-price-credits">-</span></div>
            </div>

            <div class="lb-section lb-order-setup">
                <div class="lb-pill-group">
                    <button type="button" class="button lb-pill-btn lb-order-tab is-active" data-mode="add_new_article">Sponsored article <span class="lb-tab-price" id="lb-tab-price-article">-</span></button>
                    <button type="button" class="button lb-pill-btn lb-order-tab" data-mode="link_insertion">Link placement <span class="lb-tab-price" id="lb-tab-price-link">-</span></button>
                    <button type="button" class="button lb-pill-btn lb-order-tab is-disabled" data-mode="request_article_writing" disabled aria-disabled="true">Request an article writing</button>
                    <button type="button" class="button lb-pill-btn lb-order-tab" data-mode="seo_text_ads">SEO text ads <span class="lb-tab-price" id="lb-tab-price-ads">-</span></button>
                </div>
            </div>

            <div class="lb-section lb-mode-article">
                <h4>Article content</h4>
                <div class="lb-section-grid">
                    <div class="lb-card-panel">
                        <h5>Brief</h5>
                        <div class="lb-form-row">
                            <label for="lb-modal-content-file">Import from file (DOCX, DOC, ODT, HTML)</label>
                            <input type="file" id="lb-modal-content-file" accept=".docx,.doc,.odt,.html,text/html">
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-modal-title">Title *</label>
                            <input type="text" id="lb-modal-title" placeholder="Article title">
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-modal-lead">Lead *</label>
                            <textarea id="lb-modal-lead" rows="3" placeholder="Lead paragraph"></textarea>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-modal-remarks">Special remarks to the publisher</label>
                            <textarea id="lb-modal-remarks" rows="3" placeholder="Special instructions"></textarea>
                        </div>
                    </div>
                    <div class="lb-card-panel lb-editor-panel">
                        <h5>Article body *</h5>
                        <p class="lb-hint">Use visual editor. No HTML/CSS knowledge required.</p>
                        <div class="lb-mini-actions lb-template-actions">
                            <button type="button" class="button lb-content-template" data-template="intro">Insert intro</button>
                            <button type="button" class="button lb-content-template" data-template="h2">Insert chapter (H2)</button>
                            <button type="button" class="button lb-content-template" data-template="faq">Insert FAQ block</button>
                            <button type="button" class="button lb-content-template" data-template="cta">Insert CTA</button>
                        </div>
                        <textarea id="lb-modal-content" rows="14" placeholder="Write article content here"></textarea>
                        <div class="lb-checklist">
                            <span>Recommended structure:</span>
                            <span>Title</span>
                            <span>Lead</span>
                            <span>3-5 chapters</span>
                            <span>FAQ</span>
                            <span>CTA</span>
                        </div>
                    </div>
                </div>
            </div>

            <div class="lb-section lb-mode-linkinsert lb-hidden">
                <h4>Link placement details</h4>
                <div class="lb-mode-link-grid">
                    <div class="lb-card-panel">
                        <div class="lb-form-row">
                            <label for="lb-li-keyword">Keyword *</label>
                            <input type="text" id="lb-li-keyword" placeholder="Example: florarie">
                            <small>Search by primary keyword. Only matching associated entities are shown.</small>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-target-search">Select target page (auto from associations) *</label>
                            <input type="text" id="lb-li-target-search" placeholder="Type to filter targets...">
                        </div>
                        <div class="lb-li-suggestions" id="lb-li-suggestions"></div>
                    </div>
                    <div class="lb-card-panel">
                        <h5>Selected target</h5>
                        <div class="lb-form-row">
                            <label for="lb-li-target-url">Target URL</label>
                            <input type="url" id="lb-li-target-url" readonly>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-target-title">Entity title</label>
                            <input type="text" id="lb-li-target-title" readonly>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-target-meta">Entity type / keyword</label>
                            <input type="text" id="lb-li-target-meta" readonly>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-rel-type">Link attribute *</label>
                            <select id="lb-li-rel-type">
                                <option value="follow">dofollow</option>
                                <option value="sponsored">sponsored</option>
                                <option value="nofollow">nofollow</option>
                            </select>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-billing-type">Billing type</label>
                            <select id="lb-li-billing-type">
                                <option value="one_time">One-time</option>
                                <option value="monthly">Monthly</option>
                            </select>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-li-remarks">Special remarks to publisher</label>
                            <textarea id="lb-li-remarks" rows="3" placeholder="Optional placement notes"></textarea>
                        </div>
                    </div>
                </div>
            </div>

            <div class="lb-section lb-mode-seoads lb-hidden">
                <h4>SEO text ads</h4>
                <div class="lb-mode-link-grid">
                    <div class="lb-card-panel">
                        <h5>Ad setup</h5>
                        <div class="lb-form-row">
                            <label for="lb-ads-title">Title *</label>
                            <input type="text" id="lb-ads-title" placeholder="Ad title">
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-keyword">Keyword / anchor *</label>
                            <input type="text" id="lb-ads-keyword" placeholder="Example: livrare flori">
                            <small>Used for matching and anchor intent.</small>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-target-search">Linked to URL (destination on your site) *</label>
                            <input type="text" id="lb-ads-target-search" placeholder="Type to filter destination page...">
                        </div>
                        <div class="lb-li-suggestions" id="lb-ads-suggestions"></div>
                        <div class="lb-form-row" style="margin-top:10px;">
                            <label for="lb-ads-target-url">Selected destination URL *</label>
                            <input type="url" id="lb-ads-target-url" readonly>
                        </div>
                    </div>
                    <div class="lb-card-panel">
                        <h5>Publisher placement</h5>
                        <div class="lb-form-row">
                            <label for="lb-ads-display-url">Ad display URL *</label>
                            <input type="url" id="lb-ads-display-url" placeholder="https://brand.example">
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-target-article-url">Published on URL (publisher article page)</label>
                            <input type="url" id="lb-ads-target-article-url" placeholder="https://publisher.example/article">
                            <small>Optional. If empty, publisher/plugin selects a relevant article later.</small>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-description">Ad description *</label>
                            <textarea id="lb-ads-description" rows="4" placeholder="Ad text to be inserted"></textarea>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-duration-months">Duration months</label>
                            <input type="number" id="lb-ads-duration-months" min="1" max="12" value="1">
                            <small>Monthly service. 1 to 12 months.</small>
                        </div>
                        <div class="lb-ads-preview" id="lb-ads-preview">
                            <div class="lb-ads-badge">Ad</div>
                            <div class="lb-ads-title" id="lb-ads-preview-title">SEO text ads title preview</div>
                            <div class="lb-ads-url" id="lb-ads-preview-url">https://example.com/path</div>
                            <div class="lb-ads-desc" id="lb-ads-preview-desc">Short text preview appears here (max 90 characters).</div>
                        </div>
                        <div class="lb-form-row">
                            <label for="lb-ads-remarks">Special remarks to publisher</label>
                            <textarea id="lb-ads-remarks" rows="3" placeholder="Optional notes"></textarea>
                        </div>
                    </div>
                </div>
            </div>

            <div class="lb-section lb-links-block lb-mode-article">
                <div class="lb-links-main">
                    <div class="lb-form-row">
                        <label for="lb-modal-target">Target URL *</label>
                        <input type="url" id="lb-modal-target" value="<?php echo esc_attr(home_url('/')); ?>">
                    </div>
                    <div class="lb-form-row">
                        <label for="lb-modal-keyword">Primary keyword / anchor *</label>
                        <input type="text" id="lb-modal-keyword" placeholder="Keyword">
                    </div>
                    <div class="lb-form-row">
                        <label for="lb-modal-rel-type">Links in the article *</label>
                        <select id="lb-modal-rel-type">
                            <option value="follow">They are to be dofollow</option>
                            <option value="sponsored">They are to be sponsored</option>
                            <option value="nofollow">They are to be nofollow</option>
                        </select>
                    </div>
                    <div class="lb-form-row">
                        <label for="lb-modal-billing-type">Billing type</label>
                        <select id="lb-modal-billing-type">
                            <option value="one_time">One-time</option>
                            <option value="monthly">Monthly</option>
                        </select>
                    </div>
                </div>
                <div class="lb-links-side">
                    <strong>Links to the project found in the content:</strong>
                    <ul>
                        <li>dofollow: 0</li>
                        <li>sponsored: 0</li>
                        <li>nofollow: 0</li>
                    </ul>
                    <span>Replace project's links with:</span>
                    <div class="lb-mini-actions">
                        <button type="button" class="button lb-rel-quick" data-rel="follow">dofollow</button>
                        <button type="button" class="button lb-rel-quick" data-rel="sponsored">sponsored</button>
                        <button type="button" class="button lb-rel-quick" data-rel="nofollow">nofollow</button>
                    </div>
                </div>
            </div>

            <div class="lb-section lb-mode-article">
                <div class="lb-form-row">
                    <label for="lb-modal-image">Select an image (JPG/GIF/PNG)</label>
                    <input type="file" id="lb-modal-image" accept=".jpg,.jpeg,.gif,.png,image/*">
                </div>
                <div class="lb-form-row">
                    <label for="lb-modal-photo-source">Photo source *</label>
                    <select id="lb-modal-photo-source">
                        <option value="own">Own</option>
                        <option value="stock">Stock</option>
                        <option value="publisher">Publisher</option>
                    </select>
                </div>
                <div class="lb-form-row">
                    <label for="lb-modal-attachments">Attachments (JPG/JPEG/PNG/PDF)</label>
                    <input type="file" id="lb-modal-attachments" multiple accept=".jpg,.jpeg,.png,.pdf,image/*,application/pdf">
                </div>
            </div>

            <div class="lb-section lb-mode-article">
                <h4>Linking strategy</h4>
                <div class="lb-form-row">
                    <label for="lb-modal-linking-strategy">Type of linking strategy</label>
                    <select id="lb-modal-linking-strategy">
                        <option value="not_applicable">Not applicable</option>
                        <option value="single_link">Single contextual link</option>
                        <option value="multi_link">Multiple contextual links</option>
                    </select>
                </div>
                <div class="lb-subtle-link">See details</div>
            </div>

            <div class="lb-section lb-mode-article">
                <h4>36 Months Guarantee</h4>
                <div class="lb-modal-toggle">
                    <label><input type="checkbox" id="lb-modal-guarantee-36m"> I want to buy 36 Months Guarantee</label>
                </div>
                <div class="lb-guarantee-note">
                    By purchasing the guarantee, you agree to the terms of the "36 Months Guarantee".
                    <span id="lb-modal-guarantee-cost">Guarantee costs net: calculated at checkout</span>
                </div>
            </div>

            <div class="lb-status" id="lb-order-status">Complete fields and place order.</div>
        </div>
        <div class="lb-modal-foot">
            <button type="button" class="button" id="lb-modal-cancel">Cancel</button>
            <button type="button" class="button" id="lb-save-draft">Save draft</button>
            <button type="button" class="button button-primary" id="lb-place-order">Place order</button>
        </div>
    </div>
</div>

<div class="lb-modal" id="lb-exchange-modal" style="display:none;">
    <div class="lb-modal-backdrop" data-exchange-close="1"></div>
    <div class="lb-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="lb-exchange-modal-title">
        <div class="lb-modal-head">
            <h3 id="lb-exchange-modal-title">Create link exchange request</h3>
            <button type="button" class="lb-modal-close" id="lb-exchange-close">&times;</button>
        </div>
        <div class="lb-modal-body">
            <div class="lb-modal-summary">
                <div><strong>Counterparty</strong><br><span id="lb-exchange-modal-domain">-</span></div>
                <div><strong>Authority bucket</strong><br><span id="lb-exchange-modal-authority">-</span></div>
                <div><strong>Topic overlap</strong><br><span id="lb-exchange-modal-topics">-</span></div>
                <div><strong>Compatibility score</strong><br><span id="lb-exchange-modal-score">-</span></div>
            </div>
            <div class="lb-modal-grid">
                <label for="lb-exchange-requester-target">Your target URL
                    <input type="url" id="lb-exchange-requester-target" placeholder="https://example.com/page-you-want-linked">
                </label>
                <label for="lb-exchange-requester-anchor">Anchor text they should use
                    <input type="text" id="lb-exchange-requester-anchor" placeholder="Preferred anchor text">
                </label>
                <label for="lb-exchange-counterparty-target">Their preferred target URL (optional)
                    <input type="url" id="lb-exchange-counterparty-target" placeholder="https://their-site.com/page">
                </label>
                <label for="lb-exchange-counterparty-anchor">Anchor text you can offer (optional)
                    <input type="text" id="lb-exchange-counterparty-anchor" placeholder="Anchor you will use later">
                </label>
            </div>
            <div class="lb-form-row">
                <label for="lb-exchange-requester-notes">Notes for the counterparty</label>
                <textarea id="lb-exchange-requester-notes" rows="5" placeholder="Short context, proposed timeline, reciprocity notes."></textarea>
            </div>
            <div class="lb-status" id="lb-exchange-modal-status">Fill the request details and send it to the counterparty site.</div>
        </div>
        <div class="lb-modal-foot">
            <button type="button" class="button" id="lb-exchange-cancel">Cancel</button>
            <button type="button" class="button button-primary" id="lb-exchange-send">Send request</button>
        </div>
    </div>
</div>

<style>
.aysa-dashboard-wrapper{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:#333;background:#f8f9fa;padding:20px;min-height:100vh;box-sizing:border-box;max-width:100%;overflow-x:visible}
.aysa-dashboard-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;padding-bottom:15px;border-bottom:1px solid #e0e0e0}
.aysa-dashboard-title h1{font-size:22px;margin:0 0 4px;font-weight:600}
.aysa-dashboard-title p{margin:0;color:#667085}
.aysa-offpage-content{background:#fff;border-radius:10px;box-shadow:0 5px 15px rgba(0,0,0,.08);padding:20px;max-width:100%;overflow-x:visible}
.lb-main-tabs{display:flex;gap:8px;margin-bottom:14px}
.lb-main-tab{border-radius:999px!important;padding:8px 16px!important}
.lb-main-tab.is-active{background:#0b74b5!important;border-color:#0b74b5!important;color:#fff!important}
.lb-headline-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;gap:12px}
.lb-headline-row h3{margin:0;font-size:40px;line-height:1.1;font-weight:650;color:#273447}
.lb-credit-wrap{display:flex;align-items:center;gap:8px}
.lb-credit-pill{display:flex;align-items:center}
.lb-filters-shell{border:1px solid #e4e8ef;border-radius:10px;padding:16px;background:#fbfcfe;margin-bottom:14px}
.lb-filters-shell h4{margin:0 0 12px;font-size:28px;line-height:1.1}
.lb-top-grid{display:grid;grid-template-columns:2fr 1.6fr 1fr;gap:12px;margin-bottom:12px}
.lb-card{border:1px dashed #d2d8e1;border-radius:10px;padding:14px;background:#fff}
.lb-card h5{margin:0 0 6px;font-size:18px;font-weight:700;color:#343b4b}
.lb-card p{margin:0 0 10px;color:#7a8499}
.lb-offer-types{display:flex;flex-wrap:wrap;gap:8px}
.lb-offer-types label{display:flex;gap:8px;align-items:center;border:1px solid #e4e8ef;border-radius:8px;padding:8px 10px;background:#f8fafc;color:#4b5563;font-weight:500}
.lb-note strong{display:block;margin-bottom:6px;font-size:16px}
.lb-note span{color:#667085}
.lb-filter-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:12px}
.lb-filter-grid input,.lb-filter-grid select,.lb-card input{height:40px;border:1px solid #d6dde8;border-radius:8px;padding:0 12px;font-size:14px;color:#3b4256;background:#fff}
.lb-actions-row{display:flex;justify-content:center;gap:10px;flex-wrap:wrap}
.lb-actions-row .button{height:40px;padding:0 18px;border-radius:8px;font-size:13px;text-transform:uppercase;letter-spacing:.02em}
.lb-actions-row .button-primary{background:#1fb587;border-color:#1fb587}
.lb-diagnostics{display:flex;justify-content:space-between;align-items:center;gap:12px;border:1px solid #dbe5f0;border-radius:10px;background:#f8fbff;padding:12px 14px;margin:0 0 12px}
.lb-diagnostics strong{display:block;color:#1f2937}
.lb-diagnostics span{display:block;color:#475467;font-size:13px;margin-top:4px}
.lb-diagnostics.is-error{border-color:#fecaca;background:#fff7f7}
.lb-diagnostics.is-error span{color:#b91c1c}
.lb-diagnostics.is-ok{border-color:#bbf7d0;background:#f0fdf4}
.lb-diagnostics.is-ok span{color:#166534}
.lb-status{margin:8px 0 10px;color:#344054;font-size:13px}
.lb-results-wrap{border:1px solid #e4e8ef;border-radius:10px;overflow-x:auto;overflow-y:visible;background:#fff;max-width:100%}
.lb-table{width:100%;border-collapse:collapse;font-size:13px}
.lb-table th,.lb-table td{border-bottom:1px solid #edf1f6;padding:12px 10px;vertical-align:top}
.lb-table th{background:#f7f9fc;color:#4b5563;font-size:12px;font-weight:700;position:sticky;top:0;z-index:15;white-space:nowrap}
.lb-portal{font-weight:700;color:#c92e52;font-size:17px}
.lb-meta{display:block;color:#6b7280;font-size:14px;margin-top:4px}
.lb-chip{display:inline-block;background:#eef2ff;color:#4f46e5;border-radius:999px;padding:4px 10px;font-size:13px;font-weight:600;margin-right:6px;margin-top:4px}
.lb-badge{display:inline-block;padding:4px 10px;border-radius:999px;font-weight:700;font-size:13px}
.lb-badge.good{background:#dcfce7;color:#15803d}
.lb-badge.warn{background:#fef3c7;color:#b45309}
.lb-badge.bad{background:#fee2e2;color:#b91c1c}
.lb-see-offers{background:#1fb587;color:#fff;border:none;border-radius:8px;padding:8px 14px;font-weight:700;cursor:pointer}
.lb-see-offers.is-disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
.lb-actions-group{display:flex;flex-wrap:wrap;gap:6px}
.lb-price-breakdown{display:flex;flex-direction:column;gap:6px;min-width:220px}
.lb-price-item{display:flex;justify-content:space-between;align-items:center;gap:10px;border:1px solid #e3e8f2;border-radius:8px;padding:6px 8px;background:#f8fbff}
.lb-price-item strong{font-size:11px;color:#475467;text-transform:uppercase;letter-spacing:.02em}
.lb-price-item span{font-weight:700;color:#111827}
.lb-price-item.unavailable{background:#f9fafb;border-color:#eef2f7}
.lb-price-item.unavailable span{color:#9ca3af}
.lb-empty{padding:18px;color:#6b7280}
.lb-modal{position:fixed;inset:0;z-index:99999}
.lb-modal-backdrop{position:absolute;inset:0;background:rgba(15,23,42,.55)}
.lb-modal-dialog{position:relative;background:#fff;max-width:980px;margin:38px auto;border-radius:12px;box-shadow:0 20px 50px rgba(0,0,0,.28);display:flex;flex-direction:column;max-height:calc(100vh - 76px)}
.lb-modal-head{display:flex;align-items:center;justify-content:space-between;padding:16px 18px;border-bottom:1px solid #e5e7eb}
.lb-modal-head h3{margin:0;font-size:22px;line-height:1.2}
.lb-modal-close{background:transparent;border:0;font-size:28px;line-height:1;cursor:pointer;color:#475467}
.lb-modal-body{padding:16px 18px;overflow:auto}
.lb-modal-summary{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;padding:12px;margin-bottom:14px}
.lb-modal-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px}
.lb-modal-grid-single{grid-template-columns:1fr}
.lb-modal-grid label,.lb-modal-grid-single label{display:flex;flex-direction:column;gap:6px;font-weight:600;color:#344054;font-size:13px}
.lb-modal-grid input,.lb-modal-grid select,.lb-modal-grid textarea,.lb-modal-grid-single input,.lb-modal-grid-single textarea{border:1px solid #d0d7e2;border-radius:8px;padding:9px 11px;font-size:14px;font-weight:400;color:#1f2937;background:#fff}
.lb-modal-toggle{margin:8px 0 12px}
.lb-modal-foot{padding:14px 18px;border-top:1px solid #e5e7eb;display:flex;justify-content:flex-end;gap:8px;background:#fbfdff}
.lb-section{border-top:1px dashed #d9deea;padding-top:14px;margin-top:14px}
.lb-section h4{margin:0 0 10px;font-size:18px;color:#273447}
.lb-form-row{display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
.lb-form-row label{font-weight:600;color:#344054;font-size:13px}
.lb-form-row input,.lb-form-row select,.lb-form-row textarea{border:1px solid #d0d7e2;border-radius:8px;padding:9px 11px;font-size:14px}
.lb-form-row small{color:#667085}
.lb-section-grid{display:grid;grid-template-columns:1fr 1.45fr;gap:12px}
.lb-card-panel{border:1px solid #e3e8f2;background:#fbfdff;border-radius:10px;padding:12px}
.lb-card-panel h5{margin:0 0 10px;font-size:15px;color:#273447}
.lb-editor-panel{min-height:100%}
.lb-hint{margin:0 0 8px;color:#667085;font-size:12px}
.lb-template-actions{margin-bottom:8px}
.lb-checklist{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.lb-checklist span{background:#eef4ff;color:#3b4b68;border-radius:999px;padding:4px 9px;font-size:11px;font-weight:600}
.lb-checklist span:first-child{background:transparent;color:#667085;padding:4px 0;border-radius:0}
.lb-links-block{display:grid;grid-template-columns:2fr 1fr;gap:12px}
.lb-links-side{border:1px solid #dbe1ee;border-radius:8px;background:#f8fafc;padding:10px}
.lb-links-side ul{margin:8px 0;padding-left:18px}
.lb-mini-actions{display:flex;gap:8px;flex-wrap:wrap}
.lb-mini-actions .button{height:30px;border-radius:16px}
.lb-subtle-link{color:#d83d67;font-weight:600;font-size:12px;text-align:right}
.lb-guarantee-note{display:flex;justify-content:space-between;align-items:center;gap:10px;font-size:13px;color:#475467;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:10px}
.lb-guarantee-note span{font-weight:700;color:#697386}
.lb-pill-group{display:flex;gap:8px;flex-wrap:wrap}
.lb-pill-btn{border:1px solid #3bbf95!important;color:#16996f!important;border-radius:18px!important;background:#fff!important}
.lb-pill-btn.is-active{background:#e9fff7!important}
.lb-pill-btn.is-disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
.lb-tab-price{display:inline-block;margin-left:6px;padding:1px 7px;border-radius:999px;background:#e8f6ef;color:#0f7a56;font-size:11px;font-weight:700}
.lb-hidden{display:none!important}
.lb-mode-link-grid{display:grid;grid-template-columns:1.25fr 1fr;gap:12px}
.lb-li-suggestions{border:1px solid #dbe2ef;border-radius:8px;max-height:260px;overflow:auto;background:#fff}
.lb-li-empty{padding:10px 12px;color:#667085;font-size:12px}
.lb-li-item{padding:10px 12px;border-bottom:1px solid #eef2f7;cursor:pointer}
.lb-li-item:last-child{border-bottom:none}
.lb-li-item:hover{background:#f8fbff}
.lb-li-item.is-selected{background:#eaf4ff}
.lb-li-item strong{display:block;font-size:13px;color:#1f2937}
.lb-li-item span{display:block;font-size:11px;color:#667085}
.lb-ads-preview{margin-top:10px;border:1px solid #dbe2ef;border-radius:12px;padding:12px 14px;background:#f8fbff}
.lb-ads-badge{display:inline-block;border:2px solid #16803c;color:#16803c;border-radius:8px;padding:2px 8px;font-weight:700;font-size:14px}
.lb-ads-title{margin-top:8px;color:#1a0dab;font-size:20px;font-weight:500;line-height:1.25}
.lb-ads-url{margin-top:4px;color:#14753f;font-size:20px;line-height:1.2}
.lb-ads-desc{margin-top:8px;color:#454b54;font-size:16px;line-height:1.35}
.lb-mode-seoads .lb-form-row{margin-bottom:8px}
.lb-mode-seoads .lb-card-panel{padding:10px}
.lb-issue-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:700;white-space:nowrap}
.lb-issue-badge.is-error{background:#fde8e8;color:#b42318;border:1px solid #f8b4b4}
.lb-issue-badge.is-warning{background:#fff4e5;color:#b54708;border:1px solid #fbd38d}
.lb-issue-badge.is-ok{background:#ecfdf3;color:#027a48;border:1px solid #a6f4c5}
.lb-issue-text{font-size:12px;line-height:1.35;color:#344054;max-width:520px}
.lb-audit-cards{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:10px;margin:10px 0 14px}
.lb-audit-card{background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:12px 14px;display:flex;flex-direction:column;gap:6px}
.lb-audit-card strong{font-size:24px;line-height:1;color:#0f172a}
.lb-audit-card span{font-size:12px;color:#667085}
.lb-audit-filters{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin:0 0 12px}
.lb-audit-filters select,.lb-audit-filters input{width:100%;min-height:38px}
.lb-risk-cell{display:flex;flex-direction:column;gap:6px}
.lb-mini-meta{font-size:11px;color:#64748b}
.lb-table-audit{min-width:2050px}
.lb-table-audit td,.lb-table-audit th{white-space:nowrap}
.lb-table-audit td:nth-child(2),.lb-table-audit td:nth-child(3){max-width:320px;white-space:normal;word-break:break-word}
.lb-table-audit td:nth-child(4){max-width:220px;white-space:normal;word-break:break-word}
.lb-draft-preview{margin-top:16px;border:1px solid #dbe2ef;border-radius:12px;background:#fff;padding:18px}
.lb-draft-preview-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.lb-draft-preview-meta{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:12px}
.lb-draft-preview-meta div{background:#f8fbff;border:1px solid #e2e8f0;border-radius:10px;padding:10px 12px}
.lb-draft-preview-links{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px}
.lb-draft-preview-links a{display:inline-flex;align-items:center;gap:6px;background:#eef4ff;color:#244aa5;border-radius:999px;padding:6px 10px;text-decoration:none}
.lb-draft-preview-form{display:grid;gap:12px;margin-bottom:14px}
.lb-draft-preview-form textarea,.lb-draft-preview-form input{width:100%;border:1px solid #d0d7e2;border-radius:8px;padding:9px 11px;font-size:14px;background:#fff}
.lb-draft-preview-body{border-top:1px solid #eef2f7;padding-top:14px;color:#243244}
.lb-draft-preview-body h1,.lb-draft-preview-body h2,.lb-draft-preview-body h3{color:#102a43}
.lb-mini-button{height:30px!important;border-radius:16px!important;padding:0 12px!important}
.lb-exchange-profile{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:0 0 12px}
.lb-exchange-profile-card{background:#f8fbff;border:1px solid #dbe5f0;border-radius:10px;padding:12px 14px}
.lb-exchange-profile-card strong{display:block;font-size:12px;color:#667085;margin-bottom:6px;text-transform:uppercase}
.lb-exchange-profile-card span{display:block;font-size:15px;color:#111827;font-weight:700}
.lb-exchange-compat{display:flex;flex-direction:column;gap:6px;min-width:220px}
.lb-exchange-compat .lb-chip{margin:0}
.lb-exchange-detail{margin-top:16px;border:1px solid #dbe2ef;border-radius:12px;background:#fff;padding:18px}
.lb-exchange-timeline{display:grid;gap:10px;padding:12px}
.lb-exchange-timeline-item{border:1px solid #e5e7eb;border-radius:10px;padding:10px 12px;background:#fbfdff}
.lb-exchange-timeline-item strong{display:block;margin-bottom:4px;color:#102a43}
.lb-exchange-timeline-item span{font-size:12px;color:#667085}
@media (max-width:1600px){.lb-audit-cards{grid-template-columns:repeat(4,minmax(0,1fr))}.lb-audit-filters{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:1400px){.lb-audit-cards{grid-template-columns:repeat(3,minmax(0,1fr))}.lb-audit-filters{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:1200px){.lb-top-grid{grid-template-columns:1fr}.lb-filter-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.lb-headline-row h3{font-size:28px}.lb-audit-cards{grid-template-columns:repeat(2,minmax(0,1fr))}.lb-draft-preview-meta{grid-template-columns:1fr}.lb-exchange-profile{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:700px){.lb-audit-filters{grid-template-columns:1fr}.lb-diagnostics{flex-direction:column;align-items:flex-start}}
@media (max-width:782px){.lb-filter-grid{grid-template-columns:1fr}.lb-headline-row{align-items:flex-start;flex-direction:column}.lb-modal-summary{grid-template-columns:1fr}.lb-modal-grid{grid-template-columns:1fr}.lb-modal-dialog{margin:10px}.lb-section-grid{grid-template-columns:1fr}.lb-links-block{grid-template-columns:1fr}.lb-mode-link-grid{grid-template-columns:1fr}.lb-guarantee-note{flex-direction:column;align-items:flex-start}}
</style>

<script type="text/javascript">
(function () {
function initAysaOffPageOptimization() {
    const nonce = (window.aysa_ajax && window.aysa_ajax.nonce) ? window.aysa_ajax.nonce : '';
    const projectId = (window.aysa_ajax && window.aysa_ajax.project_id) ? String(window.aysa_ajax.project_id) : ((window.aysa_params && window.aysa_params.project_id) ? String(window.aysa_params.project_id) : '');
    const publisherArticlesRefreshTimers = { draft: null, published: null };

        const state = {
        portals: [],
        filtered: [],
        orders: [],
        publisherDrafts: [],
        publisherPublished: [],
        currentPublisherDraft: null,
        linkIssues: [],
        backlinkAuditItems: [],
        selected: null,
        exchangePortals: [],
        exchangeFiltered: [],
        exchangeRequests: [],
            exchangeSelectedPortal: null,
            currentExchangeRequest: null,
            exchangeProfile: null,
            exchangeActivationCandidates: [],
            availableCredits: 0,
        includedLinksRemaining: 0,
        marketplaceDiagnostics: null,
        orderMode: 'add_new_article',
        contentEditorReady: false,
        linkTargets: [],
        selectedLinkTarget: null,
        seoAdsTargets: [],
        selectedSeoAdsTarget: null,
        gbp: {
            overview: null,
            currentJob: null,
            pollTimer: null
        }
    };

    function esc(v) {
        return String(v === undefined || v === null ? '' : v)
            .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;').replace(/'/g, '&#039;');
    }

    function findFirstStringByKeysDeep(node, keys, depth) {
        const maxDepth = 8;
        const d = Number.isFinite(depth) ? depth : 0;
        if (d > maxDepth || !node || typeof node !== 'object') return '';
        for (let i = 0; i < keys.length; i++) {
            const k = keys[i];
            if (Object.prototype.hasOwnProperty.call(node, k) && node[k] !== null && node[k] !== undefined) {
                const val = String(node[k]).trim();
                if (val !== '') return val;
            }
        }
        const values = Array.isArray(node) ? node : Object.values(node);
        for (let i = 0; i < values.length; i++) {
            const v = values[i];
            if (v && typeof v === 'object') {
                const found = findFirstStringByKeysDeep(v, keys, d + 1);
                if (found) return found;
            }
        }
        return '';
    }

    function collectUrlsDeep(node, out, depth) {
        const maxDepth = 10;
        const d = Number.isFinite(depth) ? depth : 0;
        if (d > maxDepth || !node || typeof node !== 'object') return;
        const values = Array.isArray(node) ? node : Object.values(node);
        for (let i = 0; i < values.length; i++) {
            const v = values[i];
            if (typeof v === 'string') {
                const s = v.trim();
                if (/^https?:\/\/[^\s]+$/i.test(s)) {
                    out.add(s);
                }
            } else if (v && typeof v === 'object') {
                collectUrlsDeep(v, out, d + 1);
            }
        }
    }

    function extractPublishedDetails(order) {
        const out = {
            sourceUrl: '',
            targetUrl: '',
            publishedKeyword: ''
        };
        if (!order || typeof order !== 'object') return out;
        const portalDomain = String(order.portal_domain || '').trim().toLowerCase();

        const sources = [];
        if (order.raw_track && typeof order.raw_track === 'object') sources.push(order.raw_track);
        if (order.raw_response && typeof order.raw_response === 'object') sources.push(order.raw_response);

        for (let i = 0; i < sources.length; i++) {
            const src = sources[i];
            if (!out.sourceUrl) {
                out.sourceUrl = findFirstStringByKeysDeep(src, [
                    'published_url', 'publishedUrl', 'insertion_url', 'insertionUrl',
                    'article_url', 'articleUrl', 'placement_url', 'placementUrl',
                    'source_url', 'sourceUrl', 'published_on_url', 'publishedOnUrl'
                ], 0);
            }
            if (!out.targetUrl) {
                out.targetUrl = findFirstStringByKeysDeep(src, [
                    'target_url', 'targetUrl', 'link_to', 'linkTo',
                    'destination_url', 'destinationUrl'
                ], 0);
            }
            if (!out.publishedKeyword) {
                out.publishedKeyword = findFirstStringByKeysDeep(src, [
                    'published_keyword', 'publishedKeyword', 'anchor', 'anchor_text',
                    'anchorText', 'keyword'
                ], 0);
            }

            // Timeline-specific extraction (LINK_ACTIVATED / LINK_VERIFIED_OK / ORDER_COMPLETED_BY_CRAWLER)
            if (!out.sourceUrl && src.timeline && Array.isArray(src.timeline)) {
                for (let t = 0; t < src.timeline.length; t++) {
                    const ev = src.timeline[t];
                    const evType = String((ev && (ev.event_type || ev.type || ev.name)) || '').toUpperCase();
                    if (evType.indexOf('LINK_') === -1 && evType.indexOf('COMPLETED') === -1) continue;
                    const candidate = findFirstStringByKeysDeep(ev, [
                        'published_url', 'publishedUrl', 'insertion_url', 'insertionUrl',
                        'article_url', 'articleUrl', 'placement_url', 'placementUrl',
                        'source_url', 'sourceUrl', 'url'
                    ], 0);
                    if (candidate) {
                        out.sourceUrl = candidate;
                        break;
                    }
                }
            }

            if (out.sourceUrl && out.targetUrl && out.publishedKeyword) break;
        }

        if (!out.targetUrl) out.targetUrl = String(order.target_url || '').trim();
        if (!out.publishedKeyword) out.publishedKeyword = String(order.keyword || '').trim();

        // Smart fallback: when API has no explicit published URL, pick best URL from payload on portal domain, different from target.
        if (!out.sourceUrl) {
            const allUrls = new Set();
            for (let i = 0; i < sources.length; i++) {
                collectUrlsDeep(sources[i], allUrls, 0);
            }
            const targetNorm = String(out.targetUrl || '').trim().toLowerCase();
            let best = '';
            allUrls.forEach(function (u) {
                const ul = String(u || '').trim();
                if (!ul) return;
                const ulc = ul.toLowerCase();
                if (targetNorm && ulc === targetNorm) return;
                if (portalDomain && ulc.indexOf(portalDomain) !== -1) {
                    if (!best) best = ul;
                }
            });
            if (!best) {
                // last fallback: any URL different from target
                allUrls.forEach(function (u) {
                    const ul = String(u || '').trim();
                    if (!ul) return;
                    const ulc = ul.toLowerCase();
                    if (targetNorm && ulc === targetNorm) return;
                    if (!best) best = ul;
                });
            }
            if (best) out.sourceUrl = best;
        }

        return out;
    }

    function setStatus(msg, isError) {
        const el = document.getElementById('lb-status');
        el.textContent = msg;
        el.style.color = isError ? '#b91c1c' : '#344054';
    }

    function setDiagnosticsStatus(msg, isError, isOk) {
        const wrap = document.getElementById('lb-marketplace-diagnostics');
        const el = document.getElementById('lb-marketplace-diagnostics-status');
        if (!wrap || !el) return;
        el.textContent = msg;
        wrap.classList.toggle('is-error', !!isError);
        wrap.classList.toggle('is-ok', !!isOk && !isError);
    }

    function ajaxErrorMessage(resp, fallback) {
        if (!resp || resp.success) return fallback || 'Request failed.';
        const payload = resp.data;
        if (typeof payload === 'string' && payload.trim() !== '') return payload.trim();
        if (payload && typeof payload === 'object') {
            if (payload.message && String(payload.message).trim() !== '') return String(payload.message).trim();
            if (payload.code && String(payload.code).trim() !== '') return String(payload.code).trim();
        }
        return fallback || 'Request failed.';
    }

    function setOrderStatus(msg, isError) {
        const el = document.getElementById('lb-order-status');
        el.textContent = msg;
        el.style.color = isError ? '#b91c1c' : '#344054';
    }

    function setLinkIssuesStatus(msg, isError) {
        const el = document.getElementById('lb-link-issues-status');
        if (!el) return;
        el.textContent = msg;
        el.style.color = isError ? '#b91c1c' : '#344054';
    }

    function setPublisherArticlesStatus(kind, msg, isError) {
        const id = kind === 'published' ? 'lb-published-articles-status' : 'lb-draft-articles-status';
        const el = document.getElementById(id);
        if (!el) return;
        el.textContent = msg;
        el.style.color = isError ? '#b91c1c' : '#344054';
    }

    function initContentEditor() {
        if (state.contentEditorReady) return;
        if (!window.wp || !window.wp.editor || !document.getElementById('lb-modal-content')) return;
        try {
            window.wp.editor.initialize('lb-modal-content', {
                tinymce: {
                    wpautop: true,
                    toolbar1: 'formatselect,bold,italic,bullist,numlist,blockquote,link,unlink,undo,redo',
                    toolbar2: 'h2,h3,pastetext,removeformat'
                },
                quicktags: true,
                mediaButtons: false
            });
            state.contentEditorReady = true;
        } catch (e) {
            if (window.AYSA_DEBUG === true) {
                console.warn('Content editor init failed', e);
            }
        }
    }

    function getContentValue() {
        if (window.tinyMCE && window.tinyMCE.get) {
            const editor = window.tinyMCE.get('lb-modal-content');
            if (editor) return (editor.getContent({ format: 'raw' }) || '').trim();
        }
        const raw = document.getElementById('lb-modal-content').value || '';
        return raw.trim();
    }

    function setContentValue(v) {
        const value = String(v || '');
        const textarea = document.getElementById('lb-modal-content');
        if (textarea) textarea.value = value;
        if (window.tinyMCE && window.tinyMCE.get) {
            const editor = window.tinyMCE.get('lb-modal-content');
            if (editor) editor.setContent(value);
        }
    }

    function generateClientRef(prefix) {
        const p = String(prefix || 'AYSA');
        const now = new Date();
        const pad = function(n){ return String(n).padStart(2, '0'); };
        const ts = now.getFullYear() + pad(now.getMonth() + 1) + pad(now.getDate()) + pad(now.getHours()) + pad(now.getMinutes()) + pad(now.getSeconds());
        const rnd = Math.random().toString(36).slice(2, 8).toUpperCase();
        return p + '-' + String(projectId || '0') + '-' + ts + '-' + rnd;
    }

    function updateSeoAdsPreview() {
        const title = (document.getElementById('lb-ads-title').value || '').trim();
        const displayUrl = (document.getElementById('lb-ads-display-url').value || '').trim();
        const desc = (document.getElementById('lb-ads-description').value || '').trim();
        const titleEl = document.getElementById('lb-ads-preview-title');
        const urlEl = document.getElementById('lb-ads-preview-url');
        const descEl = document.getElementById('lb-ads-preview-desc');
        if (titleEl) titleEl.textContent = title || 'SEO text ads title preview';
        if (urlEl) urlEl.textContent = displayUrl || 'https://example.com/path';
        const shortDesc = desc.length > 90 ? (desc.slice(0, 90) + '...') : desc;
        if (descEl) descEl.textContent = shortDesc || 'Short text preview appears here (max 90 characters).';
    }

    function getDraftPayload() {
        const contentRaw = getContentValue();
        return {
            mode: state.orderMode || 'add_new_article',
            target_url: (document.getElementById('lb-modal-target').value || '').trim(),
            keyword: (document.getElementById('lb-modal-keyword').value || '').trim(),
            title: (document.getElementById('lb-modal-title').value || '').trim(),
            lead: (document.getElementById('lb-modal-lead').value || '').trim(),
            content_html: contentRaw,
            remarks: (document.getElementById('lb-modal-remarks').value || '').trim(),
            rel_type: document.getElementById('lb-modal-rel-type').value || 'follow',
            billing_type: document.getElementById('lb-modal-billing-type').value || 'one_time',
            photo_source: document.getElementById('lb-modal-photo-source').value || 'own',
            linking_strategy: document.getElementById('lb-modal-linking-strategy').value || 'not_applicable',
            guarantee_36m: document.getElementById('lb-modal-guarantee-36m').checked ? 1 : 0,
            li_keyword: (document.getElementById('lb-li-keyword').value || '').trim(),
            li_target_search: (document.getElementById('lb-li-target-search').value || '').trim(),
            li_target_url: (document.getElementById('lb-li-target-url').value || '').trim(),
            li_target_title: (document.getElementById('lb-li-target-title').value || '').trim(),
            li_target_meta: (document.getElementById('lb-li-target-meta').value || '').trim(),
            li_rel_type: document.getElementById('lb-li-rel-type').value || 'follow',
            li_billing_type: document.getElementById('lb-li-billing-type').value || 'one_time',
            li_remarks: (document.getElementById('lb-li-remarks').value || '').trim(),
            ads_title: (document.getElementById('lb-ads-title').value || '').trim(),
            ads_keyword: (document.getElementById('lb-ads-keyword').value || '').trim(),
            ads_target_search: (document.getElementById('lb-ads-target-search').value || '').trim(),
            ads_target_url: (document.getElementById('lb-ads-target-url').value || '').trim(),
            ads_display_url: (document.getElementById('lb-ads-display-url').value || '').trim(),
            ads_target_article_url: (document.getElementById('lb-ads-target-article-url').value || '').trim(),
            ads_description: (document.getElementById('lb-ads-description').value || '').trim(),
            ads_duration_months: (document.getElementById('lb-ads-duration-months').value || '1').trim(),
            ads_remarks: (document.getElementById('lb-ads-remarks').value || '').trim()
        };
    }

    function applyDraftPayload(draft) {
        if (!draft || typeof draft !== 'object') return;
        if (draft.mode) setOrderMode(String(draft.mode));
        if (draft.target_url) document.getElementById('lb-modal-target').value = String(draft.target_url);
        if (draft.keyword) document.getElementById('lb-modal-keyword').value = String(draft.keyword);
        if (draft.title) document.getElementById('lb-modal-title').value = String(draft.title);
        if (draft.lead) document.getElementById('lb-modal-lead').value = String(draft.lead);
        if (draft.content_html) setContentValue(String(draft.content_html));
        if (draft.remarks) document.getElementById('lb-modal-remarks').value = String(draft.remarks);
        if (draft.rel_type) document.getElementById('lb-modal-rel-type').value = String(draft.rel_type);
        if (draft.billing_type) document.getElementById('lb-modal-billing-type').value = String(draft.billing_type);
        if (draft.photo_source) document.getElementById('lb-modal-photo-source').value = String(draft.photo_source);
        if (draft.linking_strategy) document.getElementById('lb-modal-linking-strategy').value = String(draft.linking_strategy);
        if (String(draft.guarantee_36m) === '1' || draft.guarantee_36m === true) {
            document.getElementById('lb-modal-guarantee-36m').checked = true;
        }
        if (draft.li_keyword) document.getElementById('lb-li-keyword').value = String(draft.li_keyword);
        if (draft.li_rel_type) document.getElementById('lb-li-rel-type').value = String(draft.li_rel_type);
        if (draft.li_billing_type) document.getElementById('lb-li-billing-type').value = String(draft.li_billing_type);
        if (draft.li_remarks) document.getElementById('lb-li-remarks').value = String(draft.li_remarks);
        if (draft.li_target_url) document.getElementById('lb-li-target-url').value = String(draft.li_target_url);
        if (draft.li_target_title) document.getElementById('lb-li-target-title').value = String(draft.li_target_title);
        if (draft.li_target_meta) document.getElementById('lb-li-target-meta').value = String(draft.li_target_meta);
        if (draft.li_target_search) document.getElementById('lb-li-target-search').value = String(draft.li_target_search);
        if (draft.ads_title) document.getElementById('lb-ads-title').value = String(draft.ads_title);
        if (draft.ads_keyword) document.getElementById('lb-ads-keyword').value = String(draft.ads_keyword);
        if (draft.ads_target_search) document.getElementById('lb-ads-target-search').value = String(draft.ads_target_search);
        if (draft.ads_target_url) document.getElementById('lb-ads-target-url').value = String(draft.ads_target_url);
        if (draft.ads_display_url) document.getElementById('lb-ads-display-url').value = String(draft.ads_display_url);
        if (draft.ads_target_article_url) document.getElementById('lb-ads-target-article-url').value = String(draft.ads_target_article_url);
        if (draft.ads_description) document.getElementById('lb-ads-description').value = String(draft.ads_description);
        if (draft.ads_duration_months) document.getElementById('lb-ads-duration-months').value = String(draft.ads_duration_months);
        if (draft.ads_remarks) document.getElementById('lb-ads-remarks').value = String(draft.ads_remarks);
        updateSeoAdsPreview();
    }

    function updateModeUi() {
        const isLinkInsertion = state.orderMode === 'link_insertion';
        const isSeoAds = state.orderMode === 'seo_text_ads';
        const isArticleMode = !isLinkInsertion && !isSeoAds;
        const modalTitle = document.getElementById('lb-article-modal-title');
        const serviceName = document.getElementById('lb-modal-service-name');
        document.querySelectorAll('.lb-mode-article').forEach(function (el) {
            el.classList.toggle('lb-hidden', !isArticleMode);
        });
        document.querySelectorAll('.lb-mode-linkinsert').forEach(function (el) {
            el.classList.toggle('lb-hidden', !isLinkInsertion);
        });
        document.querySelectorAll('.lb-mode-seoads').forEach(function (el) {
            el.classList.toggle('lb-hidden', !isSeoAds);
        });
        if (modalTitle) {
            modalTitle.textContent = isLinkInsertion
                ? 'Order link placement'
                : (isSeoAds ? 'Order SEO text ads' : 'Order sponsored article');
        }
        if (serviceName) {
            serviceName.textContent = isLinkInsertion
                ? 'Link placement'
                : (isSeoAds ? 'SEO text ads' : 'Sponsored article');
        }
        const placeBtn = document.getElementById('lb-place-order');
        if (placeBtn) {
            placeBtn.textContent = isLinkInsertion
                ? 'Place link placement order'
                : (isSeoAds ? 'Place SEO text ads order' : 'Place sponsored article order');
        }
        updateModePricesUi();
    }

    function setOrderMode(mode) {
        const allowed = ['add_new_article', 'link_insertion', 'seo_text_ads'];
        state.orderMode = allowed.indexOf(mode) !== -1 ? mode : 'add_new_article';
        document.querySelectorAll('.lb-order-tab').forEach(function (btn) {
            const isActive = btn.getAttribute('data-mode') === state.orderMode;
            btn.classList.toggle('is-active', isActive);
        });
        updateModeUi();
        if (state.orderMode === 'link_insertion') {
            const keyword = (document.getElementById('lb-li-keyword').value || '').trim();
            if (keyword.length >= 2) {
                loadLinkTargetsFromKeyword(keyword);
            }
        }
        if (state.orderMode === 'seo_text_ads') {
            const keyword = (document.getElementById('lb-ads-keyword').value || '').trim();
            if (keyword.length >= 2) {
                loadSeoAdsTargetsFromKeyword(keyword);
            }
        }
    }

    function clearSelectedLinkTarget() {
        state.selectedLinkTarget = null;
        document.getElementById('lb-li-target-url').value = '';
        document.getElementById('lb-li-target-title').value = '';
        document.getElementById('lb-li-target-meta').value = '';
    }

    function applySelectedLinkTarget(item) {
        state.selectedLinkTarget = item || null;
        if (!item) {
            clearSelectedLinkTarget();
            return;
        }
        const entityType = String(item.entity_type || '').toUpperCase();
        document.getElementById('lb-li-target-url').value = String(item.url || '');
        document.getElementById('lb-li-target-title').value = String(item.title || '');
        document.getElementById('lb-li-target-meta').value = [entityType, item.keyword || '']
            .filter(Boolean)
            .join(' | ');
        document.getElementById('lb-li-target-search').value = String(item.title || item.url || '');
    }

    function renderLinkTargets() {
        const wrap = document.getElementById('lb-li-suggestions');
        const items = Array.isArray(state.linkTargets) ? state.linkTargets : [];
        if (!items.length) {
            wrap.innerHTML = '<div class="lb-li-empty">No matching targets for this keyword.</div>';
            return;
        }
        const selectedUrl = state.selectedLinkTarget && state.selectedLinkTarget.url ? String(state.selectedLinkTarget.url) : '';
        wrap.innerHTML = items.map(function (item, idx) {
            const isSelected = selectedUrl !== '' && String(item.url || '') === selectedUrl;
            return '<div class="lb-li-item ' + (isSelected ? 'is-selected' : '') + '" data-li-index="' + idx + '">' +
                '<strong>' + esc(item.title || item.url || '-') + '</strong>' +
                '<span>' + esc(item.url || '-') + '</span>' +
                '<span>' + esc(String(item.entity_type || '').toUpperCase()) + ' | ' + esc(item.keyword || '-') + '</span>' +
            '</div>';
        }).join('');
    }

    function clearSelectedSeoAdsTarget() {
        state.selectedSeoAdsTarget = null;
        document.getElementById('lb-ads-target-url').value = '';
    }

    function applySelectedSeoAdsTarget(item) {
        state.selectedSeoAdsTarget = item || null;
        if (!item) {
            clearSelectedSeoAdsTarget();
            return;
        }
        document.getElementById('lb-ads-target-url').value = String(item.url || '');
        document.getElementById('lb-ads-target-search').value = String(item.title || item.url || '');
    }

    function renderSeoAdsTargets() {
        const wrap = document.getElementById('lb-ads-suggestions');
        const items = Array.isArray(state.seoAdsTargets) ? state.seoAdsTargets : [];
        if (!items.length) {
            wrap.innerHTML = '<div class="lb-li-empty">No matching destination pages for this keyword.</div>';
            return;
        }
        const selectedUrl = state.selectedSeoAdsTarget && state.selectedSeoAdsTarget.url ? String(state.selectedSeoAdsTarget.url) : '';
        wrap.innerHTML = items.map(function (item, idx) {
            const isSelected = selectedUrl !== '' && String(item.url || '') === selectedUrl;
            return '<div class="lb-li-item ' + (isSelected ? 'is-selected' : '') + '" data-ads-index="' + idx + '">' +
                '<strong>' + esc(item.title || item.url || '-') + '</strong>' +
                '<span>' + esc(item.url || '-') + '</span>' +
                '<span>' + esc(String(item.entity_type || '').toUpperCase()) + ' | ' + esc(item.keyword || '-') + '</span>' +
            '</div>';
        }).join('');
    }

    function loadSeoAdsTargetsFromKeyword(forceKeyword) {
        const keyword = (forceKeyword !== undefined ? String(forceKeyword) : (document.getElementById('lb-ads-keyword').value || '')).trim();
        clearSelectedSeoAdsTarget();
        if (keyword.length < 2) {
            state.seoAdsTargets = [];
            renderSeoAdsTargets();
            return;
        }
        const targetSearch = (document.getElementById('lb-ads-target-search').value || '').trim().toLowerCase();
        postAjax('aysa_adverlink_search_link_targets', {
            project_id: projectId,
            q: keyword,
            limit: 50
        }).then(function (resp) {
            if (!resp || !resp.success) {
                state.seoAdsTargets = [];
                renderSeoAdsTargets();
                setOrderStatus((resp && resp.data) ? String(resp.data) : 'Destination lookup failed.', true);
                return;
            }
            let items = (resp.data && Array.isArray(resp.data.items)) ? resp.data.items : [];
            if (targetSearch) {
                items = items.filter(function (item) {
                    const haystack = [item.title || '', item.url || '', item.keyword || '', item.entity_type || ''].join(' ').toLowerCase();
                    return haystack.indexOf(targetSearch) !== -1;
                });
            }
            state.seoAdsTargets = items;
            renderSeoAdsTargets();
            if (items.length === 1) {
                applySelectedSeoAdsTarget(items[0]);
            }
        }).catch(function (err) {
            state.seoAdsTargets = [];
            renderSeoAdsTargets();
            setOrderStatus(err && err.message ? err.message : 'Destination lookup failed.', true);
        });
    }

    let linkTargetSearchTimer = null;
    function loadLinkTargetsFromKeyword(forceKeyword) {
        const keyword = (forceKeyword !== undefined ? String(forceKeyword) : (document.getElementById('lb-li-keyword').value || '')).trim();
        clearSelectedLinkTarget();
        if (keyword.length < 2) {
            state.linkTargets = [];
            renderLinkTargets();
            return;
        }
        const targetSearch = (document.getElementById('lb-li-target-search').value || '').trim().toLowerCase();
        postAjax('aysa_adverlink_search_link_targets', {
            project_id: projectId,
            q: keyword,
            limit: 50
        }).then(function (resp) {
            if (!resp || !resp.success) {
                state.linkTargets = [];
                renderLinkTargets();
                setOrderStatus((resp && resp.data) ? String(resp.data) : 'Target lookup failed.', true);
                return;
            }
            let items = (resp.data && Array.isArray(resp.data.items)) ? resp.data.items : [];
            if (targetSearch) {
                items = items.filter(function (item) {
                    const haystack = [
                        item.title || '',
                        item.url || '',
                        item.keyword || '',
                        item.entity_type || ''
                    ].join(' ').toLowerCase();
                    return haystack.indexOf(targetSearch) !== -1;
                });
            }
            state.linkTargets = items;
            renderLinkTargets();
            if (items.length === 1) {
                applySelectedLinkTarget(items[0]);
            }
        }).catch(function (err) {
            state.linkTargets = [];
            renderLinkTargets();
            setOrderStatus(err && err.message ? err.message : 'Target lookup failed.', true);
        });
    }

    function loadDraftForSelectedPortal() {
        if (!state.selected) return;
        const portalId = state.selected.portal_id || state.selected.id || '';
        if (!portalId) return;
        postAjax('aysa_adverlink_get_article_draft', {
            project_id: projectId,
            portal_id: portalId
        }).then(function (resp) {
            if (!resp || !resp.success || !resp.data || !resp.data.draft) return;
            const d = resp.data.draft;
            applyDraftPayload(d);
            if (d.li_target_url) {
                state.selectedLinkTarget = {
                    url: String(d.li_target_url || ''),
                    title: String(d.li_target_title || ''),
                    keyword: String(d.li_keyword || ''),
                    entity_type: ''
                };
            }
            if (d.ads_target_url) {
                state.selectedSeoAdsTarget = {
                    url: String(d.ads_target_url || ''),
                    title: '',
                    keyword: String(d.ads_keyword || ''),
                    entity_type: ''
                };
            }
            renderLinkTargets();
            renderSeoAdsTargets();
            setOrderStatus('Draft loaded for this portal.', false);
        });
    }

    function postAjax(action, payload) {
        const p = new URLSearchParams();
        p.append('action', action);
        p.append('nonce', nonce);
        Object.keys(payload || {}).forEach(function (k) {
            if (payload[k] !== undefined && payload[k] !== null) p.append(k, String(payload[k]));
        });
        return fetch(ajaxurl, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
            body: p.toString()
        }).then(function (r) { return r.json(); });
    }

    function postAsyncAjax(task, payload, attemptsLeft) {
        const tries = typeof attemptsLeft === 'number' ? attemptsLeft : 40;
        return postAjax('aysa_offpage_async_start', Object.assign({ task: task }, payload || {}))
            .then(function (resp) {
                if (!resp || !resp.success) {
                    throw new Error(ajaxErrorMessage(resp, 'Off-page action failed.'));
                }
                const data = resp.data || {};
                if (data.status === 'completed' && data.result) {
                    return { success: true, data: data.result };
                }
                return pollOffpageAsyncStatus(task, tries);
            });
    }

    function pollOffpageAsyncStatus(task, attemptsLeft) {
        return postAjax('aysa_offpage_async_status', {
            task: task,
            project_id: projectId
        }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Off-page status failed.'));
            }
            const data = resp.data || {};
            if (data.status === 'completed' && data.result) {
                return { success: true, data: data.result };
            }
            if (data.status === 'failed') {
                throw new Error(String(data.error || 'Off-page worker failed.'));
            }
            if ((attemptsLeft || 0) <= 0) {
                throw new Error('Off-page worker timed out.');
            }
            return new Promise(function (resolve, reject) {
                window.setTimeout(function () {
                    pollOffpageAsyncStatus(task, (attemptsLeft || 0) - 1).then(resolve).catch(reject);
                }, 3000);
            });
        });
    }

    function loadMarketplaceDiagnostics() {
        setDiagnosticsStatus('Checking credentials and upstream connectivity...', false, false);
        return postAjax('aysa_adverlink_marketplace_diagnostics', {
            project_id: projectId
        }).then(function (resp) {
            if (!resp || !resp.success) {
                const payload = resp && resp.data && typeof resp.data === 'object' ? resp.data : {};
                state.marketplaceDiagnostics = payload;
                const parts = [];
                if (payload.message) parts.push(String(payload.message));
                if (payload.credential_type) parts.push('Credential: ' + String(payload.credential_type));
                if (payload.upstream_base_url) parts.push('Upstream: ' + String(payload.upstream_base_url));
                setDiagnosticsStatus(parts.join(' | ') || ajaxErrorMessage(resp, 'Marketplace diagnostics failed.'), true, false);
                return;
            }
            state.marketplaceDiagnostics = resp.data || {};
            const payload = resp.data || {};
            const parts = ['Marketplace ready'];
            if (payload.credential_type) parts.push('Credential: ' + String(payload.credential_type));
            if (payload.provider_status) parts.push('HTTP ' + String(payload.provider_status));
            if (payload.upstream_base_url) parts.push(String(payload.upstream_base_url));
            setDiagnosticsStatus(parts.join(' | '), false, true);
        }).catch(function (err) {
            setDiagnosticsStatus(err && err.message ? err.message : 'Marketplace diagnostics failed.', true, false);
        });
    }

    function setExchangeStatus(message, isError) {
        const el = document.getElementById('lb-exchange-status');
        if (!el) return;
        el.textContent = message || '';
        el.style.color = isError ? '#b42318' : '#344054';
    }

    function setExchangeRequestsStatus(message, isError) {
        const el = document.getElementById('lb-exchange-requests-status');
        if (!el) return;
        el.textContent = message || '';
        el.style.color = isError ? '#b42318' : '#344054';
    }

    function renderExchangeProfile(profile) {
        const wrap = document.getElementById('lb-exchange-profile');
        if (!wrap) return;
        if (!profile || typeof profile !== 'object') {
            wrap.innerHTML = '';
            return;
        }
        const topics = Array.isArray(profile.topics) ? profile.topics.slice(0, 6) : [];
        wrap.innerHTML = [
            '<div class="lb-exchange-profile-card"><strong>Your site</strong><span>' + esc(profile.site_domain || '-') + '</span></div>',
            '<div class="lb-exchange-profile-card"><strong>Authority</strong><span>' + esc(profile.authority_bucket || profile.authority_value || '-') + '</span></div>',
            '<div class="lb-exchange-profile-card"><strong>Country / Language</strong><span>' + esc((profile.country || '-') + ' / ' + (profile.language || '-')) + '</span></div>',
            '<div class="lb-exchange-profile-card"><strong>Topics</strong><span>' + esc(topics.join(', ') || '-') + '</span></div>'
        ].join('');
    }

    function filterExchangePortals(items) {
        const search = String((document.getElementById('lb-exchange-search') || {}).value || '').trim().toLowerCase();
        const country = String((document.getElementById('lb-exchange-country') || {}).value || '').trim().toLowerCase();
        const language = String((document.getElementById('lb-exchange-language') || {}).value || '').trim().toLowerCase();
        const topic = String((document.getElementById('lb-exchange-topic') || {}).value || '').trim().toLowerCase();
        return (items || []).filter(function (item) {
            const topics = Array.isArray(item.topics) ? item.topics.join(' ').toLowerCase() : '';
            const reasons = item.compatibility && Array.isArray(item.compatibility.reasons) ? item.compatibility.reasons.join(' ').toLowerCase() : '';
            const haystack = [item.site_domain || '', item.website_type || '', topics, reasons].join(' ').toLowerCase();
            if (search && haystack.indexOf(search) === -1) return false;
            if (country && String(item.country || '').toLowerCase().indexOf(country) === -1) return false;
            if (language && String(item.language || '').toLowerCase().indexOf(language) === -1) return false;
            if (topic && topics.indexOf(topic) === -1) return false;
            return true;
        });
    }

    function renderExchangePortals() {
        const wrap = document.getElementById('lb-exchange-results-wrap');
        if (!wrap) return;
        if (!state.exchangeFiltered.length) {
            wrap.innerHTML = '<div class="lb-empty">No compatible exchange sites match the current filters.</div>';
            return;
        }
        const rows = state.exchangeFiltered.map(function (item, idx) {
            const overlap = item.compatibility && Array.isArray(item.compatibility.topic_overlap) ? item.compatibility.topic_overlap : [];
            const reasons = item.compatibility && Array.isArray(item.compatibility.reasons) ? item.compatibility.reasons : [];
            return '<tr>' +
                '<td><span class="lb-portal">' + esc(item.site_domain || '-') + '</span><span class="lb-meta">' + esc(item.website_type || '-') + '</span><span class="lb-meta">' + esc(item.country || '-') + ' / ' + esc(item.language || '-') + '</span></td>' +
                '<td>' + esc(item.authority_bucket || '-') + '</td>' +
                '<td>' + esc(item.authority_value || '-') + '</td>' +
                '<td><div class="lb-exchange-compat"><span class="lb-chip">' + esc('Score ' + ((item.compatibility && item.compatibility.score) || 0)) + '</span><span>' + esc(overlap.join(', ') || '-') + '</span></div></td>' +
                '<td>' + esc(reasons[0] || '-') + '</td>' +
                '<td><button type="button" class="button button-primary lb-open-exchange-modal" data-row="' + idx + '">Request exchange</button></td>' +
            '</tr>';
        }).join('');
        wrap.innerHTML = '<table class="lb-table"><thead><tr><th>Portal</th><th>Authority bucket</th><th>Authority</th><th>Compatibility</th><th>Primary reason</th><th>Action</th></tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function loadExchangePortals(forceRefresh) {
        setExchangeStatus('Loading compatible sites...', false);
        postAjax('aysa_adverlink_exchange_list_portals', {
            project_id: projectId,
            per_page: 100,
            force_refresh: forceRefresh ? '1' : '0'
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setExchangeStatus(ajaxErrorMessage(resp, 'Could not load exchange portals.'), true);
                state.exchangePortals = [];
                state.exchangeFiltered = [];
                renderExchangePortals();
                return;
            }
            state.exchangePortals = Array.isArray(resp.data && resp.data.items) ? resp.data.items : [];
            state.exchangeProfile = (resp.data && typeof resp.data.requester_profile === 'object') ? resp.data.requester_profile : null;
            renderExchangeProfile(state.exchangeProfile);
            state.exchangeFiltered = filterExchangePortals(state.exchangePortals);
            setExchangeStatus('Loaded ' + state.exchangeFiltered.length + ' compatible exchange sites.', false);
            renderExchangePortals();
        }).catch(function (err) {
            setExchangeStatus(err && err.message ? err.message : 'Could not load exchange portals.', true);
        });
    }

    function openExchangeModal(rowIndex) {
        const item = state.exchangeFiltered[rowIndex];
        if (!item) return;
        state.exchangeSelectedPortal = item;
        document.getElementById('lb-exchange-modal-domain').textContent = String(item.site_domain || '-');
        document.getElementById('lb-exchange-modal-authority').textContent = String(item.authority_bucket || '-');
        document.getElementById('lb-exchange-modal-topics').textContent = Array.isArray(item.compatibility && item.compatibility.topic_overlap) ? item.compatibility.topic_overlap.join(', ') : '-';
        document.getElementById('lb-exchange-modal-score').textContent = String((item.compatibility && item.compatibility.score) || 0);
        document.getElementById('lb-exchange-requester-target').value = '<?php echo esc_js(home_url('/')); ?>';
        document.getElementById('lb-exchange-requester-anchor').value = '';
        document.getElementById('lb-exchange-counterparty-target').value = '';
        document.getElementById('lb-exchange-counterparty-anchor').value = '';
        document.getElementById('lb-exchange-requester-notes').value = '';
        document.getElementById('lb-exchange-modal-status').textContent = 'Fill the request details and send it to the counterparty site.';
        document.getElementById('lb-exchange-modal-status').style.color = '#344054';
        document.getElementById('lb-exchange-modal').style.display = 'block';
    }

    function closeExchangeModal() {
        document.getElementById('lb-exchange-modal').style.display = 'none';
        state.exchangeSelectedPortal = null;
    }

    function renderExchangeRequests() {
        const wrap = document.getElementById('lb-exchange-requests-wrap');
        if (!wrap) return;
        if (!state.exchangeRequests.length) {
            wrap.innerHTML = '<div class="lb-empty">No exchange requests yet.</div>';
            document.getElementById('lb-exchange-detail').style.display = 'none';
            return;
        }
        const rows = state.exchangeRequests.map(function (item) {
            const counterpart = item.viewer_role === 'requester' ? item.counterparty_site_domain : item.requester_site_domain;
            const labels = item.status_labels || {};
            const internalSourceUrl = item.viewer_role === 'requester' ? (item.requester_source_url || '') : (item.counterparty_source_url || '');
            const activatedLinkCell = internalSourceUrl
                ? '<a href="' + esc(internalSourceUrl) + '" target="_blank" rel="noopener noreferrer">Open source page</a>'
                : '-';
            return '<tr>' +
                '<td>' + esc(item.exchange_ref || '-') + '</td>' +
                '<td>' + esc(counterpart || '-') + '</td>' +
                '<td>' + esc(labels.summary || item.status || '-') + '</td>' +
                '<td>' + esc(labels.obligation || '-') + '</td>' +
                '<td>' + activatedLinkCell + '</td>' +
                '<td>' + esc(item.updated_at || item.created_at || '-') + '</td>' +
                '<td><button type="button" class="button lb-mini-button lb-open-exchange-request" data-ref="' + esc(item.exchange_ref || '') + '">Open</button></td>' +
            '</tr>';
        }).join('');
        wrap.innerHTML = '<table class="lb-table"><thead><tr><th>Ref</th><th>Counterparty</th><th>Status</th><th>Obligation</th><th>Activated link</th><th>Updated</th><th>Action</th></tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function renderExchangeRequestDetail(request) {
        const panel = document.getElementById('lb-exchange-detail');
        if (!panel) return;
        if (!request || typeof request !== 'object') {
            panel.style.display = 'none';
            return;
        }
        state.currentExchangeRequest = request;
        const yourInternalSourceUrl = request.viewer_role === 'requester' ? (request.requester_source_url || '') : (request.counterparty_source_url || '');
        const yourInternalSourceHtml = yourInternalSourceUrl
            ? '<a href="' + esc(yourInternalSourceUrl) + '" target="_blank" rel="noopener noreferrer">Open activated source page</a>'
            : '-';
        document.getElementById('lb-exchange-detail-title').textContent = 'Exchange ' + String(request.exchange_ref || '-');
        document.getElementById('lb-exchange-detail-meta').innerHTML = [
            '<div><strong>Requester</strong><br>' + esc(request.requester_site_domain || '-') + '</div>',
            '<div><strong>Counterparty</strong><br>' + esc(request.counterparty_site_domain || '-') + '</div>',
            '<div><strong>Status</strong><br>' + esc((request.status_labels && request.status_labels.summary) || request.status || '-') + '</div>',
            '<div><strong>Obligation</strong><br>' + esc((request.status_labels && request.status_labels.obligation) || request.current_obligation || '-') + '</div>',
            '<div><strong>Your activation</strong><br>' + esc(request.viewer_role === 'requester' ? (request.requester_activation_state || 'pending') : (request.counterparty_activation_state || 'pending')) + '</div>',
            '<div><strong>Counterparty activation</strong><br>' + esc(request.viewer_role === 'requester' ? (request.counterparty_activation_state || 'pending') : (request.requester_activation_state || 'pending')) + '</div>',
            '<div><strong>Your activated link</strong><br>' + yourInternalSourceHtml + '</div>'
        ].join('');
        const timeline = Array.isArray(request.timeline) ? request.timeline : [];
        document.getElementById('lb-exchange-timeline-wrap').innerHTML = timeline.length
            ? '<div class="lb-exchange-timeline">' + timeline.map(function (item) {
                return '<div class="lb-exchange-timeline-item"><strong>' + esc(item.event_type || '-') + '</strong><span>' + esc(item.created_at || '-') + '</span><div class="lb-mini-meta">' + esc(JSON.stringify(item.payload || {})) + '</div></div>';
            }).join('') + '</div>'
            : '<div class="lb-empty">No timeline events yet.</div>';
        const activateBtn = document.getElementById('lb-exchange-publish-btn');
        if (activateBtn) {
            activateBtn.textContent = 'Activate my link';
        }
        panel.style.display = 'block';
        loadExchangeActivationCandidates();
    }

    function renderExchangeActivationCandidates() {
        const select = document.getElementById('lb-exchange-source-post');
        if (!select) return;
        const items = Array.isArray(state.exchangeActivationCandidates) ? state.exchangeActivationCandidates : [];
        if (!items.length) {
            select.innerHTML = '<option value="">No eligible source pages found</option>';
            return;
        }
        select.innerHTML = items.map(function (item) {
            const scoreLabel = item.semantic_score !== undefined && item.semantic_score !== null ? ('fit ' + String(item.semantic_score)) : '';
            const label = [item.title || ('#' + item.id), item.post_type || '', scoreLabel, item.url || ''].filter(Boolean).join(' | ');
            return '<option value="' + esc(item.id || '') + '">' + esc(label) + '</option>';
        }).join('');
    }

    function loadExchangeActivationCandidates() {
        return postAjax('aysa_adverlink_exchange_list_activation_candidates', {
            project_id: projectId,
            limit: 30,
            exchange_ref: state.currentExchangeRequest ? String(state.currentExchangeRequest.exchange_ref || '') : '',
            target_url: state.currentExchangeRequest ? String(state.currentExchangeRequest.viewer_role === 'requester' ? (state.currentExchangeRequest.counterparty_target_url || '') : (state.currentExchangeRequest.requester_target_url || '')) : '',
            anchor_text: state.currentExchangeRequest ? String(state.currentExchangeRequest.viewer_role === 'requester' ? (state.currentExchangeRequest.counterparty_anchor_text || '') : (state.currentExchangeRequest.requester_anchor_text || '')) : ''
        }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Could not load source pages.'));
            }
            state.exchangeActivationCandidates = Array.isArray(resp.data && resp.data.items) ? resp.data.items : [];
            renderExchangeActivationCandidates();
        }).catch(function (err) {
            state.exchangeActivationCandidates = [];
            renderExchangeActivationCandidates();
            setExchangeRequestsStatus(err && err.message ? err.message : 'Could not load source pages.', true);
        });
    }

    function loadExchangeRequests() {
        setExchangeRequestsStatus('Loading exchange requests...', false);
        postAjax('aysa_adverlink_exchange_list_requests', {
            project_id: projectId,
            direction: 'all',
            limit: 100
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setExchangeRequestsStatus(ajaxErrorMessage(resp, 'Could not load exchange requests.'), true);
                return;
            }
            state.exchangeRequests = Array.isArray(resp.data && resp.data.items) ? resp.data.items : [];
            renderExchangeRequests();
            setExchangeRequestsStatus('Loaded ' + state.exchangeRequests.length + ' exchange requests.', false);
        }).catch(function (err) {
            setExchangeRequestsStatus(err && err.message ? err.message : 'Could not load exchange requests.', true);
        });
    }

    function reloadExchangeRequest(ref) {
        if (!ref) return Promise.resolve();
        return postAjax('aysa_adverlink_exchange_get_request', {
            project_id: projectId,
            exchange_ref: ref
        }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Could not load exchange request.'));
            }
            renderExchangeRequestDetail(resp.data && resp.data.request ? resp.data.request : null);
        });
    }

    function exchangeAction(action, extraPayload) {
        if (!state.currentExchangeRequest) return;
        const ref = String(state.currentExchangeRequest.exchange_ref || '');
        let asyncTask = '';
        const payload = Object.assign({
            project_id: projectId,
            exchange_ref: ref,
            request_id: state.currentExchangeRequest && state.currentExchangeRequest.id ? String(state.currentExchangeRequest.id) : ''
        }, extraPayload || {});
        if (action === 'accept' || action === 'reject') {
            asyncTask = 'exchange_request_respond';
            payload.decision = action;
        } else if (action === 'verify') {
            asyncTask = 'exchange_refresh_verification';
        } else if (action === 'dispute' || action === 'cancel' || action === 'expire') {
            asyncTask = 'exchange_change_state';
            payload.state_action = action;
        } else {
            return;
        }
        return postAsyncAjax(asyncTask, payload).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Exchange action failed.'));
            }
            loadExchangeRequests();
            return reloadExchangeRequest(ref);
        }).catch(function (err) {
            setExchangeRequestsStatus(err && err.message ? err.message : 'Exchange action failed.', true);
        });
    }

    function offerTypesFromChecks() {
        return Array.from(document.querySelectorAll('.lb-offer-check:checked')).map(function (c) { return c.value; });
    }

    function serviceTypeLabel(type) {
        const normalized = String(type || '').toLowerCase();
        if (normalized === 'seo_article' || normalized === 'sponsored_articles') return 'Sponsored article';
        if (normalized === 'link_insertion') return 'Link placement';
        if (normalized === 'seo_ads_text' || normalized === 'brand_mention') return 'SEO text ads';
        if (normalized === 'professional_article' || normalized === 'banners') return 'Banner placement';
        return String(type || '-')
            .replace(/_/g, ' ')
            .replace(/\b\w/g, function (char) { return char.toUpperCase(); });
    }

    function firstServiceTypeForApi(types) {
        const map = {
            sponsored_articles: 'seo_article',
            link_insertion: 'link_insertion',
            brand_mention: 'seo_ads_text',
            banners: 'professional_article'
        };
        for (let i = 0; i < types.length; i++) {
            if (map[types[i]]) return map[types[i]];
        }
        return '';
    }

    function getServiceTypeForMode(mode) {
        if (mode === 'link_insertion') return 'link_insertion';
        if (mode === 'seo_text_ads') return 'seo_ads_text';
        return 'seo_article';
    }

    function getServiceBillingForMode(mode) {
        if (mode === 'seo_text_ads') return 'monthly';
        if (mode === 'link_insertion') {
            return document.getElementById('lb-li-billing-type') ? (document.getElementById('lb-li-billing-type').value || 'one_time') : 'one_time';
        }
        return document.getElementById('lb-modal-billing-type') ? (document.getElementById('lb-modal-billing-type').value || 'one_time') : 'one_time';
    }

    function getModeServicePrice(row, mode, billingOverride) {
        const item = row || state.selected;
        if (!item || !Array.isArray(item.services)) return 0;
        const serviceType = getServiceTypeForMode(mode);
        const billing = String((billingOverride || getServiceBillingForMode(mode) || '')).toLowerCase();
        const services = item.services.filter(function (svc) {
            return String((svc && svc.service_type) || '').toLowerCase() === serviceType;
        });
        if (!services.length) return 0;
        let chosen = services.find(function (svc) {
            return String((svc && svc.billing_type) || '').toLowerCase() === billing;
        });
        if (!chosen) chosen = services[0];
        const price = Number((chosen && chosen.sale_price_eur) || 0);
        return Number.isFinite(price) ? price : 0;
    }

    function formatModePriceLabel(row, mode, billingOverride) {
        const price = getModeServicePrice(row, mode, billingOverride);
        if (!(price > 0)) {
            return 'n/a';
        }
        const credits = Math.round(price * 100);
        return price.toFixed(2) + ' EUR (' + credits + ' cr)';
    }

    function priceBreakdownItem(label, price) {
        const hasPrice = Number(price) > 0;
        const value = hasPrice ? (price.toFixed(2) + ' EUR / ' + Math.round(price * 100) + ' cr') : 'n/a';
        return '<div class="lb-price-item' + (hasPrice ? '' : ' unavailable') + '"><strong>' + esc(label) + '</strong><span>' + esc(value) + '</span></div>';
    }

    function renderModeActionButton(label, idx, mode, price) {
        const hasPrice = Number(price) > 0;
        const text = hasPrice ? (label + ' · ' + formatModePriceLabel(state.filtered[idx], mode)) : (label + ' · n/a');
        return '<button type="button" class="lb-see-offers lb-order-article' + (hasPrice ? '' : ' is-disabled') + '" data-row="' + idx + '" data-mode="' + esc(mode) + '"' + (hasPrice ? '' : ' disabled aria-disabled="true"') + '>' + esc(text) + '</button>';
    }

    function updateModePricesUi() {
        const modes = [
            { mode: 'add_new_article', id: 'lb-tab-price-article' },
            { mode: 'link_insertion', id: 'lb-tab-price-link' },
            { mode: 'seo_text_ads', id: 'lb-tab-price-ads' }
        ];
        modes.forEach(function (entry) {
            const el = document.getElementById(entry.id);
            if (!el) return;
            const modePrice = getModeServicePrice(state.selected, entry.mode);
            if (modePrice > 0) {
                el.textContent = modePrice.toFixed(2) + ' EUR';
            } else {
                el.textContent = '-';
            }
        });

        const price = getModeServicePrice(state.selected, state.orderMode);
        const credits = price > 0 ? Math.round(price * 100) : 0;
        const priceEl = document.getElementById('lb-modal-price-eur');
        const creditsEl = document.getElementById('lb-modal-price-credits');
        if (priceEl) priceEl.textContent = price > 0 ? price.toFixed(2) + ' EUR' : '-';
        if (creditsEl) creditsEl.textContent = String(credits);
        const placeBtn = document.getElementById('lb-place-order');
        if (placeBtn) {
            placeBtn.disabled = !(price > 0);
            placeBtn.classList.toggle('button-disabled', !(price > 0));
        }
    }

    function boolToIcon(v) {
        if (v === true || String(v).toLowerCase() === 'true' || String(v).toLowerCase() === 'yes' || String(v) === '1') return 'yes';
        if (v === false || String(v).toLowerCase() === 'false' || String(v).toLowerCase() === 'no' || String(v) === '0') return 'no';
        return 'unknown';
    }

    function scoreBadge(score) {
        let n = Number(score || 0);
        if (!Number.isFinite(n) || n <= 0) return '<span class="lb-badge warn">-</span>';
        if (n > 10) n = n / 10;
        n = Math.round(n * 10) / 10;
        if (n >= 8) return '<span class="lb-badge good">' + esc(n) + ' / 10</span>';
        if (n >= 6) return '<span class="lb-badge warn">' + esc(n) + ' / 10</span>';
        return '<span class="lb-badge bad">' + esc(n) + ' / 10</span>';
    }

    function extractPortalDomain(value) {
        const raw = String(value || '').trim();
        if (!raw) return '';
        try {
            const withProtocol = /^[a-z]+:\/\//i.test(raw) ? raw : ('https://' + raw);
            return new URL(withProtocol).hostname.replace(/^www\./i, '').trim().toLowerCase();
        } catch (e) {
            return raw
                .replace(/^[a-z]+:\/\//i, '')
                .replace(/^www\./i, '')
                .split('/')[0]
                .split('?')[0]
                .split('#')[0]
                .trim()
                .toLowerCase();
        }
    }

    function normalizePortalRow(row) {
        const out = Object.assign({}, row || {});
        const metrics = (out.metrics && typeof out.metrics === 'object') ? out.metrics : {};
        const policy = (out.policy && typeof out.policy === 'object') ? out.policy : {};
        const content = (out.content && typeof out.content === 'object') ? out.content : {};
        const social = (out.social && typeof out.social === 'object') ? out.social : {};
        const services = Array.isArray(out.services) ? out.services : [];
        const normalizedServices = services.map(function (svc) {
            if (!svc || typeof svc !== 'object') return {};
            return svc;
        });

        const serviceTypes = normalizedServices
            .map(function (svc) { return String(svc.service_type || '').trim(); })
            .filter(Boolean);
        const uniqueServiceTypes = Array.from(new Set(serviceTypes));
        if (!Array.isArray(out.service_types) || !out.service_types.length) {
            out.service_types = uniqueServiceTypes;
        }

        const prices = normalizedServices
            .map(function (svc) { return Number(svc.sale_price_eur || 0); })
            .filter(function (v) { return Number.isFinite(v) && v > 0; });
        if ((!out.sale_price_eur || Number(out.sale_price_eur) <= 0) && prices.length) {
            out.sale_price_eur = Math.min.apply(null, prices);
        }

        const billingTypes = normalizedServices
            .map(function (svc) { return String(svc.billing_type || '').trim(); })
            .filter(Boolean);
        if (!out.billing_type && billingTypes.length) {
            out.billing_type = billingTypes[0];
        }

        if (!out.portal_id && out.id) {
            out.portal_id = out.id;
        }

        if (!out.domain && out.url) out.domain = out.url;
        if (!out.portal_type && out.website_type) out.portal_type = out.website_type;
        const normalizedDomain = extractPortalDomain(out.domain || out.url || out.name || '');
        if (normalizedDomain) {
            out.domain = normalizedDomain;
        }

        if (out.active_users === undefined && metrics.monthly_active_users !== undefined) {
            out.active_users = metrics.monthly_active_users;
        }
        if ((out.ahrefs === undefined || out.ahrefs === null || out.ahrefs === '') && metrics.ur_medium !== undefined) {
            out.ahrefs = metrics.ur_medium;
        }
        if ((out.semrush === undefined || out.semrush === null || out.semrush === '') && metrics.unique_users !== undefined) {
            out.semrush = metrics.unique_users;
        }
        if ((out.trust_flow === undefined || out.trust_flow === null || out.trust_flow === '') && metrics.trust_flow !== undefined) {
            out.trust_flow = metrics.trust_flow;
        }
        if ((out.substantive_assessment === undefined || out.substantive_assessment === null || out.substantive_assessment === '') && metrics.qualitative_evaluation !== undefined) {
            out.substantive_assessment = metrics.qualitative_evaluation;
        }
        if ((out.technical_assessment === undefined || out.technical_assessment === null || out.technical_assessment === '') && metrics.technical_evaluation !== undefined) {
            out.technical_assessment = metrics.technical_evaluation;
        }

        if (out.dofollow === undefined && policy.dofollow !== undefined) out.dofollow = policy.dofollow;
        if (out.traffic_tracking === undefined && policy.traffic_tracking !== undefined) out.traffic_tracking = policy.traffic_tracking;
        if (!out.tags && Array.isArray(content.tags)) out.tags = content.tags;
        if (!out.social_profiles && social) out.social_profiles = social;

        return out;
    }

    function normalizePortalItems(items) {
        if (!Array.isArray(items)) return [];
        return items
            .map(normalizePortalRow)
            .filter(function (item) {
                const domain = extractPortalDomain(item.domain || item.url || item.name || '');
                if (!domain) return false;
                if (domain === 'localhost' || domain === '127.0.0.1') return false;
                if (domain.indexOf('.localhost') !== -1) return false;
                return true;
            });
    }

    function filterPortals(items) {
        const q = (document.getElementById('lb-domain-query').value || '').trim().toLowerCase();
        const keywordQ = (document.getElementById('lb-keyword-search').value || '').trim().toLowerCase();
        const theme = (document.getElementById('lb-theme').value || '').trim().toLowerCase();
        const minDr = Number(document.getElementById('lb-min-dr').value || 0);
        const minAhrefs = Number(document.getElementById('lb-min-ahrefs').value || 0);
        const minTrust = Number(document.getElementById('lb-min-trust').value || 0);
        const priceFrom = Number(document.getElementById('lb-price-from').value || 0);
        const priceTo = Number(document.getElementById('lb-price-to').value || 0);
        const dofollow = document.getElementById('lb-dofollow').value;
        const selectedOfferTypes = offerTypesFromChecks();

        return items.filter(function (r) {
            const domain = String(r.domain || r.url || r.name || '').toLowerCase();
            const portalType = String(r.type || r.portal_type || r.website_type || '').toLowerCase();
            const region = String(r.region || r.country || r.country_region || '').toLowerCase();
            const offerTypes = Array.isArray(r.service_types) ? r.service_types.map(String) : [String(r.service_type || '')];
            const offerTypesLc = offerTypes.map(function (x) { return x.toLowerCase(); });
            const sale = Number(r.sale_price_eur || r.price_eur || r.price || 0);
            const dr = Number(r.dr || r.domain_rating || r.domain_authority || r.da || 0);
            const ahrefs = Number(r.ahrefs || r.ahrefs_traffic || r.active_users || 0);
            const trust = Number(r.trust_flow || r.trust || 0);
            const dofollowRaw = boolToIcon(r.dofollow || r.has_dofollow || r.dofollow_links);
            const tagsText = Array.isArray(r.tags) ? r.tags.join(' ') : '';
            const catsText = Array.isArray(r.accepted_categories) ? r.accepted_categories.join(' ') : '';
            const themeText = String(r.theme || r.website_type || tagsText || catsText).toLowerCase();
            const countryText = String(r.country || '').toLowerCase();

            if (q && domain.indexOf(q) === -1) return false;
            if (keywordQ && domain.indexOf(keywordQ) === -1 && offerTypesLc.join(' ').indexOf(keywordQ) === -1) return false;
            if (theme && themeText.indexOf(theme) === -1) return false;
            if (document.getElementById('lb-country').value && countryText && countryText.indexOf(String(document.getElementById('lb-country').value).trim().toLowerCase()) === -1) return false;
            if (document.getElementById('lb-portal-type').value && portalType.indexOf(String(document.getElementById('lb-portal-type').value).trim().toLowerCase()) === -1) return false;
            if (document.getElementById('lb-region').value && region.indexOf(String(document.getElementById('lb-region').value).trim().toLowerCase()) === -1) return false;
            if (minDr > 0 && dr < minDr) return false;
            if (minAhrefs > 0 && ahrefs < minAhrefs) return false;
            if (minTrust > 0 && trust < minTrust) return false;
            if (priceFrom > 0 && sale < priceFrom) return false;
            if (priceTo > 0 && sale > priceTo) return false;
            if (dofollow === 'yes' && dofollowRaw !== 'yes') return false;
            if (dofollow === 'no' && dofollowRaw !== 'no') return false;

            if (selectedOfferTypes.length) {
                const map = {
                    sponsored_articles: 'seo_article',
                    link_insertion: 'link_insertion',
                    brand_mention: 'seo_ads_text',
                    banners: 'professional_article'
                };
                const wanted = selectedOfferTypes.map(function (x) { return (map[x] || x).toLowerCase(); });
                const ok = wanted.some(function (w) { return offerTypesLc.some(function (t) { return t.indexOf(w) !== -1; }); });
                if (!ok) return false;
            }

            return true;
        });
    }

    function renderPortals() {
        const wrap = document.getElementById('lb-results-wrap');
        if (!state.filtered.length) {
            wrap.innerHTML = '<div class="lb-empty">No portals match the current filters.</div>';
            return;
        }

        const rows = state.filtered.map(function (r, idx) {
            const domain = r.domain || r.url || r.name || '-';
            const portalType = r.type || r.portal_type || r.website_type || 'General portal';
            const country = r.country || r.country_region || 'Romania';
            const offerTypes = Array.isArray(r.service_types) ? r.service_types : [r.service_type || 'n/a'];
            const offerChips = offerTypes.filter(Boolean).slice(0, 3).map(function (t) { return '<span class="lb-chip">' + esc(serviceTypeLabel(t)) + '</span>'; }).join('');
            const activeUsers = r.active_users || r.users || '-';
            const ahrefs = r.ahrefs || r.ahrefs_traffic || '-';
            const semrush = r.semrush || r.semrush_traffic || '-';
            const trust = r.trust_flow || r.trust || '-';
            const da = r.domain_authority || r.da || r.dr || r.domain_rating || '-';
            const dofollow = boolToIcon(r.dofollow || r.has_dofollow || r.dofollow_links);
            const traffic = boolToIcon(r.traffic_tracking || r.has_traffic_tracking);
            const substantive = r.substantive_assessment || r.substantive_score || '-';
            const technical = r.technical_assessment || r.technical_score || '-';
            const tags = Array.isArray(r.tags) ? r.tags : [];
            const tagChips = tags.slice(0, 2).map(function (t) { return '<span class="lb-chip">' + esc(t) + '</span>'; }).join('');
            const articlePrice = getModeServicePrice(r, 'add_new_article', 'one_time');
            const linkPrice = getModeServicePrice(r, 'link_insertion', 'one_time');
            const adsPrice = getModeServicePrice(r, 'seo_text_ads', 'monthly');
            const priceBlock = '<div class="lb-price-breakdown">' +
                priceBreakdownItem('Article', articlePrice) +
                priceBreakdownItem('Link placement', linkPrice) +
                priceBreakdownItem('SEO text ads', adsPrice) +
            '</div>';
            const actions = [
                renderModeActionButton('Order sponsored article', idx, 'add_new_article', articlePrice),
                renderModeActionButton('Order link placement', idx, 'link_insertion', linkPrice),
                renderModeActionButton('Order SEO text ads', idx, 'seo_text_ads', adsPrice)
            ];
            return '<tr>' +
                '<td><span class="lb-portal">' + esc(domain) + '</span><span class="lb-meta">' + esc(portalType) + '</span><span class="lb-meta">' + esc(country) + '</span>' + tagChips + '</td>' +
                '<td>' + offerChips + '</td>' +
                '<td>' + esc(activeUsers) + '</td>' +
                '<td>' + esc(da) + '</td>' +
                '<td>' + esc(ahrefs) + '</td>' +
                '<td>' + esc(semrush) + '</td>' +
                '<td>' + esc(trust) + '</td>' +
                '<td>' + (dofollow === 'yes' ? 'Yes' : (dofollow === 'no' ? 'No' : '-')) + '</td>' +
                '<td>' + (traffic === 'yes' ? 'Yes' : (traffic === 'no' ? 'No' : '-')) + '</td>' +
                '<td>' + scoreBadge(substantive) + '</td>' +
                '<td>' + scoreBadge(technical) + '</td>' +
                '<td>' + priceBlock + '</td>' +
                '<td><div class="lb-actions-group">' + actions.join('') + '</div></td>' +
            '</tr>';
        }).join('');

        wrap.innerHTML = '<table class="lb-table"><thead><tr>' +
            '<th>Portal</th><th>Offer type</th><th>Active users</th><th>DA</th><th>AHREFS</th><th>Semrush</th><th>Trust Flow</th><th>Dofollow</th><th>Traffic</th><th>Substantive assessment</th><th>Technical assessment</th><th>Pricing by order type</th><th>Actions</th>' +
            '</tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function loadCredits() {
        postAjax('aysa_adverlink_credit_balance', { project_id: projectId }).then(function (resp) {
            if (!resp || !resp.success) {
                document.getElementById('lb-credit-value').textContent = 'N/A';
                document.getElementById('lb-included-links-value').textContent = 'N/A';
                return;
            }
            const d = resp.data || {};
            const includedTotal = Number(d.included_links_total || d.included_links || 0);
            const includedUsed = Number(d.included_links_used || 0);
            const includedRemainingRaw = Number(d.included_links_remaining || 0);
            const includedRemaining = includedTotal > 0
                ? Math.max(0, Math.min(includedTotal, includedRemainingRaw || (includedTotal - includedUsed)))
                : Math.max(0, includedRemainingRaw);
            state.availableCredits = Number(d.available_credits || 0);
            state.includedLinksRemaining = includedRemaining;
            document.getElementById('lb-credit-value').textContent = String(d.available_credits || 0);
            document.getElementById('lb-included-links-value').textContent = String(includedRemaining);
        }).catch(function () {
            document.getElementById('lb-credit-value').textContent = 'N/A';
            document.getElementById('lb-included-links-value').textContent = 'N/A';
        });
    }

    function loadPortals(forceRefresh) {
        const selectedTypes = offerTypesFromChecks();
        const payload = {
            project_id: projectId,
            service_type: firstServiceTypeForApi(selectedTypes),
            billing_type: document.getElementById('lb-billing-type').value,
            per_page: 100,
            force_refresh: forceRefresh ? '1' : '0'
        };

        setStatus('Loading domains...', false);
        postAjax('aysa_adverlink_list_portals', payload).then(function (resp) {
            if (!resp || !resp.success) {
                const errMsg = ajaxErrorMessage(resp, 'Request failed.');
                setStatus(errMsg, true);
                state.portals = [];
                state.filtered = [];
                renderPortals();
                if (errMsg.toLowerCase().indexOf('credentials') !== -1 || errMsg.toLowerCase().indexOf('api key') !== -1) {
                    document.getElementById('lb-results-wrap').innerHTML =
                        '<div class="lb-empty">Off-Page is not configured yet. ' +
                        '<a href="<?php echo esc_url(admin_url('admin.php?page=aysa-settings')); ?>">Open Settings</a> and add marketplace credentials.</div>';
                }
                return;
            }
            state.portals = normalizePortalItems((resp.data && resp.data.items) ? resp.data.items : []);
            state.filtered = filterPortals(state.portals);
            setStatus('Loaded ' + state.filtered.length + ' portals' + ((resp.data && resp.data.cached) ? ' (cached)' : '') + '.', false);
            renderPortals();
        }).catch(function (err) {
            setStatus(err && err.message ? err.message : 'Request failed.', true);
        });
    }

    function refreshFilteredView() {
        state.filtered = filterPortals(state.portals);
        setStatus('Showing ' + state.filtered.length + ' filtered portals.', false);
        renderPortals();
    }

    function fillOrderPanel(rowIndex, mode) {
        const row = state.filtered[rowIndex];
        if (!row) return;
        state.selected = row;
        state.linkTargets = [];
        state.selectedLinkTarget = null;
        state.seoAdsTargets = [];
        state.selectedSeoAdsTarget = null;
        const domain = row.domain || row.url || row.name || '';
        const defaultPrice = Number(row.sale_price_eur || row.price_eur || row.price || 0);
        const guarantee = defaultPrice > 0 ? (defaultPrice * 0.18).toFixed(2) + ' EUR' : 'calculated at checkout';

        document.getElementById('lb-modal-portal').textContent = domain;
        document.getElementById('lb-modal-guarantee-cost').textContent = 'Guarantee costs net: ' + guarantee;
        document.getElementById('lb-modal-keyword').value = '';
        document.getElementById('lb-modal-title').value = 'Article order - ' + domain;
        document.getElementById('lb-modal-target').value = '<?php echo esc_js(home_url('/')); ?>';
        document.getElementById('lb-modal-lead').value = '';
        setContentValue('');
        document.getElementById('lb-modal-remarks').value = '';
        document.getElementById('lb-modal-guarantee-36m').checked = false;
        document.getElementById('lb-li-keyword').value = '';
        document.getElementById('lb-li-target-search').value = '';
        document.getElementById('lb-li-rel-type').value = 'follow';
        document.getElementById('lb-li-billing-type').value = 'one_time';
        document.getElementById('lb-li-remarks').value = '';
        clearSelectedLinkTarget();
        renderLinkTargets();
        document.getElementById('lb-ads-title').value = 'SEO TEXT ADS - ' + domain;
        document.getElementById('lb-ads-keyword').value = '';
        document.getElementById('lb-ads-target-search').value = '';
        document.getElementById('lb-ads-target-url').value = '';
        document.getElementById('lb-ads-display-url').value = '<?php echo esc_js(home_url('/')); ?>';
        document.getElementById('lb-ads-target-article-url').value = '';
        document.getElementById('lb-ads-description').value = '';
        document.getElementById('lb-ads-duration-months').value = '1';
        document.getElementById('lb-ads-remarks').value = '';
        clearSelectedSeoAdsTarget();
        renderSeoAdsTargets();
        updateSeoAdsPreview();
        setOrderMode(mode || 'add_new_article');
        setOrderStatus('Portal selected: ' + domain, false);
        document.getElementById('lb-article-modal').style.display = 'block';
        setTimeout(function () { initContentEditor(); }, 60);
        loadDraftForSelectedPortal();
    }

    function loadOrders() {
        postAjax('aysa_adverlink_get_orders', { project_id: projectId }).then(function (resp) {
            if (!resp || !resp.success) return;
            state.orders = (resp.data && resp.data.items) ? resp.data.items : [];
            const wrap = document.getElementById('lb-orders-wrap');
            if (!state.orders.length) {
                wrap.innerHTML = '';
                return;
            }
            const rows = state.orders.slice().reverse().map(function (o) {
                let verificationText = '-';
                if (o.verification && typeof o.verification === 'object') {
                    const valid = o.verification.is_valid;
                    const code = o.verification.http_status_code || '-';
                    verificationText = (valid === true ? 'Valid' : (valid === false ? 'Invalid' : 'Pending')) + ' (HTTP ' + code + ')';
                }
                const billingText = String(o.billing_type || 'one_time');
                let subscriptionText = '-';
                if (billingText === 'monthly' || billingText === 'subscription') {
                    const sub = (o.subscription && typeof o.subscription === 'object') ? o.subscription : {};
                    const subStatus = String(sub.status || 'unknown');
                    const nextRenewal = String(sub.next_renewal_at || '-');
                    const renewalCount = Number(o.renewal_count || 0);
                    const renewalError = String(o.last_subscription_renewal_error || '');
                    subscriptionText = subStatus + ' | next: ' + nextRenewal + ' | renewals: ' + renewalCount;
                    if (renewalError) {
                        subscriptionText += ' | error: ' + renewalError;
                    }
                }
                const details = extractPublishedDetails(o);
                const statusText = (o.is_trackable_ref === false)
                    ? 'REF_INVALID_FOR_TRACKING'
                    : String(o.status || '-');
                const sourceUrlHtml = details.sourceUrl
                    ? '<a href="' + esc(details.sourceUrl) + '" target="_blank" rel="noopener noreferrer">' + esc(details.sourceUrl) + '</a>'
                    : '-';
                const targetUrlHtml = details.targetUrl
                    ? '<a href="' + esc(details.targetUrl) + '" target="_blank" rel="noopener noreferrer">' + esc(details.targetUrl) + '</a>'
                    : '-';
                return '<tr>' +
                    '<td>' + esc(o.order_ref || '-') + '</td>' +
                    '<td>' + esc(o.portal_domain || o.portal_id || '-') + '</td>' +
                    '<td>' + esc(details.publishedKeyword || '-') + '</td>' +
                    '<td>' + sourceUrlHtml + '</td>' +
                    '<td>' + targetUrlHtml + '</td>' +
                    '<td>' + esc(statusText) + '</td>' +
                    '<td>' + esc(billingText) + '</td>' +
                    '<td>' + esc(subscriptionText) + '</td>' +
                    '<td>' + esc(verificationText) + '</td>' +
                    '<td>' + esc(o.charged_credits_cents || o.estimated_credits || 0) + '</td>' +
                    '<td>' + esc(o.created_at || '-') + '</td>' +
                '</tr>';
            }).join('');
            wrap.innerHTML = '<table class="lb-table"><thead><tr><th>Order Ref</th><th>Portal</th><th>Published keyword</th><th>Published on URL</th><th>Linked to URL</th><th>Status</th><th>Billing</th><th>Subscription</th><th>Verification</th><th>Credits</th><th>Created</th></tr></thead><tbody>' + rows + '</tbody></table>';
        });
    }

    function renderPublisherDraftPreview(draft) {
        const panel = document.getElementById('lb-draft-preview');
        if (!panel) return;
        if (!draft || typeof draft !== 'object') {
            state.currentPublisherDraft = null;
            panel.style.display = 'none';
            return;
        }

        state.currentPublisherDraft = draft;

        document.getElementById('lb-draft-preview-title').textContent = String(draft.title || 'Draft preview');
        const metaHtml = [
            '<div><strong>Portal</strong><br>' + esc(draft.portal_domain || '-') + '</div>',
            '<div><strong>Keyword principal</strong><br>' + esc(draft.primary_keyword || '-') + '</div>',
            '<div><strong>Limba</strong><br>' + esc(draft.language || '-') + '</div>',
            '<div><strong>Status</strong><br>' + esc(draft.status || '-') + '</div>'
        ].join('');
        document.getElementById('lb-draft-preview-meta').innerHTML = metaHtml;

        const links = Array.isArray(draft.internal_links) ? draft.internal_links : [];
        const linksHtml = links.length
            ? links.map(function (link) {
                const href = String(link.href || link.url || '').trim();
                const anchor = String(link.anchor || '').trim();
                if (!href || !anchor) return '';
                return '<a href="' + esc(href) + '" target="_blank" rel="noopener noreferrer">' + esc(anchor) + '</a>';
            }).join('')
            : '<span class="lb-empty">No internal links proposed yet.</span>';
        document.getElementById('lb-draft-preview-links').innerHTML = linksHtml;
        document.getElementById('lb-draft-edit-title').value = String(draft.title || '');
        document.getElementById('lb-draft-edit-excerpt').value = String(draft.excerpt || '');
        document.getElementById('lb-draft-edit-body').value = String(draft.body_html || '');
        document.getElementById('lb-draft-preview-body').innerHTML = String(draft.body_html || '<p>No content generated yet.</p>');
        panel.style.display = 'block';
    }

    function renderPublisherArticles(kind) {
        const isPublished = kind === 'published';
        const items = isPublished ? state.publisherPublished : state.publisherDrafts;
        const wrap = document.getElementById(isPublished ? 'lb-published-articles-wrap' : 'lb-draft-articles-wrap');
        if (!wrap) return;
        if (!items.length) {
            wrap.innerHTML = '<div class="lb-empty">' + (isPublished ? 'No published articles tracked yet.' : 'No draft or approved articles available yet.') + '</div>';
            if (!isPublished) {
                renderPublisherDraftPreview(null);
            }
            return;
        }

        const rows = items.map(function (item) {
            const publishedUrl = String(item.published_url || '').trim();
            const actionHtml = isPublished
                ? (publishedUrl ? '<a class="button lb-mini-button" href="' + esc(publishedUrl) + '" target="_blank" rel="noopener noreferrer">Open</a>' : '-')
                : '<button type="button" class="button lb-mini-button lb-open-publisher-draft" data-draft-id="' + esc(item.id || '') + '">Open draft</button>';

            return '<tr>' +
                '<td>' + esc(item.title || '-') + '</td>' +
                '<td>' + esc(item.portal_domain || '-') + '</td>' +
                '<td>' + esc(item.primary_keyword || '-') + '</td>' +
                '<td>' + esc(item.language || '-') + '</td>' +
                '<td>' + esc(item.order_ref || '-') + '</td>' +
                '<td>' + esc(item.status || '-') + '</td>' +
                '<td>' + esc(item.updated_at || item.created_at || '-') + '</td>' +
                '<td>' + actionHtml + '</td>' +
            '</tr>';
        }).join('');

        wrap.innerHTML = '<table class="lb-table"><thead><tr><th>Title</th><th>Portal</th><th>Primary keyword</th><th>Language</th><th>Order ref</th><th>Status</th><th>Updated</th><th>Action</th></tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function loadPublisherArticles(kind) {
        const isPublished = kind === 'published';
        const status = isPublished ? 'published' : 'draft';
        setPublisherArticlesStatus(kind, isPublished ? 'Loading published articles...' : 'Loading draft and approved articles...', false);
        postAjax('aysa_adverlink_list_publisher_article_drafts', {
            project_id: projectId,
            status: status,
            limit: 50
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setPublisherArticlesStatus(kind, ajaxErrorMessage(resp, 'Failed to load publisher articles.'), true);
                return;
            }
            const items = (resp.data && Array.isArray(resp.data.items)) ? resp.data.items : [];
            if (isPublished) {
                state.publisherPublished = items;
            } else {
                state.publisherDrafts = items;
            }
            renderPublisherArticles(kind);
            setPublisherArticlesStatus(kind, (isPublished ? 'Published' : 'Draft/approved') + ' articles loaded: ' + items.length, false);
        }).catch(function (err) {
            setPublisherArticlesStatus(kind, err && err.message ? err.message : 'Failed to load publisher articles.', true);
        });
    }

    function schedulePublisherArticlesRefresh(kind, delayMs) {
        const key = kind === 'published' ? 'published' : 'draft';
        if (publisherArticlesRefreshTimers[key]) {
            clearTimeout(publisherArticlesRefreshTimers[key]);
        }
        publisherArticlesRefreshTimers[key] = window.setTimeout(function () {
            publisherArticlesRefreshTimers[key] = null;
            loadPublisherArticles(key);
        }, Math.max(250, Number(delayMs || 900)));
    }

    function openPublisherDraft(draftId) {
        if (!draftId) return;
        setPublisherArticlesStatus('draft', 'Opening draft...', false);
        postAjax('aysa_adverlink_get_publisher_article_draft', {
            draft_id: draftId
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setPublisherArticlesStatus('draft', ajaxErrorMessage(resp, 'Failed to load draft.'), true);
                return;
            }
            renderPublisherDraftPreview((resp.data && resp.data.draft) ? resp.data.draft : null);
            setPublisherArticlesStatus('draft', 'Draft opened.', false);
        }).catch(function (err) {
            setPublisherArticlesStatus('draft', err && err.message ? err.message : 'Failed to load draft.', true);
        });
    }

    function renderLinkIssuesTable() {
        const wrap = document.getElementById('lb-link-issues-wrap');
        if (!wrap) return;
        if (!state.linkIssues.length) {
            wrap.innerHTML = '<div class="lb-empty">No link issues detected.</div>';
            return;
        }
        const buildBadge = function (row) {
            const status = String(row.status || '').toUpperCase();
            const hasProblem = !!(row.issue_type || row.issue_message || row.issue_summary);
            if (status === 'COMPLETED' && !hasProblem) {
                return '<span class="lb-issue-badge is-ok">&#10003; OK</span>';
            }
            if (status === 'FAILED' || status === 'ERROR' || status === 'INVALID') {
                return '<span class="lb-issue-badge is-error">&#9888; Problem</span>';
            }
            return '<span class="lb-issue-badge is-warning">&#9888; Attention</span>';
        };
        const rows = state.linkIssues.map(function (o) {
            const sourceUrl = o.published_on_url
                ? '<a href="' + esc(o.published_on_url) + '" target="_blank" rel="noopener noreferrer">' + esc(o.published_on_url) + '</a>'
                : '-';
            const targetUrl = o.linked_to_url
                ? '<a href="' + esc(o.linked_to_url) + '" target="_blank" rel="noopener noreferrer">' + esc(o.linked_to_url) + '</a>'
                : '-';
            const issueText = String(o.issue_summary || o.issue_message || o.issue_type || '-');
            return '<tr>' +
                '<td>' + esc(o.order_ref || '-') + '</td>' +
                '<td>' + esc(o.portal_domain || '-') + '</td>' +
                '<td>' + esc(o.published_keyword || '-') + '</td>' +
                '<td>' + sourceUrl + '</td>' +
                '<td>' + targetUrl + '</td>' +
                '<td>' + buildBadge(o) + '<div class="lb-issue-text">' + esc(String(o.status || '-')) + '</div></td>' +
                '<td>' + esc(o.issue_type || '-') + '</td>' +
                '<td><div class="lb-issue-text">' + esc(issueText) + '</div></td>' +
                '<td>' + esc(o.detected_at || '-') + '</td>' +
            '</tr>';
        }).join('');
        wrap.innerHTML = '<table class="lb-table"><thead><tr><th>Order Ref</th><th>Portal</th><th>Keyword</th><th>Published on URL</th><th>Linked to URL</th><th>Alert</th><th>Issue type</th><th>Issue details</th><th>Detected at</th></tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function loadLinkIssues(forceRefresh) {
        const payload = {
            project_id: projectId,
            force_refresh: forceRefresh ? '1' : '0'
        };
        if (forceRefresh) {
            setLinkIssuesStatus('Refreshing link issues from external API...', false);
        }
        postAjax('aysa_adverlink_get_link_issues', payload).then(function (resp) {
            if (!resp || !resp.success) {
                setLinkIssuesStatus((resp && resp.data) ? String(resp.data) : 'Failed to load link issues.', true);
                return;
            }
            state.linkIssues = (resp.data && resp.data.items && Array.isArray(resp.data.items)) ? resp.data.items : [];
            renderLinkIssuesTable();
            const ls = (resp.data && resp.data.last_sync) ? resp.data.last_sync : {};
            const syncedAt = ls && ls.synced_at ? String(ls.synced_at) : 'never';
            setLinkIssuesStatus('Link issues: ' + state.linkIssues.length + ' | Last sync: ' + syncedAt, false);
        }).catch(function (err) {
            setLinkIssuesStatus(err && err.message ? err.message : 'Failed to load link issues.', true);
        });
    }

    function normalizeBacklinkAuditItem(item) {
        const get = function (keys) {
            return findFirstStringByKeysDeep(item || {}, keys, 0);
        };
        const sourceUrl = get(['source_url', 'backlink_url', 'url_from', 'sourceUrl', 'url', 'page_from_url']);
        const targetUrl = get(['target_url', 'url_to', 'linked_to_url', 'targetUrl', 'page_to_url']);
        const anchor = get(['anchor', 'anchor_text', 'keyword', 'published_keyword']);
        const referringDomain = get(['referring_domain', 'source_domain', 'domain_from', 'portal_domain', 'domain']);
        const relRaw = get(['rel', 'rel_type', 'link_attribute']);
        const dofollowRaw = get(['dofollow', 'is_dofollow', 'rel_type', 'link_type', 'rel']);
        const firstSeen = get(['first_seen', 'firstSeen', 'detected_at', 'created_at']);
        const lastSeen = get(['last_seen', 'lastSeen', 'updated_at', 'checked_at']);
        const sourceStatus = get(['source_http_status', 'source_status', 'status_code_source', 'http_status_code', 'status_code']);
        const targetStatus = get(['target_http_status', 'target_status', 'status_code_target']);
        const sourceLang = get(['source_language', 'lang', 'language']);
        const topical = get(['topic', 'category', 'issue_type', 'link_type']);
        const sourceCountry = get(['source_country', 'country_from', 'ip_from_country', 'country']);
        const sourceTld = get(['source_tld', 'tld_from']);
        const domainRank = parseInt(get(['domain_rank', 'domain_from_rank']), 10) || 0;
        const pageRank = parseInt(get(['page_rank', 'rank']), 10) || 0;
        const linkSpamScore = parseInt(get(['link_spam_score', 'spam_score']), 10) || 0;
        const brokenBacklink = String(get(['broken_backlink', 'is_broken'])).toLowerCase();
        const isNew = String(get(['is_new'])).toLowerCase();
        const isLost = String(get(['is_lost', 'lost'])).toLowerCase();
        const srcHost = safeHost(sourceUrl);
        const tld = sourceTld || inferTld(srcHost);
        const anchorType = classifyAnchor(anchor, targetUrl);
        const dofollow = isFollow(dofollowRaw, relRaw);

        return {
            sourceUrl: sourceUrl || '-',
            targetUrl: targetUrl || '-',
            anchor: anchor || '-',
            referringDomain: referringDomain || '-',
            sourceHost: srcHost || referringDomain || '-',
            sourceCountry: sourceCountry || '-',
            sourceTld: tld || '-',
            anchorType: anchorType,
            relRaw: relRaw || '-',
            dofollow: dofollow,
            dofollowRaw: dofollowRaw || '',
            firstSeen: firstSeen || '-',
            lastSeen: lastSeen || '-',
            sourceStatus: sourceStatus || '-',
            targetStatus: targetStatus || '-',
            sourceLang: sourceLang || '-',
            topical: topical || '-',
            domainRank: domainRank,
            pageRank: pageRank,
            linkSpamScore: linkSpamScore,
            brokenBacklink: brokenBacklink === '1' || brokenBacklink === 'true' || brokenBacklink === 'yes',
            isNew: isNew === '1' || isNew === 'true' || isNew === 'yes',
            isLost: isLost === '1' || isLost === 'true' || isLost === 'yes',
            raw: item || {}
        };
    }

    function safeHost(url) {
        try {
            const u = new URL(url);
            return u.hostname || '';
        } catch (_) {
            return '';
        }
    }

    function inferTld(host) {
        if (!host) return '';
        const p = String(host).toLowerCase().split('.');
        if (p.length < 2) return '';
        return p[p.length - 1];
    }

    function classifyAnchor(anchor, targetUrl) {
        const a = String(anchor || '').trim().toLowerCase();
        if (!a || a === '-') return 'other';
        if (a.indexOf('http://') === 0 || a.indexOf('https://') === 0 || a.indexOf('www.') === 0) return 'naked';
        const generic = ['click aici', 'click here', 'aici', 'here', 'site', 'website', 'detalii', 'read more', 'learn more'];
        if (generic.indexOf(a) !== -1) return 'generic';
        const tokens = a.split(/\s+/).filter(Boolean);
        if (tokens.length >= 3) return 'compound';
        const targetHost = safeHost(targetUrl).replace(/^www\./, '').toLowerCase();
        if (targetHost && a.includes(targetHost.split('.')[0])) return 'brand';
        const moneyHints = ['pret', 'price', 'buy', 'cheap', 'best', 'servicii', 'flori', 'seo', 'casino', 'bonus'];
        if (moneyHints.some(function (k) { return a.includes(k); })) return 'money';
        if (tokens.length <= 2) return 'money';
        return 'other';
    }

    function isFollow(dofollowRaw, relRaw) {
        const d = String(dofollowRaw || '').toLowerCase();
        const r = String(relRaw || '').toLowerCase();
        if (d === '1' || d === 'true' || d === 'yes' || d === 'follow' || d === 'dofollow') return true;
        if (d === '0' || d === 'false' || d === 'no' || d === 'nofollow') return false;
        if (r.includes('nofollow') || r.includes('ugc') || r.includes('sponsored')) return false;
        return true;
    }

    function computeBacklinkRisk(row) {
        let score = 0;
        const anchor = String(row.anchor || '').toLowerCase();
        const dofollow = !!row.dofollow;
        const srcStatus = parseInt(String(row.sourceStatus || '').replace(/[^\d]/g, ''), 10);
        const tgtStatus = parseInt(String(row.targetStatus || '').replace(/[^\d]/g, ''), 10);
        const url = String(row.sourceUrl || '').toLowerCase();
        const tld = String(row.sourceTld || '').toLowerCase();
        const riskyTlds = ['xyz', 'top', 'cfd', 'sbs', 'monster', 'store', 'click', 'shop', 'site'];

        if (anchor && anchor !== '-' && anchor.split(' ').length <= 2) score += 10;
        if (anchor.includes('buy') || anchor.includes('cheap') || anchor.includes('casino') || anchor.includes('viagra')) score += 35;
        if (row.anchorType === 'money') score += 16;
        if (row.anchorType === 'brand') score -= 8;
        if (dofollow) score += 8;
        if (!Number.isNaN(srcStatus) && srcStatus >= 400) score += 22;
        if (!Number.isNaN(tgtStatus) && tgtStatus >= 400) score += 16;
        if (row.brokenBacklink) score += 28;
        if (row.isLost) score += 14;
        if (row.linkSpamScore > 0) score += Math.min(25, row.linkSpamScore);
        if (riskyTlds.indexOf(tld) !== -1) score += 18;
        if (url.includes('/tag/') || url.includes('/author/') || url.includes('/comments') || url.includes('?replytocom=')) score += 10;
        if (row.domainRank > 0 && row.domainRank <= 20) score += 8;
        if (row.pageRank > 0 && row.pageRank <= 20) score += 10;

        score = Math.max(0, Math.min(100, score));
        let risk = 'low';
        if (score >= 60) risk = 'high';
        else if (score >= 30) risk = 'medium';
        return { score, risk };
    }

    function renderBacklinkAuditTable() {
        const wrap = document.getElementById('lb-backlink-audit-wrap');
        if (!wrap) return;
        let rowsData = (state.backlinkAuditItems || []).slice();
        const riskFilter = (document.getElementById('lb-audit-risk-filter') || {}).value || '';
        const followFilter = (document.getElementById('lb-audit-follow-filter') || {}).value || '';
        const anchorFilter = (document.getElementById('lb-audit-anchor-filter') || {}).value || '';
        const healthFilter = (document.getElementById('lb-audit-health-filter') || {}).value || '';
        const search = String((document.getElementById('lb-audit-search') || {}).value || '').trim().toLowerCase();
        if (riskFilter) {
            rowsData = rowsData.filter(function (r) { return r.risk === riskFilter; });
        }
        if (followFilter === 'follow') rowsData = rowsData.filter(function (r) { return !!r.dofollow; });
        if (followFilter === 'nofollow') rowsData = rowsData.filter(function (r) { return !r.dofollow; });
        if (anchorFilter) rowsData = rowsData.filter(function (r) { return String(r.anchorType || '') === anchorFilter; });
        if (healthFilter === 'broken') rowsData = rowsData.filter(function (r) { return !!r.brokenBacklink; });
        if (healthFilter === 'new') rowsData = rowsData.filter(function (r) { return !!r.isNew; });
        if (healthFilter === 'lost') rowsData = rowsData.filter(function (r) { return !!r.isLost; });
        if (search) {
            rowsData = rowsData.filter(function (r) {
                const hay = [
                    r.sourceUrl, r.targetUrl, r.anchor, r.referringDomain, r.sourceHost,
                    r.sourceCountry, r.sourceTld, r.relRaw, r.topical
                ].join(' ').toLowerCase();
                return hay.indexOf(search) !== -1;
            });
        }

        if (!rowsData.length) {
            wrap.innerHTML = '<div class=\"lb-empty\">No backlink rows to display for current filter.</div>';
            return;
        }

        const rows = rowsData.map(function (r) {
            const riskBadge = r.risk === 'high'
                ? '<span class=\"lb-issue-badge is-error\">⚠ High (' + r.score + ')</span>'
                : (r.risk === 'medium'
                    ? '<span class=\"lb-issue-badge is-warning\">⚠ Medium (' + r.score + ')</span>'
                    : '<span class=\"lb-issue-badge is-ok\">✓ Low (' + r.score + ')</span>');
            const src = r.sourceUrl && r.sourceUrl !== '-'
                ? '<a href=\"' + esc(r.sourceUrl) + '\" target=\"_blank\" rel=\"noopener noreferrer\">' + esc(r.sourceUrl) + '</a>'
                : '-';
            const tgt = r.targetUrl && r.targetUrl !== '-'
                ? '<a href=\"' + esc(r.targetUrl) + '\" target=\"_blank\" rel=\"noopener noreferrer\">' + esc(r.targetUrl) + '</a>'
                : '-';
            const flags = [];
            if (r.brokenBacklink) flags.push('Broken');
            if (r.isNew) flags.push('New');
            if (r.isLost) flags.push('Lost');
            if (r.linkSpamScore > 0) flags.push('Spam ' + r.linkSpamScore);
            return '<tr>' +
                '<td><div class=\"lb-risk-cell\">' + riskBadge + '<span class=\"lb-mini-meta\">' + esc(flags.join(' | ') || 'Clean') + '</span></div></td>' +
                '<td>' + src + '</td>' +
                '<td>' + tgt + '</td>' +
                '<td>' + esc(r.anchor) + '</td>' +
                '<td>' + esc(r.anchorType || '-') + '</td>' +
                '<td>' + esc(r.referringDomain) + '</td>' +
                '<td>' + esc((r.sourceTld || '-') + ' / ' + (r.sourceCountry || '-')) + '</td>' +
                '<td>' + esc(r.relRaw || '-') + '</td>' +
                '<td>' + (r.dofollow ? 'Follow' : 'Nofollow') + '</td>' +
                '<td>' + esc(String(r.domainRank || '-')) + '</td>' +
                '<td>' + esc(String(r.pageRank || '-')) + '</td>' +
                '<td>' + esc(r.sourceStatus) + ' / ' + esc(r.targetStatus) + '</td>' +
                '<td>' + esc(r.firstSeen) + '</td>' +
                '<td>' + esc(r.lastSeen) + '</td>' +
                '<td>' + esc(r.topical || '-') + '</td>' +
            '</tr>';
        }).join('');

        wrap.innerHTML = '<table class=\"lb-table lb-table-audit\"><thead><tr><th>Risk</th><th>Backlink URL</th><th>Target URL</th><th>Anchor</th><th>Anchor type</th><th>Referring domain</th><th>TLD/Country</th><th>Rel</th><th>Follow</th><th>Domain rank</th><th>Page rank</th><th>HTTP src/tgt</th><th>First seen</th><th>Last seen</th><th>Type</th></tr></thead><tbody>' + rows + '</tbody></table>';
    }

    function updateBacklinkAuditCards() {
        const items = state.backlinkAuditItems || [];
        let low = 0, medium = 0, high = 0;
        let follow = 0, broken = 0;
        const refDomains = {};
        items.forEach(function (r) {
            if (r.risk === 'high') high++;
            else if (r.risk === 'medium') medium++;
            else low++;
            if (r.dofollow) follow++;
            if (r.brokenBacklink) broken++;
            if (r.referringDomain && r.referringDomain !== '-') refDomains[r.referringDomain.toLowerCase()] = 1;
        });
        const setText = function (id, value) {
            const el = document.getElementById(id);
            if (el) el.textContent = String(value);
        };
        setText('lb-audit-total', items.length);
        setText('lb-audit-refdomains', Object.keys(refDomains).length);
        setText('lb-audit-follow-rate', items.length ? (Math.round((follow / items.length) * 100) + '%') : '0%');
        setText('lb-audit-broken', broken);
        setText('lb-audit-low', low);
        setText('lb-audit-medium', medium);
        setText('lb-audit-high', high);
    }

    function runBacklinkAudit() {
        const currentHost = String(window.location.hostname || '').trim().toLowerCase();
        const domain = currentHost.replace(/^www\./, '');
        if (!domain) {
            document.getElementById('lb-backlink-audit-status').textContent = 'Cannot detect current domain.';
            return;
        }
        if (domain === 'localhost' || domain === '127.0.0.1' || domain.indexOf('.localhost') !== -1) {
            document.getElementById('lb-backlink-audit-status').textContent = 'Backlink audit is not available on local domains.';
            return;
        }
        document.getElementById('lb-backlink-audit-status').textContent = 'Running backlink audit for ' + domain + '...';
        postAjax('aysa_adverlink_backlink_audit', {
            domain: domain,
            project_id: projectId,
            limit: 200
        }).then(function (resp) {
            if (!resp || !resp.success) {
                document.getElementById('lb-backlink-audit-status').textContent = (resp && resp.data) ? String(resp.data) : 'Audit failed.';
                return;
            }
            const rawItems = (resp.data && Array.isArray(resp.data.items)) ? resp.data.items : [];
            const normalized = rawItems.map(normalizeBacklinkAuditItem).map(function (r) {
                const scored = computeBacklinkRisk(r);
                return Object.assign({}, r, scored);
            });
            state.backlinkAuditItems = normalized;
            updateBacklinkAuditCards();
            renderBacklinkAuditTable();
            if (resp.data && resp.data.fallback) {
                document.getElementById('lb-backlink-audit-status').textContent = 'Audit completed using the backup analysis flow: ' + normalized.length + ' rows analyzed.';
            } else {
                const generatedAt = (resp.data && resp.data.generated_at) ? String(resp.data.generated_at) : '';
                document.getElementById('lb-backlink-audit-status').textContent = 'Audit completed: ' + normalized.length + ' rows analyzed.' + (generatedAt ? (' Saved at: ' + generatedAt) : '');
            }
        }).catch(function (err) {
            document.getElementById('lb-backlink-audit-status').textContent = err && err.message ? err.message : 'Audit failed.';
        });
    }

    function loadBacklinkAuditSnapshot() {
        postAjax('aysa_adverlink_get_backlink_audit', {
            project_id: projectId
        }).then(function (resp) {
            if (!resp || !resp.success) return;
            const rawItems = (resp.data && Array.isArray(resp.data.items)) ? resp.data.items : [];
            if (!rawItems.length) {
                document.getElementById('lb-backlink-audit-status').textContent = 'No saved audit yet. Use Run audit now.';
                return;
            }
            const normalized = rawItems.map(normalizeBacklinkAuditItem).map(function (r) {
                const scored = computeBacklinkRisk(r);
                return Object.assign({}, r, scored);
            });
            state.backlinkAuditItems = normalized;
            updateBacklinkAuditCards();
            renderBacklinkAuditTable();
            const snapshot = (resp.data && resp.data.snapshot && typeof resp.data.snapshot === 'object') ? resp.data.snapshot : {};
            const generatedAt = snapshot.generated_at ? String(snapshot.generated_at) : '';
            const provider = snapshot.provider ? String(snapshot.provider) : 'snapshot';
            document.getElementById('lb-backlink-audit-status').textContent =
                'Loaded saved audit: ' + normalized.length + ' rows' + (generatedAt ? (' | Generated: ' + generatedAt) : '') + ' | Source: ' + provider;
        }).catch(function () {
            // Silent fail: keep default message
        });
    }

    function setGbpStatus(message, isError) {
        const el = document.getElementById('gbp-status');
        if (!el) return;
        el.textContent = String(message || '');
        el.style.color = isError ? '#b42318' : '';
    }

    function gbpAction(action, payload) {
        return postAjax(action, Object.assign({ project_id: projectId }, payload || {}));
    }

    function currentGbpLocation() {
        const overview = state.gbp.overview || {};
        const locations = Array.isArray(overview.locations) ? overview.locations : [];
        const selected = document.getElementById('gbp-active-location-select');
        const selectedName = selected ? String(selected.value || '') : '';
        if (selectedName) {
            const matched = locations.find(function (row) { return String(row.location_name || '') === selectedName; });
            if (matched) return matched;
        }
        return overview.primary_location || locations[0] || null;
    }

    function fillGbpEditors(location) {
        const loc = location || {};
        const raw = (loc && typeof loc.location_json === 'object' && loc.location_json) ? loc.location_json : {};
        document.getElementById('gbp-info-title').value = String(loc.title || raw.title || '');
        document.getElementById('gbp-info-phone').value = String(loc.primary_phone || raw.primaryPhone || '');
        document.getElementById('gbp-info-website').value = String(loc.website_uri || raw.websiteUri || '');
        document.getElementById('gbp-info-language').value = String(loc.language_code || raw.languageCode || '');
        const cat = raw.categories && raw.categories.primaryCategory && raw.categories.primaryCategory.displayName ? raw.categories.primaryCategory.displayName : '';
        document.getElementById('gbp-info-category').value = String(cat || '');
        const desc = raw.profile && raw.profile.description ? raw.profile.description : '';
        document.getElementById('gbp-info-description').value = String(desc || '');
        document.getElementById('gbp-regular-hours-json').value = JSON.stringify(raw.regularHours || {}, null, 2);
        document.getElementById('gbp-special-hours-json').value = JSON.stringify(raw.specialHours || {}, null, 2);
        document.getElementById('gbp-attributes-json').value = JSON.stringify(raw.attributes || [], null, 2);
        document.getElementById('gbp-services-json').value = JSON.stringify(raw.serviceItems || [], null, 2);
    }

    function setDisabled(id, disabled) {
        const el = document.getElementById(id);
        if (!el) return;
        el.disabled = !!disabled;
    }

    function applyGbpUiAvailability(overview) {
        const connection = (overview && typeof overview.connection === 'object') ? overview.connection : {};
        const locations = Array.isArray(overview.locations) ? overview.locations : [];
        const hasLocations = locations.length > 0;
        const hasAccounts = (Array.isArray(overview.accounts) ? overview.accounts : []).length > 0;
        const stateName = String(connection.state || '');

        const locationDependentIds = [
            'gbp-active-location-select',
            'gbp-set-primary-location',
            'gbp-sync-reviews',
            'gbp-refresh-performance',
            'gbp-refresh-verification',
            'gbp-save-business-info',
            'gbp-save-hours',
            'gbp-save-attributes',
            'gbp-save-services',
            'gbp-create-post',
            'gbp-upload-media',
            'gbp-get-verification-status',
            'gbp-start-verification',
            'gbp-delete-location'
        ];

        locationDependentIds.forEach(function (id) {
            setDisabled(id, !hasLocations);
        });
        setDisabled('gbp-sync-accounts', !connection.connected || !!connection.gbp_scopes_missing);
        setDisabled('gbp-create-location', !hasAccounts);
        setDisabled('gbp-create-account-name', !hasAccounts);
        setDisabled('gbp-sync-locations', !hasAccounts || !!connection.gbp_scopes_missing);

        const jumpBtn = document.getElementById('gbp-jump-create-location');
        if (jumpBtn) {
            jumpBtn.style.display = (!hasLocations && hasAccounts && stateName === 'connected_no_locations') ? '' : 'none';
        }
    }

    function renderGbpOverview(data) {
        state.gbp.overview = data || {};
        const overview = state.gbp.overview;
        const connection = (overview && typeof overview.connection === 'object') ? overview.connection : {};
        const accounts = Array.isArray(overview.accounts) ? overview.accounts : [];
        const locations = Array.isArray(overview.locations) ? overview.locations : [];
        const reviewsSummary = (overview && typeof overview.reviews_summary === 'object') ? overview.reviews_summary : {};
        const jobs = Array.isArray(overview.jobs) ? overview.jobs : [];
        const perf = (overview && typeof overview.performance_summary === 'object') ? overview.performance_summary : {};
        const primary = overview.primary_location || locations[0] || {};

        document.getElementById('gbp-card-accounts').textContent = String(accounts.length);
        document.getElementById('gbp-card-locations').textContent = String(locations.length);
        document.getElementById('gbp-card-reviews').textContent = String(reviewsSummary.count || 0);
        document.getElementById('gbp-card-rating').textContent = String(reviewsSummary.average_rating || 0);
        document.getElementById('gbp-card-jobs').textContent = String(jobs.length);
        const caps = connection.capabilities || {};
        document.getElementById('gbp-card-capabilities').textContent =
            ['gsc','ga4','gbp'].filter(function (k) { return !!caps[k]; }).join(', ') || 'none';

        const stateName = String(connection.state || '');
        const connMsg = String(connection.message || (
            connection.gbp_scopes_missing
                ? 'Google connected, but GBP scopes are missing. Reconnect Google.'
                : (connection.connected ? ('Connected as ' + String(connection.email || 'Google account')) : 'Google not connected.')
        ));
        document.getElementById('gbp-connection-status-text').textContent = connMsg;
        if (stateName === 'connected_no_accounts') {
            setGbpStatus('Google is connected, but no Business Profile accounts were found. Start with Sync accounts. If it still shows 0, this Google user does not own or manage a GBP account yet.', false);
        } else if (stateName === 'connected_no_locations') {
            setGbpStatus('Google is connected, but no Business Profile locations were found. Sync locations, create a location, or switch Google account.', false);
        } else {
            setGbpStatus('Latest GBP state loaded.', false);
        }

        const locationSelect = document.getElementById('gbp-active-location-select');
        if (locationSelect) {
            const previous = String(locationSelect.value || '');
            locationSelect.innerHTML = '';
            locations.forEach(function (row) {
                const opt = document.createElement('option');
                opt.value = String(row.location_name || '');
                opt.textContent = String(row.title || row.location_name || 'Location');
                if (row.is_primary) opt.textContent += ' (Primary)';
                locationSelect.appendChild(opt);
            });
            if (previous && locations.some(function (row) { return String(row.location_name || '') === previous; })) {
                locationSelect.value = previous;
            } else if (primary && primary.location_name) {
                locationSelect.value = String(primary.location_name);
            }
        }
        const accountInput = document.getElementById('gbp-create-account-name');
        if (accountInput && !accountInput.value && accounts[0] && accounts[0].account_name) {
            accountInput.value = String(accounts[0].account_name);
        }

        fillGbpEditors(currentGbpLocation());
        applyGbpUiAvailability(overview);

        document.getElementById('gbp-connection-wrap').innerHTML =
            '<div><strong>Status:</strong> ' + esc(connMsg) + '</div>'
            + '<div><strong>Scopes:</strong> ' + esc((connection.granted_scopes || []).join(', ')) + '</div>'
            + '<div><strong>Connection state:</strong> ' + esc(stateName || 'unknown') + '</div>'
            + '<div><strong>Accounts:</strong> ' + esc(String(connection.accounts_count || accounts.length || 0)) + '</div>'
            + '<div><strong>Locations:</strong> ' + esc(String(connection.locations_count || locations.length || 0)) + '</div>'
            + '<div><strong>Primary location:</strong> ' + esc(String(primary.title || primary.location_name || 'Not selected')) + '</div>'
            + (stateName === 'connected_no_accounts'
                ? '<div style="margin-top:8px;"><strong>Next step:</strong> Click <em>Sync accounts</em>. If accounts remain at 0, connect a Google user that already owns/manages a Business Profile account or create/claim the business in Google first.</div>'
                : '')
            + (stateName === 'connected_no_locations'
                ? '<div style="margin-top:8px;"><strong>Next step:</strong> Use <em>Create first location</em> or sync locations from the selected GBP account.</div>'
                : '');

        document.getElementById('gbp-locations-wrap').innerHTML =
            '<table class="widefat striped"><thead><tr><th>Location</th><th>Account</th><th>Website</th><th>Phone</th><th>Primary</th></tr></thead><tbody>'
            + (locations.length ? locations.map(function (row) {
                return '<tr><td>' + esc(String(row.title || row.location_name || '')) + '</td><td>' + esc(String(row.account_name || '')) + '</td><td>' + esc(String(row.website_uri || '')) + '</td><td>' + esc(String(row.primary_phone || '')) + '</td><td>' + (row.is_primary ? 'Yes' : 'No') + '</td></tr>';
            }).join('') : '<tr><td colspan="5">' + esc(
                stateName === 'connected_no_locations'
                    ? 'Google is connected, but no Business Profile locations were found yet.'
                    : 'No locations synced yet.'
            ) + '</td></tr>')
            + '</tbody></table>';

        const perfMetrics = perf.metrics && perf.metrics.multiDailyMetricTimeSeries ? perf.metrics.multiDailyMetricTimeSeries : [];
        document.getElementById('gbp-performance-wrap').innerHTML =
            '<div><strong>Performance updated:</strong> ' + esc(String(perf.updated_at || '')) + '</div>'
            + '<div><strong>Metric series:</strong> ' + esc(String(perfMetrics.length || 0)) + '</div>';

        const latestReviews = Array.isArray(reviewsSummary.latest_reviews) ? reviewsSummary.latest_reviews : [];
        document.getElementById('gbp-reviews-wrap').innerHTML =
            '<table class="widefat striped"><thead><tr><th>Reviewer</th><th>Stars</th><th>Comment</th><th>Reply</th></tr></thead><tbody>'
            + (latestReviews.length ? latestReviews.map(function (row) {
                const reviewName = String(row.review_name || '');
                const reply = row.reply && row.reply.comment ? String(row.reply.comment) : '';
                return '<tr><td>' + esc(String(row.reviewer_name || '')) + '</td><td>' + esc(String(row.star_rating || '')) + '</td><td>' + esc(String(row.comment_text || '')) + '</td><td>'
                    + '<textarea data-gbp-review-name="' + esc(reviewName) + '" class="gbp-review-reply" rows="2">' + esc(reply) + '</textarea>'
                    + '<div class="lb-actions-row" style="margin-top:6px;"><button type="button" class="button gbp-save-review-reply" data-review-name="' + esc(reviewName) + '">Save reply</button><button type="button" class="button gbp-delete-review-reply" data-review-name="' + esc(reviewName) + '">Delete reply</button></div>'
                    + '</td></tr>';
            }).join('') : '<tr><td colspan="4">No reviews synced yet.</td></tr>')
            + '</tbody></table>';

        document.getElementById('gbp-jobs-wrap').innerHTML =
            '<table class="widefat striped"><thead><tr><th>Job</th><th>Status</th><th>Updated</th><th>Error</th></tr></thead><tbody>'
            + (jobs.length ? jobs.map(function (row) {
                return '<tr><td>' + esc(String(row.job_type || '')) + '</td><td>' + esc(String(row.status || '')) + '</td><td>' + esc(String(row.updated_at || '')) + '</td><td>' + esc(String(row.error || '')) + '</td></tr>';
            }).join('') : '<tr><td colspan="4">No jobs yet.</td></tr>')
            + '</tbody></table>';

        const verification = (overview && typeof overview.verification_summary === 'object') ? overview.verification_summary : {};
        document.getElementById('gbp-verification-wrap').innerHTML =
            '<div><strong>Updated:</strong> ' + esc(String(verification.updated_at || '')) + '</div>'
            + '<div><strong>Voice of merchant:</strong> <pre>' + esc(JSON.stringify(verification.voice_of_merchant || {}, null, 2)) + '</pre></div>'
            + '<div><strong>Options:</strong> <pre>' + esc(JSON.stringify(verification.options || {}, null, 2)) + '</pre></div>';
    }

    function loadGbpOverview() {
        setGbpStatus('Loading Google Business Profile overview...', false);
        return gbpAction('aysa_gbp_get_overview', {}).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error((resp && resp.data) ? String(resp.data) : 'GBP overview failed.');
            }
            renderGbpOverview(resp.data || {});
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'GBP overview failed.', true);
        });
    }

    function openGbpConnect() {
        return postAjax('aysa_google_get_auth_url', {
            project_id: projectId,
            return_url: window.location.href.replace(/#.*$/, '') + '#google-business-profile'
        }).then(function (resp) {
            if (!resp || !resp.success || !resp.data || !resp.data.auth_url) {
                throw new Error((resp && resp.data) ? String(resp.data) : 'Could not create Google auth URL.');
            }
            window.location.href = String(resp.data.auth_url);
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not start Google OAuth.', true);
        });
    }

    function startGbpJob(jobType, extra) {
        setGbpStatus('Starting GBP job: ' + jobType + '...', false);
        return gbpAction('aysa_gbp_start_job', Object.assign({ job_type: jobType, location_name: String((currentGbpLocation() || {}).location_name || '') }, extra || {})).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error((resp && resp.data) ? String(resp.data) : 'Could not start GBP job.');
            }
            state.gbp.currentJob = resp.data && resp.data.job ? resp.data.job : null;
            if (state.gbp.pollTimer) window.clearTimeout(state.gbp.pollTimer);
            state.gbp.pollTimer = window.setTimeout(pollGbpJob, 2500);
            setGbpStatus('GBP job queued...', false);
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not start GBP job.', true);
        });
    }

    function pollGbpJob() {
        return gbpAction('aysa_gbp_get_job_status', {}).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error((resp && resp.data) ? String(resp.data) : 'Could not fetch GBP job status.');
            }
            const job = resp.data || {};
            state.gbp.currentJob = job;
            const status = String(job.status || '');
            setGbpStatus('Latest GBP job status: ' + (status || 'idle'), status === 'failed');
            if (status === 'queued' || status === 'running') {
                state.gbp.pollTimer = window.setTimeout(pollGbpJob, 4000);
            } else {
                loadGbpOverview();
            }
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not fetch GBP job status.', true);
        });
    }

    function switchMainTab(tabName) {
        const sections = {
            'link-building': document.getElementById('lb-view-link-building'),
            'link-exchange': document.getElementById('lb-view-link-exchange'),
            'draft-articles': document.getElementById('lb-view-draft-articles'),
            'published-articles': document.getElementById('lb-view-published-articles'),
            'backlink-audit': document.getElementById('lb-view-backlink-audit'),
            'google-business-profile': document.getElementById('lb-view-google-business-profile')
        };
        Object.keys(sections).forEach(function (key) {
            if (!sections[key]) return;
            sections[key].style.display = key === tabName ? 'block' : 'none';
        });
        document.querySelectorAll('.lb-main-tab').forEach(function (btn) {
            const active = btn.getAttribute('data-main-tab') === tabName;
            btn.classList.toggle('is-active', active);
        });
        if (tabName === 'draft-articles') {
            loadPublisherArticles('draft');
            schedulePublisherArticlesRefresh('draft', 1200);
        } else if (tabName === 'link-exchange') {
            loadExchangePortals(false);
            loadExchangeRequests();
        } else if (tabName === 'published-articles') {
            loadPublisherArticles('published');
            schedulePublisherArticlesRefresh('published', 1200);
        } else if (tabName === 'google-business-profile') {
            loadGbpOverview();
        }
    }

    function applyInitialTabFromHash() {
        const hash = String(window.location.hash || '').replace(/^#/, '');
        if (hash === 'draft-articles' || hash === 'published-articles' || hash === 'backlink-audit' || hash === 'link-building' || hash === 'link-exchange' || hash === 'google-business-profile') {
            switchMainTab(hash);
            return true;
        }
        return false;
    }

    async function refreshOrdersTracking() {
        await postAjax('aysa_adverlink_get_orders', { project_id: projectId }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error((resp && resp.data) ? String(resp.data) : 'Failed to load orders.');
            }
            state.orders = (resp.data && resp.data.items) ? resp.data.items : [];
        });
        const trackable = (state.orders || []).filter(function (o) {
            const ref = String(o.order_ref || '');
            if (o.is_trackable_ref === false) return false;
            return ref !== '' && ref.indexOf('local-') !== 0;
        });
        if (!trackable.length) {
            setStatus('No external order refs available for tracking yet.', true);
            loadOrders();
            return;
        }
        setStatus('Refreshing tracking for ' + trackable.length + ' orders...', false);
        for (let i = 0; i < trackable.length; i++) {
            const order = trackable[i];
            await postAjax('aysa_adverlink_track_order', {
                project_id: projectId,
                order_ref: String(order.order_ref || '')
            }).catch(function () { return null; });
        }
        setStatus('Tracking refresh complete.', false);
        loadOrders();
        loadCredits();
        loadLinkIssues(true);
    }

    function bindClick(id, handler) {
        const el = document.getElementById(id);
        if (!el) return;
        el.addEventListener('click', handler);
    }

    bindClick('lb-search-btn', function () {
        if (!state.portals.length) {
            loadPortals(true);
            return;
        }
        refreshFilteredView();
    });

    bindClick('lb-refresh-orders', function () {
        refreshOrdersTracking();
    });
    bindClick('gbp-refresh-overview', function () {
        loadGbpOverview();
    });
    bindClick('gbp-sync-accounts', function () {
        startGbpJob('accounts_sync');
    });
    bindClick('gbp-connect-google', function () {
        openGbpConnect();
    });
    bindClick('gbp-jump-create-location', function () {
        const target = document.getElementById('gbp-create-location-json');
        if (!target) return;
        target.scrollIntoView({ behavior: 'smooth', block: 'center' });
        target.focus();
    });
    bindClick('gbp-sync-locations', function () {
        startGbpJob('locations_sync');
    });
    bindClick('gbp-sync-reviews', function () {
        startGbpJob('reviews_sync');
    });
    bindClick('gbp-refresh-performance', function () {
        startGbpJob('performance_refresh');
    });
    bindClick('gbp-refresh-verification', function () {
        startGbpJob('verification_status_refresh');
    });
    bindClick('gbp-set-primary-location', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_set_primary_location', { location_name: String(location.location_name) }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not set primary location.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not set primary location.', true);
        });
    });
    bindClick('gbp-save-business-info', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        const patch = {
            title: document.getElementById('gbp-info-title').value || '',
            primaryPhone: document.getElementById('gbp-info-phone').value || '',
            websiteUri: document.getElementById('gbp-info-website').value || '',
            languageCode: document.getElementById('gbp-info-language').value || '',
            profile: { description: document.getElementById('gbp-info-description').value || '' }
        };
        const categoryName = document.getElementById('gbp-info-category').value || '';
        if (categoryName.trim()) {
            patch.categories = { primaryCategory: { displayName: categoryName.trim() } };
        }
        gbpAction('aysa_gbp_update_location_info', { location_name: String(location.location_name), patch: JSON.stringify(patch) }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not update business info.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not update business info.', true);
        });
    });
    bindClick('gbp-save-hours', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_update_hours', {
            location_name: String(location.location_name),
            regularHours: document.getElementById('gbp-regular-hours-json').value || '{}',
            specialHours: document.getElementById('gbp-special-hours-json').value || '{}'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not update hours.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not update hours.', true);
        });
    });
    bindClick('gbp-save-attributes', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_update_attributes', {
            location_name: String(location.location_name),
            attributes: document.getElementById('gbp-attributes-json').value || '[]'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not update attributes.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not update attributes.', true);
        });
    });
    bindClick('gbp-save-services', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_update_services', {
            location_name: String(location.location_name),
            serviceItems: document.getElementById('gbp-services-json').value || '[]'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not update services.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not update services.', true);
        });
    });
    bindClick('gbp-create-post', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_create_post', {
            location_name: String(location.location_name),
            post: document.getElementById('gbp-post-json').value || '{}'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not create GBP post.');
            setGbpStatus('GBP post created.', false);
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not create GBP post.', true);
        });
    });
    bindClick('gbp-upload-media', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_upload_media', {
            location_name: String(location.location_name),
            media: document.getElementById('gbp-media-json').value || '{}'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not upload GBP media.');
            setGbpStatus('GBP media upload requested.', false);
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not upload GBP media.', true);
        });
    });
    bindClick('gbp-get-verification-status', function () {
        gbpAction('aysa_gbp_get_verification_status', {
            location_name: String((currentGbpLocation() || {}).location_name || '')
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not get verification status.');
            const payload = resp.data && resp.data.verification ? resp.data.verification : {};
            document.getElementById('gbp-verification-wrap').innerHTML = '<pre>' + esc(JSON.stringify(payload, null, 2)) + '</pre>';
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not get verification status.', true);
        });
    });
    bindClick('gbp-start-verification', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_start_verification', {
            location_name: String(location.location_name),
            verification: document.getElementById('gbp-verification-json').value || '{}'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not start verification.');
            setGbpStatus('Verification flow started.', false);
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not start verification.', true);
        });
    });
    bindClick('gbp-create-location', function () {
        gbpAction('aysa_gbp_create_location', {
            account_name: document.getElementById('gbp-create-account-name').value || '',
            location: document.getElementById('gbp-create-location-json').value || '{}'
        }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not create location.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not create location.', true);
        });
    });
    bindClick('gbp-delete-location', function () {
        const location = currentGbpLocation();
        if (!location || !location.location_name) {
            setGbpStatus('Choose a location first.', true);
            return;
        }
        gbpAction('aysa_gbp_delete_location', { location_name: String(location.location_name) }).then(function (resp) {
            if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not delete location.');
            loadGbpOverview();
        }).catch(function (err) {
            setGbpStatus(err && err.message ? err.message : 'Could not delete location.', true);
        });
    });
    const gbpLocationSelect = document.getElementById('gbp-active-location-select');
    if (gbpLocationSelect) {
        gbpLocationSelect.addEventListener('change', function () {
            fillGbpEditors(currentGbpLocation());
        });
    }
    bindClick('lb-exchange-refresh-portals', function () {
        loadExchangePortals(true);
    });
    bindClick('lb-exchange-refresh-requests', function () {
        loadExchangeRequests();
    });

    bindClick('lb-refresh-link-issues', function () {
        loadLinkIssues(true);
    });
    bindClick('lb-run-backlink-audit', function () {
        runBacklinkAudit();
    });

    bindClick('lb-refresh-lb-credits', function () {
        loadCredits();
        loadPortals(true);
    });
    bindClick('lb-refresh-draft-articles', function () {
        loadPublisherArticles('draft');
    });
    bindClick('lb-refresh-published-articles', function () {
        loadPublisherArticles('published');
    });
    bindClick('lb-save-publisher-draft', function () {
        const current = state.currentPublisherDraft;
        if (!current || !current.id) {
            setPublisherArticlesStatus('draft', 'Open a draft first.', true);
            return;
        }
        const title = (document.getElementById('lb-draft-edit-title').value || '').trim();
        const excerpt = (document.getElementById('lb-draft-edit-excerpt').value || '').trim();
        const bodyHtml = (document.getElementById('lb-draft-edit-body').value || '').trim();
        if (!title || !bodyHtml) {
            setPublisherArticlesStatus('draft', 'Title and body are required.', true);
            return;
        }
        setPublisherArticlesStatus('draft', 'Saving draft...', false);
        postAsyncAjax('publisher_draft_update', {
            project_id: projectId,
            draft_id: current.id,
            title: title,
            excerpt: excerpt,
            body_html: bodyHtml,
            status: 'edited'
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setPublisherArticlesStatus('draft', ajaxErrorMessage(resp, 'Failed to save draft.'), true);
                return;
            }
            const draft = (resp.data && resp.data.draft) ? resp.data.draft : null;
            renderPublisherDraftPreview(draft);
            loadPublisherArticles('draft');
            setPublisherArticlesStatus('draft', 'Draft saved.', false);
        }).catch(function (err) {
            setPublisherArticlesStatus('draft', err && err.message ? err.message : 'Failed to save draft.', true);
        });
    });
    bindClick('lb-approve-publisher-draft', function () {
        const current = state.currentPublisherDraft;
        if (!current || !current.id) {
            setPublisherArticlesStatus('draft', 'Open a draft first.', true);
            return;
        }
        setPublisherArticlesStatus('draft', 'Approving draft for publishing...', false);
        postAsyncAjax('publisher_draft_approve', {
            project_id: projectId,
            draft_id: current.id
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setPublisherArticlesStatus('draft', ajaxErrorMessage(resp, 'Failed to approve draft.'), true);
                return;
            }
            const draft = (resp.data && resp.data.draft) ? resp.data.draft : null;
            renderPublisherDraftPreview(draft);
            loadPublisherArticles('draft');
            loadPublisherArticles('published');
            setPublisherArticlesStatus('draft', 'Draft approved. It remains here until the placement is live, then it moves to Published Articles.', false);
        }).catch(function (err) {
            setPublisherArticlesStatus('draft', err && err.message ? err.message : 'Failed to approve draft.', true);
        });
    });

    bindClick('lb-advanced-btn', function () {
        setStatus('Advanced filters are active in current filter rows.', false);
    });

    bindClick('lb-refresh-marketplace-diagnostics', function () {
        loadMarketplaceDiagnostics();
    });
    bindClick('lb-exchange-close', closeExchangeModal);
    bindClick('lb-exchange-cancel', closeExchangeModal);
    bindClick('lb-exchange-send', function () {
        if (!state.exchangeSelectedPortal) {
            return;
        }
        const statusEl = document.getElementById('lb-exchange-modal-status');
        statusEl.textContent = 'Sending exchange request...';
        statusEl.style.color = '#344054';
        postAsyncAjax('exchange_request_create', {
            project_id: projectId,
            counterparty_portal_json: JSON.stringify(state.exchangeSelectedPortal),
            requester_target_url: document.getElementById('lb-exchange-requester-target').value.trim(),
            requester_anchor_text: document.getElementById('lb-exchange-requester-anchor').value.trim(),
            counterparty_target_url: document.getElementById('lb-exchange-counterparty-target').value.trim(),
            counterparty_anchor_text: document.getElementById('lb-exchange-counterparty-anchor').value.trim(),
            requester_notes: document.getElementById('lb-exchange-requester-notes').value.trim()
        }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Could not create exchange request.'));
            }
            closeExchangeModal();
            loadExchangeRequests();
            setExchangeRequestsStatus('Exchange request sent.', false);
        }).catch(function (err) {
            statusEl.textContent = err && err.message ? err.message : 'Could not create exchange request.';
            statusEl.style.color = '#b42318';
        });
    });
    bindClick('lb-exchange-accept-btn', function () {
        if (!state.currentExchangeRequest) return;
        const counterpartyTargetUrl = window.prompt('Target URL you want linked from the requester site:', String(state.currentExchangeRequest.counterparty_target_url || '')) || '';
        const counterpartyAnchorText = window.prompt('Anchor text they should use:', String(state.currentExchangeRequest.counterparty_anchor_text || '')) || '';
        exchangeAction('accept', {
            counterparty_target_url: counterpartyTargetUrl,
            counterparty_anchor_text: counterpartyAnchorText
        });
    });
    bindClick('lb-exchange-reject-btn', function () {
        exchangeAction('reject');
    });
    bindClick('lb-exchange-verify-btn', function () {
        exchangeAction('verify');
    });
    bindClick('lb-exchange-dispute-btn', function () {
        const reason = window.prompt('Reason for dispute:', '') || '';
        exchangeAction('dispute', { reason: reason });
    });
    bindClick('lb-exchange-refresh-sources-btn', function () {
        loadExchangeActivationCandidates();
    });
    bindClick('lb-exchange-publish-btn', function () {
        if (!state.currentExchangeRequest) return;
        const select = document.getElementById('lb-exchange-source-post');
        const sourcePostId = select ? String(select.value || '').trim() : '';
        if (!sourcePostId) {
            return;
        }
        postAsyncAjax('exchange_activate_link', {
            project_id: projectId,
            exchange_ref: String(state.currentExchangeRequest.exchange_ref || ''),
            source_post_id: sourcePostId
        }).then(function (resp) {
            if (!resp || !resp.success) {
                throw new Error(ajaxErrorMessage(resp, 'Could not activate reciprocal link.'));
            }
            const placementMode = String((resp.data && resp.data.placement_mode) || '');
            if (placementMode === 'partner_box_fallback') {
                setExchangeRequestsStatus('Activated using partner box fallback at the end of the selected content.', false);
            } else if (placementMode === 'semantic_match') {
                setExchangeRequestsStatus('Activated using a semantically matched source page.', false);
            } else {
                setExchangeRequestsStatus('Reciprocal link activated successfully.', false);
            }
            loadExchangeRequests();
            return reloadExchangeRequest(String(state.currentExchangeRequest.exchange_ref || ''));
        }).catch(function (err) {
            setExchangeRequestsStatus(err && err.message ? err.message : 'Could not activate reciprocal link.', true);
        });
    });

    bindClick('lb-saved-btn', function () {
        setStatus('Saved searches will be added in next step.', false);
    });

    const auditRiskFilter = document.getElementById('lb-audit-risk-filter');
    if (auditRiskFilter) {
        auditRiskFilter.addEventListener('change', function () {
            renderBacklinkAuditTable();
        });
    }
    ['lb-audit-follow-filter', 'lb-audit-anchor-filter', 'lb-audit-health-filter'].forEach(function (id) {
        const el = document.getElementById(id);
        if (!el) return;
        el.addEventListener('change', function () {
            renderBacklinkAuditTable();
        });
    });
    const auditSearch = document.getElementById('lb-audit-search');
    if (auditSearch) {
        let searchTimer = null;
        auditSearch.addEventListener('input', function () {
            if (searchTimer) window.clearTimeout(searchTimer);
            searchTimer = window.setTimeout(function () {
                renderBacklinkAuditTable();
            }, 160);
        });
    }

    document.querySelectorAll('.lb-main-tab').forEach(function (btn) {
        btn.addEventListener('click', function () {
            const tab = btn.getAttribute('data-main-tab') || 'link-building';
            switchMainTab(tab);
        });
    });

    Array.from(document.querySelectorAll('.lb-offer-check')).forEach(function (el) {
        el.addEventListener('change', function () {
            loadPortals(true);
        });
    });

    ['lb-domain-query','lb-keyword-search','lb-theme','lb-country','lb-portal-type','lb-region','lb-dofollow','lb-price-from','lb-price-to','lb-min-dr','lb-min-ahrefs','lb-min-trust','lb-billing-type'].forEach(function(id){
        const el=document.getElementById(id);
        if (!el) return;
        el.addEventListener('change', refreshFilteredView);
        if (el.tagName === 'INPUT') {
            el.addEventListener('keyup', function(e){ if (e.key === 'Enter') refreshFilteredView(); });
        }
    });
    ['lb-exchange-search','lb-exchange-country','lb-exchange-language','lb-exchange-topic'].forEach(function(id){
        const el=document.getElementById(id);
        if (!el) return;
        el.addEventListener('change', function () {
            state.exchangeFiltered = filterExchangePortals(state.exchangePortals);
            renderExchangePortals();
        });
        el.addEventListener('keyup', function(e){
            if (e.key === 'Enter') {
                state.exchangeFiltered = filterExchangePortals(state.exchangePortals);
                renderExchangePortals();
            }
        });
    });

    document.addEventListener('click', function (e) {
        const saveReply = e.target.closest('.gbp-save-review-reply');
        if (saveReply) {
            const reviewName = String(saveReply.getAttribute('data-review-name') || '');
            const box = document.querySelector('textarea.gbp-review-reply[data-gbp-review-name="' + reviewName.replace(/"/g, '\\"') + '"]');
            const comment = box ? String(box.value || '') : '';
            gbpAction('aysa_gbp_reply_review', { review_name: reviewName, comment: comment }).then(function (resp) {
                if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not save review reply.');
                setGbpStatus('Review reply saved.', false);
            }).catch(function (err) {
                setGbpStatus(err && err.message ? err.message : 'Could not save review reply.', true);
            });
            return;
        }
        const deleteReply = e.target.closest('.gbp-delete-review-reply');
        if (deleteReply) {
            const reviewName = String(deleteReply.getAttribute('data-review-name') || '');
            gbpAction('aysa_gbp_delete_review_reply', { review_name: reviewName }).then(function (resp) {
                if (!resp || !resp.success) throw new Error((resp && resp.data) ? String(resp.data) : 'Could not delete review reply.');
                setGbpStatus('Review reply deleted.', false);
                loadGbpOverview();
            }).catch(function (err) {
                setGbpStatus(err && err.message ? err.message : 'Could not delete review reply.', true);
            });
            return;
        }
        const openDraftBtn = e.target.closest('.lb-open-publisher-draft');
        if (openDraftBtn) {
            openPublisherDraft(Number(openDraftBtn.getAttribute('data-draft-id') || '0'));
            return;
        }
        const openExchangeBtn = e.target.closest('.lb-open-exchange-modal');
        if (openExchangeBtn) {
            openExchangeModal(Number(openExchangeBtn.getAttribute('data-row') || '0'));
            return;
        }
        const openExchangeRequestBtn = e.target.closest('.lb-open-exchange-request');
        if (openExchangeRequestBtn) {
            reloadExchangeRequest(String(openExchangeRequestBtn.getAttribute('data-ref') || '')).catch(function (err) {
                setExchangeRequestsStatus(err && err.message ? err.message : 'Could not load exchange request.', true);
            });
            return;
        }
        if (e.target && e.target.getAttribute('data-exchange-close') === '1') {
            closeExchangeModal();
            return;
        }
        const btn = e.target.closest('.lb-order-article');
        if (!btn) return;
        if (btn.classList.contains('is-disabled') || btn.disabled) return;
        const idx = Number(btn.getAttribute('data-row'));
        const mode = btn.getAttribute('data-mode') || 'add_new_article';
        if (!Number.isFinite(idx)) return;
        fillOrderPanel(idx, mode);
    });

    function closeArticleModal() {
        const modal = document.getElementById('lb-article-modal');
        if (modal) modal.style.display = 'none';
    }

    bindClick('lb-article-close', closeArticleModal);
    bindClick('lb-modal-cancel', closeArticleModal);
    bindClick('lb-save-draft', function () {
        if (!state.selected) {
            setOrderStatus('Select a portal first.', true);
            return;
        }
        const portalId = state.selected.portal_id || state.selected.id || '';
        if (!portalId) {
            setOrderStatus('Selected portal has no valid portal_id.', true);
            return;
        }
        setOrderStatus('Saving draft...', false);
        const draft = getDraftPayload();
        postAjax('aysa_adverlink_save_article_draft', {
            project_id: projectId,
            portal_id: portalId,
            draft_json: JSON.stringify(draft)
        }).then(function (resp) {
            if (!resp || !resp.success) {
                setOrderStatus((resp && resp.data) ? String(resp.data) : 'Draft save failed.', true);
                return;
            }
            setOrderStatus('Draft saved.', false);
        }).catch(function (err) {
            setOrderStatus(err && err.message ? err.message : 'Draft save failed.', true);
        });
    });
    document.addEventListener('click', function (e) {
        const tab = e.target.closest('.lb-order-tab');
        if (!tab) return;
        const mode = tab.getAttribute('data-mode') || '';
        if (!mode || tab.classList.contains('is-disabled') || tab.disabled) {
            setOrderStatus('This tab is inactive in this phase. Use Sponsored article.', true);
            return;
        }
        setOrderMode(mode);
        if (mode === 'link_insertion') {
            setOrderStatus('Link placement mode active. Select a keyword and target page from your associations.', false);
        } else if (mode === 'seo_text_ads') {
            setOrderStatus('SEO text ads mode active. Set the ad creative and choose a destination page from your associations.', false);
        } else {
            setOrderStatus('Sponsored article mode active.', false);
        }
    });
    const liKeywordInput = document.getElementById('lb-li-keyword');
    if (liKeywordInput) {
        liKeywordInput.addEventListener('input', function () {
            if (linkTargetSearchTimer) {
                clearTimeout(linkTargetSearchTimer);
            }
            linkTargetSearchTimer = setTimeout(function () {
                loadLinkTargetsFromKeyword();
            }, 350);
        });
    }
    const liSearchInput = document.getElementById('lb-li-target-search');
    if (liSearchInput) {
        liSearchInput.addEventListener('input', function () {
            if (linkTargetSearchTimer) {
                clearTimeout(linkTargetSearchTimer);
            }
            linkTargetSearchTimer = setTimeout(function () {
                loadLinkTargetsFromKeyword();
            }, 200);
        });
    }
    const adsKeywordInput = document.getElementById('lb-ads-keyword');
    if (adsKeywordInput) {
        adsKeywordInput.addEventListener('input', function () {
            if (linkTargetSearchTimer) {
                clearTimeout(linkTargetSearchTimer);
            }
            linkTargetSearchTimer = setTimeout(function () {
                loadSeoAdsTargetsFromKeyword();
            }, 350);
        });
    }
    const adsSearchInput = document.getElementById('lb-ads-target-search');
    if (adsSearchInput) {
        adsSearchInput.addEventListener('input', function () {
            if (linkTargetSearchTimer) {
                clearTimeout(linkTargetSearchTimer);
            }
            linkTargetSearchTimer = setTimeout(function () {
                loadSeoAdsTargetsFromKeyword();
            }, 200);
        });
    }
    ['lb-ads-title','lb-ads-display-url','lb-ads-description'].forEach(function(id){
        const el = document.getElementById(id);
        if (!el) return;
        el.addEventListener('input', updateSeoAdsPreview);
    });
    ['lb-modal-billing-type','lb-li-billing-type'].forEach(function(id){
        const el = document.getElementById(id);
        if (!el) return;
        el.addEventListener('change', updateModePricesUi);
    });
    document.addEventListener('click', function (e) {
        const row = e.target.closest('.lb-li-item[data-li-index]');
        if (!row) return;
        const idx = Number(row.getAttribute('data-li-index'));
        if (!Number.isFinite(idx)) return;
        if (!Array.isArray(state.linkTargets) || !state.linkTargets[idx]) return;
        applySelectedLinkTarget(state.linkTargets[idx]);
        renderLinkTargets();
    });
    document.addEventListener('click', function (e) {
        const row = e.target.closest('.lb-li-item[data-ads-index]');
        if (!row) return;
        const idx = Number(row.getAttribute('data-ads-index'));
        if (!Number.isFinite(idx)) return;
        if (!Array.isArray(state.seoAdsTargets) || !state.seoAdsTargets[idx]) return;
        applySelectedSeoAdsTarget(state.seoAdsTargets[idx]);
        renderSeoAdsTargets();
    });
    document.addEventListener('click', function (e) {
        const relBtn = e.target.closest('.lb-rel-quick');
        if (!relBtn) return;
        const rel = relBtn.getAttribute('data-rel') || 'follow';
        const relSelect = document.getElementById('lb-modal-rel-type');
        if (relSelect) relSelect.value = rel;
    });
    document.addEventListener('click', function (e) {
        const t = e.target.closest('.lb-content-template');
        if (!t) return;
        const key = t.getAttribute('data-template') || '';
        const templates = {
            intro: '<p>Write a short intro paragraph that explains what this article covers and why it matters.</p>',
            h2: '<h2>Chapter title</h2><p>Explain this chapter with useful and clear details.</p>',
            faq: '<h2>Frequently asked questions</h2><h3>Question</h3><p>Answer</p>',
            cta: '<p><strong>Call to action:</strong> Add a clear next step for the reader.</p>'
        };
        const snippet = templates[key];
        if (!snippet) return;
        if (window.tinyMCE && window.tinyMCE.get && window.tinyMCE.get('lb-modal-content')) {
            window.tinyMCE.get('lb-modal-content').execCommand('mceInsertContent', false, snippet);
        } else {
            const ta = document.getElementById('lb-modal-content');
            const start = ta.selectionStart || ta.value.length;
            const end = ta.selectionEnd || ta.value.length;
            const before = ta.value.substring(0, start);
            const after = ta.value.substring(end);
            ta.value = before + snippet + after;
        }
    });
    document.addEventListener('click', function (e) {
        if (e.target && e.target.getAttribute && e.target.getAttribute('data-close') === '1') {
            closeArticleModal();
        }
    });

    bindClick('lb-place-order', function () {
        if (!state.selected) {
            setOrderStatus('Select a portal first.', true);
            return;
        }
        const portalId = state.selected.portal_id || state.selected.id || '';
        if (!portalId) {
            setOrderStatus('Selected portal has no valid portal_id.', true);
            return;
        }

        const price = getModeServicePrice(state.selected, state.orderMode);
        const estimatedCredits = price > 0 ? Math.round(price * 100) : 0;
        if (estimatedCredits <= 0) {
            setOrderStatus('No price configured for selected portal/service/billing. Choose another option.', true);
            return;
        }
        const modeUsesIncludedLink = ['add_new_article', 'link_insertion', 'seo_text_ads'].indexOf(String(state.orderMode || 'add_new_article')) !== -1;
        if (estimatedCredits > 0 && Number(state.availableCredits || 0) < estimatedCredits && !(modeUsesIncludedLink && Number(state.includedLinksRemaining || 0) > 0)) {
            setOrderStatus('Insufficient credits. Preparing payment link for the missing amount...', false);
        }

        let payload = {
            project_id: projectId,
            portal_id: portalId,
            portal_domain: state.selected.domain || state.selected.url || state.selected.name || '',
            estimated_credits: estimatedCredits,
            service_type: 'seo_article',
            client_ref: generateClientRef('AYSA'),
            client_name: '<?php echo esc_js(get_bloginfo('name')); ?>',
            project_ref: 'wp-project-<?php echo esc_js((string) get_option('aysa_project_id', 0)); ?>'
        };

        if (state.orderMode === 'link_insertion') {
            const liKeyword = (document.getElementById('lb-li-keyword').value || '').trim();
            const selectedTarget = state.selectedLinkTarget;
            const targetUrl = selectedTarget && selectedTarget.url ? String(selectedTarget.url).trim() : '';
            if (!liKeyword || !targetUrl) {
                setOrderStatus('Required for link placement: keyword and selected target page.', true);
                return;
            }
            const liTitle = 'Link placement - ' + liKeyword;
            payload = Object.assign(payload, {
                service_type: 'link_insertion',
                billing_type: document.getElementById('lb-li-billing-type').value || 'one_time',
                keyword: liKeyword,
                target_url: targetUrl,
                title: liTitle,
                rel_type: document.getElementById('lb-li-rel-type').value || 'follow',
                order_meta_json: JSON.stringify({
                    workflow: 'manual_link_insertion_v1',
                    request_mode: 'link_insertion',
                    special_remarks: (document.getElementById('lb-li-remarks').value || '').trim(),
                    selected_target: selectedTarget || null
                })
            });
        } else if (state.orderMode === 'seo_text_ads') {
            const adsTitle = (document.getElementById('lb-ads-title').value || '').trim();
            const adsKeyword = (document.getElementById('lb-ads-keyword').value || '').trim();
            const selectedTarget = state.selectedSeoAdsTarget;
            const adsTargetUrl = selectedTarget && selectedTarget.url ? String(selectedTarget.url).trim() : '';
            const adDisplayUrl = (document.getElementById('lb-ads-display-url').value || '').trim();
            const targetArticleUrl = (document.getElementById('lb-ads-target-article-url').value || '').trim();
            const adDescription = (document.getElementById('lb-ads-description').value || '').trim();
            const rawDuration = parseInt((document.getElementById('lb-ads-duration-months').value || '1').trim(), 10);
            const durationMonths = Number.isFinite(rawDuration) ? Math.max(1, Math.min(12, rawDuration)) : 1;
            if (!adsTitle || !adDisplayUrl || !adDescription) {
                setOrderStatus('Required for SEO text ads: title, display URL, and ad description.', true);
                return;
            }
            if (!adsKeyword || !adsTargetUrl) {
                setOrderStatus('Required for SEO text ads: keyword and destination page selected from your associations.', true);
                return;
            }
            if (adDescription.length > 90) {
                setOrderStatus('Ad description must be maximum 90 characters.', true);
                return;
            }

            payload = Object.assign(payload, {
                service_type: 'seo_ads_text',
                billing_type: 'monthly',
                keyword: adsKeyword,
                target_url: adsTargetUrl,
                title: adsTitle,
                rel_type: 'follow',
                ad_display_url: adDisplayUrl,
                ad_description: adDescription,
                duration_months: durationMonths,
                order_meta_json: JSON.stringify({
                    workflow: 'manual_seo_text_ads_v1',
                    request_mode: 'seo_text_ads',
                    special_remarks: (document.getElementById('lb-ads-remarks').value || '').trim(),
                    selected_target: selectedTarget || null
                })
            });
            if (targetArticleUrl) {
                payload.target_article_url = targetArticleUrl;
            }
        } else {
            const keyword = document.getElementById('lb-modal-keyword').value.trim();
            const target = document.getElementById('lb-modal-target').value.trim();
            const title = document.getElementById('lb-modal-title').value.trim();
            const lead = document.getElementById('lb-modal-lead').value.trim();
            const articleContent = getContentValue();
            const contentBrief = document.getElementById('lb-modal-remarks').value.trim() || lead;
            if (!keyword || !target || !title || !lead || !articleContent) {
                setOrderStatus('Required: keyword, target URL, title, lead and content.', true);
                return;
            }

            payload = Object.assign(payload, {
                service_type: 'seo_article',
                billing_type: document.getElementById('lb-modal-billing-type').value || 'one_time',
                keyword: keyword,
                target_url: target,
                title: title,
                rel_type: document.getElementById('lb-modal-rel-type').value,
                article_topic: title,
                article_brief: lead,
                article_word_count: Math.max(200, Math.min(5000, Math.ceil(articleContent.length / 6))),
                article_language: 'ro',
                article_tone: 'professional',
                article_keywords: JSON.stringify(keyword.split(',').map(function (s) { return s.trim(); }).filter(Boolean).slice(0, 30)),
                article_content_html: articleContent,
                order_meta_json: JSON.stringify({
                    workflow: 'manual_article_order_v1',
                    linking_strategy: document.getElementById('lb-modal-linking-strategy').value,
                    guarantee_36m: !!document.getElementById('lb-modal-guarantee-36m').checked,
                    photo_source: document.getElementById('lb-modal-photo-source').value,
                    lead: lead,
                    content_brief: contentBrief,
                    special_remarks: document.getElementById('lb-modal-remarks').value.trim(),
                    request_mode: 'add_new_article'
                })
            });
        }

        setOrderStatus(
            state.orderMode === 'link_insertion'
                ? 'Placing link placement order...'
                : (state.orderMode === 'seo_text_ads' ? 'Placing SEO text ads order...' : 'Placing sponsored article order...'),
            false
        );
        postAjax('aysa_adverlink_create_order', payload).then(function (resp) {
            if (!resp || !resp.success) {
                const data = resp && resp.data ? resp.data : null;
                const message = data && typeof data === 'object'
                    ? String(data.assistant_message || data.message || 'Order failed.')
                    : (resp && resp.data ? String(resp.data) : 'Order failed.');
                if (data && typeof data === 'object' && data.payment_link) {
                    window.open(String(data.payment_link), '_blank', 'noopener');
                    setOrderStatus(message, false);
                    return;
                }
                setOrderStatus(message, true);
                return;
            }
            let orderStatus = 'Order placed: ' + (resp.data.order_ref || 'N/A');
            if (resp.data && resp.data.publisher_article_draft && resp.data.publisher_article_draft.id) {
                orderStatus += ' | Draft article created: #' + String(resp.data.publisher_article_draft.id);
            } else if (resp.data && resp.data.publisher_article_draft_warning) {
                orderStatus += ' | Draft pending: ' + String(resp.data.publisher_article_draft_warning);
            }
            setOrderStatus(orderStatus, false);
            closeArticleModal();
            loadCredits();
            loadOrders();
            loadLinkIssues(true);
            loadPublisherArticles('draft');
            schedulePublisherArticlesRefresh('draft', 1400);
        }).catch(function (err) {
            setOrderStatus(err && err.message ? err.message : 'Order failed.', true);
        });
    });

    setOrderMode('add_new_article');
    renderLinkTargets();
    renderSeoAdsTargets();
    updateSeoAdsPreview();
    loadMarketplaceDiagnostics();
    loadCredits();
    loadPortals(false);
    loadExchangePortals(false);
    loadExchangeRequests();
    loadOrders();
    loadLinkIssues(false);
    loadBacklinkAuditSnapshot();
    if (!applyInitialTabFromHash()) {
        switchMainTab('link-building');
    }
    window.addEventListener('hashchange', function () {
        applyInitialTabFromHash();
    });
}

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initAysaOffPageOptimization, { once: true });
} else {
    initAysaOffPageOptimization();
}
})();
</script>
