(function($){
  'use strict';

  function getSearchParams(url) {
    try {
      return new URL(url).searchParams;
    } catch (e) {
      return null;
    }
  }

  $(function(){
    $(document).on('submit', '#calliope_sp_publish_form', function(){
      var $form = $(this);
      if ($form.data('calliopeSpSubmitting')) {
        return false;
      }

      $form.data('calliopeSpSubmitting', true);
      var $button = $form.find('button[type="submit"]').first();
      if ($button.length) {
        if (!$button.data('original-label')) {
          $button.data('original-label', String($button.text() || 'Publish now'));
        }
        var publishingLabel = $button.attr('data-publishing-label') || 'Publishing…';
        $button.prop('disabled', true).text(publishingLabel);
      }
      return true;
    });

    var $pinterestEnvironment = $('#calliope_sp_pinterest_env');
    var $pinterestConnect = $('#calliope_sp_pinterest_connect');
    function syncPinterestEnvironmentConnect() {
      if (!$pinterestEnvironment.length || !$pinterestConnect.length) return;
      var selected = String($pinterestEnvironment.val() || '');
      var saved = String($pinterestEnvironment.attr('data-saved-environment') || '');
      var changed = selected !== saved;
      $pinterestConnect.toggleClass('disabled', changed).attr('aria-disabled', changed ? 'true' : 'false');
      if (changed) {
        $pinterestConnect.attr('tabindex', '-1').text($pinterestConnect.attr('data-unsaved-label') || 'Save settings before connecting');
        $('#calliope_sp_pinterest_environment_notice').prop('hidden', false);
      } else {
        $pinterestConnect.removeAttr('tabindex').text(selected === 'sandbox' ? ($pinterestConnect.attr('data-sandbox-label') || 'Connect Pinterest — Sandbox') : ($pinterestConnect.attr('data-production-label') || 'Connect Pinterest — Production'));
        $('#calliope_sp_pinterest_environment_notice').prop('hidden', true);
      }
    }
    $pinterestEnvironment.on('change', syncPinterestEnvironmentConnect);
    $pinterestConnect.on('click', function(event){
      if ($(this).attr('aria-disabled') === 'true') event.preventDefault();
    });
    syncPinterestEnvironmentConnect();

    try {
      var params = new URLSearchParams(window.location.search || '');
      if (params.get('page') !== 'calliope-social-publisher') return;

      var tab = params.get('tab') || 'editor';
      if (tab !== 'connections') return;

      // Store selection when clicking network tabs.
      $(document).on('click', '.calliope-sp-net-tab', function(){
        var sp = getSearchParams(this.href);
        if (!sp) return;
        var net = sp.get('net');
        if (net) {
          try { window.localStorage.setItem('calliope_sp_last_net', net); } catch (e) {}
        }
      });

      var currentNet = params.get('net');
      if (currentNet) {
        try { window.localStorage.setItem('calliope_sp_last_net', currentNet); } catch (e) {}
        return;
      }

      // If we landed without ?net=..., restore the last one (helps after POST redirects).
      var lastNet = null;
      try { lastNet = window.localStorage.getItem('calliope_sp_last_net'); } catch (e) {}

      if (lastNet) {
        params.set('net', lastNet);
        var newUrl = window.location.pathname + '?' + params.toString() + (window.location.hash || '');
        window.location.replace(newUrl);
      }
    } catch (e) {
      // noop
    }
  });
})(jQuery);

(function(){
  'use strict';

  var NETWORK_DESCRIPTIONS = {
    bluesky: 'Publish text, links, and images to a Bluesky account with an app password.',
    mastodon: 'Publish posts, links, images, and videos to the selected Mastodon server.',
    tumblr: 'Publish text, links, and images to the configured Tumblr blog.',
    pinterest: 'Publish images and links to the selected Pinterest board.',
    threads: 'Publish text, links, and images to the connected Threads profile.',
    instagram: 'Publish image posts to the connected Instagram professional account.',
    linkedin: 'Publish text, links, and images to the authenticated LinkedIn profile.',
    blogger: 'Publish articles, links, and images to the selected Blogger blog.',
    telegram: 'Publish posts to a Telegram group, channel, or topic through a bot.',
    facebook: 'Publish text, links, and images to the selected Facebook Page.',
    discord: 'Publish posts, links, images, and videos directly to a Discord text channel.',
    youtube: 'Connect the Google account and YouTube channel used for videos and Shorts.',
    wordpress_remote: 'Connect external WordPress sites through application passwords.',
    custom_webhook: 'Connect custom webhook endpoints for external automation.'
  };
  var CONNECTION_TUTORIAL_URL = 'https://pluginswordpress.calliope.com.ar/calliope-social-publisher/';
  var CONNECTION_TUTORIAL_LABEL = ((window.CALLIOPE_SP_JOB_RUNNER || {}).i18n || {}).connectionTutorialLabel || 'Step-by-step connection and video tutorial';

  function getParams() {
    try {
      return new URLSearchParams(window.location.search || '');
    } catch (e) {
      return null;
    }
  }

  function isConnectionsPage() {
    var params = getParams();
    if (!params || params.get('page') !== 'calliope-social-publisher') {
      return false;
    }
    return (params.get('tab') || 'dashboard') === 'connections';
  }

  function getActiveTab() {
    return document.querySelector('.calliope-sp-net-tab.is-active');
  }

  function getNetworkSlug(tab) {
    if (!tab || !tab.classList) {
      return '';
    }
    for (var i = 0; i < tab.classList.length; i++) {
      var className = tab.classList.item(i);
      if (className && className.indexOf('net-') === 0) {
        return className.slice(4);
      }
    }
    return '';
  }

  function cleanTitleFromTab(tab) {
    if (!tab) {
      return '';
    }
    var clone = tab.cloneNode(true);
    Array.prototype.forEach.call(clone.querySelectorAll('.screen-reader-text,.calliope-sp-net-icon,.calliope-sp-network-icon,svg'), function(node){
      node.parentNode.removeChild(node);
    });
    return clone.textContent.replace(/\s+/g, ' ').trim();
  }

  function firstHeadingText(panel) {
    var heading = panel ? panel.querySelector('h2,h3') : null;
    return heading ? heading.textContent.replace(/\s+/g, ' ').trim() : '';
  }

  function getPanelTitle(panel, tab) {
    return cleanTitleFromTab(tab) || firstHeadingText(panel) || 'Connection';
  }

  function getDescription(slug, panel) {
    if (slug && NETWORK_DESCRIPTIONS[slug]) {
      return NETWORK_DESCRIPTIONS[slug];
    }
    var description = panel ? panel.querySelector('.description,.calliope-sp-hint') : null;
    return description ? description.textContent.replace(/\s+/g, ' ').trim() : '';
  }

  function cloneNetworkIcon(tab) {
    var source = tab ? tab.querySelector('.calliope-sp-network-icon,.calliope-sp-net-icon,svg') : null;
    var holder = document.createElement('span');
    holder.className = 'calliope-sp-connection-logo';
    holder.setAttribute('aria-hidden', 'true');
    if (source) {
      var clone = source.cloneNode(true);
      clone.classList.add('calliope-sp-connection-logo__icon');
      holder.appendChild(clone);
    }
    return holder;
  }

  function copyNetworkColor(tab, target) {
    if (!tab || !target || !window.getComputedStyle) {
      return;
    }
    var styles = window.getComputedStyle(tab);
    var color = styles.getPropertyValue('--calliope-sp-net-color') || styles.getPropertyValue('--calliope-network-color') || styles.color;
    if (color) {
      target.style.setProperty('--calliope-sp-net-color', color.trim());
      target.style.setProperty('--calliope-network-color', color.trim());
    }
  }

  function buildHeader(title, description, tab) {
    var header = document.createElement('header');
    header.className = 'calliope-sp-connection-heading';
    header.appendChild(cloneNetworkIcon(tab));

    var copy = document.createElement('div');
    var h2 = document.createElement('h2');
    h2.textContent = title;
    copy.appendChild(h2);
    if (description) {
      var p = document.createElement('p');
      p.textContent = description;
      copy.appendChild(p);
    }
    header.appendChild(copy);
    return header;
  }

  function isTutorialBlock(node) {
    if (!node || !node.textContent) {
      return false;
    }
    if (node.classList && (node.classList.contains('calliope-spp-setup-guide') || node.classList.contains('calliope-sp-howto'))) {
      return true;
    }
    if (node.matches && node.matches('ul.ul-disc')) {
      return true;
    }
    var text = node.textContent.replace(/\s+/g, ' ').trim();
    return /Quick guide|How to connect|Connection tutorial/i.test(text);
  }

  function moveTutorials(source, aside) {
    var selectors = '.calliope-sp-howto,.calliope-sp-hint,.calliope-spp-setup-guide,ul.ul-disc';
    var moved = 0;
    Array.prototype.forEach.call(source.querySelectorAll(selectors), function(node){
      if (!node.closest || node.closest('.calliope-sp-connection-guide')) {
        return;
      }
      if (!isTutorialBlock(node)) {
        return;
      }
      node.classList.add('calliope-sp-connection-guide-block');
      aside.appendChild(node);
      moved++;
    });
    return moved;
  }

  function addDefaultGuide(aside, title) {
    var h3 = document.createElement('h3');
    h3.textContent = 'How to connect ' + title;
    aside.appendChild(h3);

    var steps = [
      ['Save the required credentials.', 'Copy the values from the provider developer panel and save them here.'],
      ['Start the authorization flow.', 'Use the connect button in the connection panel and approve the requested permissions.'],
      ['Return and test the connection.', 'When the provider sends you back to WordPress, run the test before publishing.']
    ];
    var ol = document.createElement('ol');
    ol.className = 'calliope-sp-connection-steps';
    steps.forEach(function(step){
      var li = document.createElement('li');
      var strong = document.createElement('strong');
      var span = document.createElement('span');
      strong.textContent = step[0];
      span.textContent = step[1];
      li.appendChild(strong);
      li.appendChild(span);
      ol.appendChild(li);
    });
    aside.appendChild(ol);
  }

  function finishGuide(aside, title) {
    if (!aside.children.length) {
      addDefaultGuide(aside, title);
      normalizeNumberedTutorials(aside);
      appendConnectionTutorialLink(aside);
      return;
    }
    if (!aside.querySelector('h3,b')) {
      var h3 = document.createElement('h3');
      h3.textContent = 'How to connect ' + title;
      aside.insertBefore(h3, aside.firstChild);
    }
    normalizeNumberedTutorials(aside);
    appendConnectionTutorialLink(aside);
  }

  function nodeText(nodes) {
    var text = '';
    Array.prototype.forEach.call(nodes, function(node){
      text += node.textContent || '';
    });
    return text.replace(/\s+/g, ' ').trim();
  }

  function startsWithStepNumber(nodes) {
    return /^\d+\)\s+/.test(nodeText(nodes));
  }

  function stripLeadingStepNumber(nodes) {
    var stripped = false;
    function walk(node) {
      if (stripped || !node) {
        return;
      }
      if (node.nodeType === 3) {
        var next = node.nodeValue.replace(/^\s*\d+\)\s*/, '');
        if (next !== node.nodeValue) {
          node.nodeValue = next;
          stripped = true;
        }
        return;
      }
      Array.prototype.some.call(node.childNodes || [], function(child){
        walk(child);
        return stripped;
      });
    }
    Array.prototype.some.call(nodes, function(node){
      walk(node);
      return stripped;
    });
  }

  function splitByDirectBreaks(container) {
    var segments = [];
    var current = [];
    Array.prototype.forEach.call(container.childNodes, function(node){
      if (node.nodeType === 1 && String(node.tagName || '').toUpperCase() === 'BR') {
        segments.push(current);
        current = [];
        return;
      }
      current.push(node);
    });
    segments.push(current);
    return segments;
  }

  function transformNumberedTextBlock(container) {
    if (!container || container.dataset.calliopeNumberedSteps === '1' || container.querySelector('ol')) {
      return;
    }

    var segments = splitByDirectBreaks(container);
    var numberedCount = 0;
    segments.forEach(function(segment){
      if (startsWithStepNumber(segment)) {
        numberedCount++;
      }
    });
    if (numberedCount < 2) {
      return;
    }

    var fragment = document.createDocumentFragment();
    var ol = null;
    var currentLi = null;

    segments.forEach(function(segment){
      if (!nodeText(segment)) {
        return;
      }
      if (startsWithStepNumber(segment)) {
        if (!ol) {
          ol = document.createElement('ol');
          ol.className = 'calliope-sp-connection-steps';
          fragment.appendChild(ol);
        }
        stripLeadingStepNumber(segment);
        currentLi = document.createElement('li');
        segment.forEach(function(node){ currentLi.appendChild(node); });
        ol.appendChild(currentLi);
        return;
      }
      if (currentLi) {
        var span = document.createElement('span');
        segment.forEach(function(node){ span.appendChild(node); });
        currentLi.appendChild(span);
        return;
      }
      segment.forEach(function(node){ fragment.appendChild(node); });
    });

    container.textContent = '';
    container.appendChild(fragment);
    container.dataset.calliopeNumberedSteps = '1';
  }

  function normalizeNumberedTutorials(guide) {
    if (!guide) {
      return;
    }
    Array.prototype.forEach.call(guide.querySelectorAll('ul.ul-disc'), function(ul){
      var ol = document.createElement('ol');
      ol.className = 'calliope-sp-connection-steps';
      Array.prototype.forEach.call(ul.attributes || [], function(attr){
        if (attr.name !== 'class') {
          ol.setAttribute(attr.name, attr.value);
        }
      });
      while (ul.firstChild) {
        ol.appendChild(ul.firstChild);
      }
      ul.parentNode.replaceChild(ol, ul);
    });

    var candidates = [guide].concat(Array.prototype.slice.call(guide.querySelectorAll('.calliope-sp-connection-guide-block, .calliope-sp-connection-guide-block > div, .calliope-sp-connection-guide-block .calliope-sp-muted, .calliope-sp-connection-guide-block .calliope-sp-hint')));
    candidates.forEach(transformNumberedTextBlock);
  }

  function appendConnectionTutorialLink(guide) {
    if (!guide || guide.querySelector('[data-calliope-connection-tutorial-link="1"]')) {
      return;
    }

    var p = document.createElement('p');
    p.className = 'calliope-sp-connection-resource-link';
    p.setAttribute('data-calliope-connection-tutorial-link', '1');

    var a = document.createElement('a');
    a.href = CONNECTION_TUTORIAL_URL;
    a.target = '_blank';
    a.rel = 'noopener noreferrer';
    a.textContent = CONNECTION_TUTORIAL_LABEL;

    p.appendChild(a);
    guide.appendChild(p);
  }

  function normalizeMainHeading(card, title) {
    var heading = card ? card.querySelector('h2,h3') : null;
    if (!heading) {
      return;
    }
    var current = heading.textContent.replace(/\s+/g, ' ').trim().toLowerCase();
    if (current === String(title || '').toLowerCase()) {
      heading.textContent = 'Connection';
    }
  }

  function promoteStatusBadge(card) {
    if (!card || card.dataset.calliopeStatusPromoted === '1') {
      return;
    }
    var heading = card.firstElementChild && /^H[23]$/i.test(card.firstElementChild.tagName || '') ? card.firstElementChild : card.querySelector('h2,h3');
    var badge = card.querySelector('.calliope-sp-badge');
    if (!heading || !badge || heading.contains(badge)) {
      return;
    }

    var oldParent = badge.parentElement;
    var row = document.createElement('div');
    row.className = 'calliope-spp-card-heading calliope-sp-connection-card-heading';
    heading.parentNode.insertBefore(row, heading);
    row.appendChild(heading);
    row.appendChild(badge);

    if (oldParent && oldParent !== card && !oldParent.querySelector('a,button,input,select,textarea')) {
      var leftover = oldParent.textContent.replace(/Status\s*:|\s+/gi, '');
      if (leftover === '') {
        oldParent.parentNode.removeChild(oldParent);
      }
    }

    card.dataset.calliopeStatusPromoted = '1';
  }

  function buildGrid(title) {
    var grid = document.createElement('div');
    grid.className = 'calliope-sp-connection-grid';

    var main = document.createElement('section');
    main.className = 'calliope-sp-connection-main';
    main.setAttribute('aria-label', 'Connection');

    var aside = document.createElement('aside');
    aside.className = 'calliope-sp-connection-guide calliope-spp-network-card calliope-spp-setup-guide';
    aside.setAttribute('aria-label', 'How to connect ' + title);

    grid.appendChild(main);
    grid.appendChild(aside);
    return { grid: grid, main: main, aside: aside };
  }

  function prependConnectionTitle(container) {
    if (!container || container.querySelector('.calliope-sp-connection-main-title')) {
      return;
    }
    var h3 = document.createElement('h3');
    h3.className = 'calliope-sp-connection-main-title';
    h3.textContent = 'Connection';
    container.insertBefore(h3, container.firstChild);
  }

  function enhanceFreeCard(card, tab) {
    if (!card || card.dataset.calliopeConnectionLayout === '1' || card.classList.contains('calliope-sp-connection-shell') || card.classList.contains('calliope-spp-network-panel') || card.querySelector('.calliope-spp-network-panel')) {
      return;
    }

    var slug = getNetworkSlug(tab);
    var title = getPanelTitle(card, tab);
    var shell = document.createElement('section');
    shell.className = 'calliope-sp-connection-shell net-' + slug + (tab && tab.classList.contains('is-connected') ? ' is-connected' : ' is-disconnected');
    shell.dataset.calliopeConnectionLayout = '1';
    copyNetworkColor(tab, shell);

    var header = buildHeader(title, getDescription(slug, card), tab);
    var parts = buildGrid(title);

    card.parentNode.insertBefore(shell, card);
    shell.appendChild(header);
    shell.appendChild(parts.grid);
    parts.main.appendChild(card);
    card.dataset.calliopeConnectionLayout = '1';
    card.classList.add('calliope-sp-connection-main-card');
    normalizeMainHeading(card, title);
    promoteStatusBadge(card);

    moveTutorials(card, parts.aside);
    finishGuide(parts.aside, title);
  }

  function firstElementAfterDivider() {
    var divider = document.querySelector('.calliope-sp-panel > .calliope-sp-divider');
    var node = divider ? divider.nextElementSibling : null;
    while (node && node.classList && node.classList.contains('notice')) {
      node = node.nextElementSibling;
    }
    return node;
  }

  function enhanceLegacyProPanel(panel, tab) {
    if (!panel || panel.dataset.calliopeConnectionLayout === '1' || panel.querySelector('.calliope-spp-network-panel')) {
      return;
    }

    var slug = getNetworkSlug(tab) || String(panel.getAttribute('data-calliope-spp-section') || '');
    var title = getPanelTitle(panel, tab);
    panel.dataset.calliopeConnectionLayout = '1';
    panel.classList.add('calliope-sp-connection-shell', 'calliope-sp-connection-shell--pro', 'net-' + slug);
    panel.classList.add(tab && tab.classList.contains('is-connected') ? 'is-connected' : 'is-disconnected');
    copyNetworkColor(tab, panel);

    var directHero = null;
    Array.prototype.some.call(panel.children, function(child){
      if (child.classList && child.classList.contains('calliope-spp-connection-hero')) {
        directHero = child;
        return true;
      }
      return false;
    });

    var header = directHero;
    if (header) {
      header.classList.add('calliope-sp-connection-heading');
      if (!header.querySelector('.calliope-sp-connection-logo')) {
        header.insertBefore(cloneNetworkIcon(tab), header.firstChild);
      }
    } else {
      var directHeading = null;
      Array.prototype.some.call(panel.children, function(child){
        if (/^H[23]$/i.test(child.tagName || '')) {
          directHeading = child;
          return true;
        }
        return false;
      });
      header = buildHeader(title, getDescription(slug, panel), tab);
      panel.insertBefore(header, panel.firstChild);
      if (directHeading && directHeading.parentNode) {
        directHeading.parentNode.removeChild(directHeading);
      }
    }

    var parts = buildGrid(title);
    parts.main.classList.add('calliope-spp-network-card');
    prependConnectionTitle(parts.main);
    var children = Array.prototype.slice.call(panel.children);
    children.forEach(function(child){
      if (child === header || child === parts.grid || (child.classList && child.classList.contains('notice'))) {
        return;
      }
      if (/^HR$/i.test(child.tagName || '')) {
        child.parentNode.removeChild(child);
        return;
      }
      if (isTutorialBlock(child)) {
        child.classList.add('calliope-sp-connection-guide-block');
        parts.aside.appendChild(child);
        return;
      }
      parts.main.appendChild(child);
    });

    finishGuide(parts.aside, title);
    panel.appendChild(parts.grid);
  }

  document.addEventListener('DOMContentLoaded', function(){
    if (!isConnectionsPage()) {
      return;
    }
    var activeTab = getActiveTab();
    var panel = firstElementAfterDivider();
    if (!panel) {
      return;
    }
    if (panel.classList.contains('calliope-spp-network-panel')) {
      appendConnectionTutorialLink(panel.querySelector('.calliope-spp-setup-guide'));
      return;
    }
    if (panel.classList.contains('calliope-spp-integrated-admin')) {
      enhanceLegacyProPanel(panel, activeTab);
    } else {
      enhanceFreeCard(panel, activeTab);
    }
  });
})();

(function($){
  'use strict';

  var DRAFT_VERSION = 1;
  var DRAFT_PREFIX = 'calliope_sp_manual_draft_v1_';
  var saveTimer = null;
  var restoringDraft = false;
  var draftClearedAfterPublish = false;

  function getSearchParamsSafe() {
    try {
      return new URLSearchParams(window.location.search || '');
    } catch (e) {
      return null;
    }
  }

  function isPublisherAdminPage() {
    var params = getSearchParamsSafe();
    return !!params && params.get('page') === 'calliope-social-publisher';
  }

  function isDashboardComposer() {
    var params = getSearchParamsSafe();
    var tab = params ? (params.get('tab') || 'dashboard') : '';
    return isPublisherAdminPage() && tab === 'publisher' && $('#calliope_sp_publish_form').length > 0;
  }

  function getStorage() {
    try {
      if (window.sessionStorage) {
        return window.sessionStorage;
      }
    } catch (e) {}
    return null;
  }

  function getDraftKey() {
    var origin = '';
    try {
      origin = window.location.origin || (window.location.protocol + '//' + window.location.host);
    } catch (e) {
      origin = '';
    }

    var scope = [
      origin,
      window.location ? window.location.pathname : '',
      'calliope-social-publisher',
      'dashboard'
    ].join('|');

    return DRAFT_PREFIX + scope.replace(/[^a-z0-9_.:-]+/gi, '_').replace(/^_+|_+$/g, '').slice(0, 160);
  }

  function removeDraft() {
    var storage = getStorage();
    if (!storage) {
      return;
    }
    try {
      storage.removeItem(getDraftKey());
    } catch (e) {}
  }

  function clearDraftAfterSuccessfulPublish() {
    draftClearedAfterPublish = true;
    removeDraft();
  }

  function shouldClearDraftFromUrl() {
    var params = getSearchParamsSafe();
    if (!params || !isPublisherAdminPage()) {
      return false;
    }
    return params.get('calliope_sp_clear_draft') === '1'
      || params.get('calliope_sp_clear_image') === '1'
      || params.get('calliope_sp_published') === '1';
  }

  function clearComposerFieldsAfterPublish() {
    restoringDraft = true;
    try {
      [
        '#calliope_sp_title',
        '#calliope_sp_content',
        '#calliope_sp_hashtags',
        '#calliope_sp_link',
        '#calliope_sp_ai_prompt',
        '#calliope_sp_link_context',
        '#calliope_sp_alt_text',
        '#calliope_sp_data'
      ].forEach(function(selector){
        var $field = $(selector);
        if ($field.length) {
          $field.val('').trigger('input').trigger('change');
        }
      });

      $('#calliope_sp_source_post_id').val('');
      $('#calliope_sp_ai_used').val('0');

      var $format = $('#calliope_sp_image_format');
      if ($format.length) {
        $format.val('original').trigger('change');
      }
      $('#final-img, #img-crop').attr('src', '').removeAttr('srcset');
      $('#preview, #edit-area').hide();
      $('#btn-up, #btn-local').show();
      $('#file-input').val('');
    } finally {
      restoringDraft = false;
    }
  }

  function isString(value) {
    return typeof value === 'string';
  }

  function isPlainObject(value) {
    return value && typeof value === 'object' && !Array.isArray(value);
  }

  function getFieldValue(selector) {
    var $field = $(selector);
    return $field.length ? String($field.val() || '') : '';
  }

  function getImagePreviewSrc() {
    var $img = $('#final-img');
    return $img.length ? String($img.attr('src') || '') : '';
  }

  function getPublicationType() {
    var value = $('#calliope_sp_publish_form input[name="calliope_sp_publication_type"]:checked').val();
    return value === 'video' ? 'video' : 'standard';
  }

  function getSelectedNetworks() {
    var networks = [];
    $('#calliope_sp_publish_form input[type="checkbox"][name^="post_to_"]').each(function(){
      if (this.checked && !this.disabled && this.name) {
        networks.push(String(this.name));
      }
    });
    return networks;
  }

  function getSelectedAccountGroups() {
    var groups = [];
    $('#calliope_sp_publish_form input[type="checkbox"][name="calliope_spp_account_groups[]"]').each(function(){
      if (this.checked && !this.disabled) groups.push(String(this.value || ''));
    });
    return groups;
  }

  function getTemplateSelections() {
    var selections = {};
    $('#calliope_sp_publish_form select[name^="calliope_spp_template_selection["]').each(function(){
      var match = String(this.name || '').match(/^calliope_spp_template_selection\[([a-z0-9_]+)\]$/i);
      if (match) selections[match[1]] = String($(this).val() || '');
    });
    return selections;
  }

  function collectDraft() {
    return {
      version: DRAFT_VERSION,
      form: 'admin-dashboard',
      updatedAt: Date.now(),
      fields: {
        publicationType: getPublicationType(),
        title: getFieldValue('#calliope_sp_title'),
        content: getFieldValue('#calliope_sp_content'),
        hashtags: getFieldValue('#calliope_sp_hashtags'),
        link: getFieldValue('#calliope_sp_link'),
        prompt: getFieldValue('#calliope_sp_ai_prompt'),
        linkContext: getFieldValue('#calliope_sp_link_context'),
        sourcePostId: getFieldValue('#calliope_sp_source_post_id'),
        aiUsed: getFieldValue('#calliope_sp_ai_used'),
        altText: getFieldValue('#calliope_sp_alt_text'),
        imageData: getFieldValue('#calliope_sp_data'),
        imagePreviewSrc: getImagePreviewSrc(),
        imageFormat: getFieldValue('#calliope_sp_image_format')
      },
      selectedNetworks: getSelectedNetworks(),
      selectedAccountGroups: getSelectedAccountGroups(),
      templateSelections: getTemplateSelections()
    };
  }

  function hasDraftContent(draft) {
    if (!draft || !isPlainObject(draft.fields)) {
      return false;
    }

    var fields = draft.fields;
    return [
      fields.title,
      fields.content,
      fields.hashtags,
      fields.link,
      fields.prompt,
      fields.linkContext,
      fields.altText,
      fields.imageData,
      fields.imagePreviewSrc
    ].some(function(value){
      return isString(value) && value.trim() !== '';
    });
  }

  function saveDraftNow() {
    if (!isDashboardComposer() || restoringDraft || draftClearedAfterPublish) {
      return;
    }

    var storage = getStorage();
    if (!storage) {
      return;
    }

    var draft = collectDraft();
    try {
      if (hasDraftContent(draft)) {
        storage.setItem(getDraftKey(), JSON.stringify(draft));
      } else {
        storage.removeItem(getDraftKey());
      }
    } catch (e) {}
  }

  function scheduleDraftSave() {
    if (saveTimer) {
      window.clearTimeout(saveTimer);
    }
    saveTimer = window.setTimeout(saveDraftNow, 250);
  }

  function readDraft() {
    var storage = getStorage();
    if (!storage) {
      return null;
    }

    var raw = '';
    try {
      raw = storage.getItem(getDraftKey()) || '';
    } catch (e) {
      return null;
    }

    if (!raw) {
      return null;
    }

    var draft;
    try {
      draft = JSON.parse(raw);
    } catch (e) {
      removeDraft();
      return null;
    }

    if (!isPlainObject(draft) || draft.version !== DRAFT_VERSION || draft.form !== 'admin-dashboard' || !isPlainObject(draft.fields)) {
      removeDraft();
      return null;
    }

    if (!Array.isArray(draft.selectedNetworks)) {
      draft.selectedNetworks = [];
    }
    if (!Array.isArray(draft.selectedAccountGroups)) {
      draft.selectedAccountGroups = [];
    }

    return draft;
  }

  function setFieldIfEmpty(selector, value) {
    if (!isString(value) || value === '') {
      return;
    }
    var $field = $(selector);
    if (!$field.length || String($field.val() || '') !== '') {
      return;
    }
    $field.val(value).trigger('input').trigger('change');
  }

  function restoreImage(fields) {
    if (!isString(fields.imageData) || fields.imageData === '' || !/^data:image\//i.test(fields.imageData)) {
      return;
    }

    var $data = $('#calliope_sp_data');
    if (!$data.length || String($data.val() || '') !== '') {
      return;
    }

    var previewSrc = isString(fields.imagePreviewSrc) && /^data:image\//i.test(fields.imagePreviewSrc)
      ? fields.imagePreviewSrc
      : fields.imageData;

    $data.val(fields.imageData).trigger('change');
    $('#final-img').attr('src', previewSrc);
    $('#preview').show();
    $('#edit-area').hide();
    $('#btn-up, #btn-local').show();
  }

  function restoreImageFormat(value) {
    if (!isString(value) || value === '') {
      return;
    }
    var $format = $('#calliope_sp_image_format');
    if (!$format.length) {
      return;
    }

    var hasOption = false;
    $format.find('option').each(function(){
      if (String(this.value || '') === value) {
        hasOption = true;
      }
    });

    if (!hasOption) {
      return;
    }

    $format.val(value).trigger('change');
  }

  function restorePublicationType(value) {
    if (!isString(value) || !/^(standard|video)$/i.test(value)) {
      return false;
    }

    var $choice = $('#calliope_sp_publish_form input[name="calliope_sp_publication_type"][value="' + value + '"]');
    if (!$choice.length || $choice.is(':disabled')) {
      return false;
    }

    if (!$choice.is(':checked')) {
      $choice.prop('checked', true).trigger('change');
    }
    return true;
  }

  function restoreNetworks(networks, publicationType) {
    if (!Array.isArray(networks)) {
      return;
    }
    if (!isString(publicationType) || publicationType !== getPublicationType()) {
      return;
    }

    var selected = {};
    networks.forEach(function(name){
      if (isString(name) && /^post_to_[a-z0-9_]+$/i.test(name)) {
        selected[name] = true;
      }
    });

    $('#calliope_sp_publish_form input[type="checkbox"][name^="post_to_"]').each(function(){
      this.checked = !this.disabled && !!selected[this.name];
    }).trigger('change');
  }

  function restoreAccountGroups(groups) {
    if (!Array.isArray(groups)) return;
    var selected = {};
    groups.forEach(function(uuid){
      if (isString(uuid) && /^[a-f0-9-]{36}$/i.test(uuid)) selected[uuid.toLowerCase()] = true;
    });
    $('#calliope_sp_publish_form input[type="checkbox"][name="calliope_spp_account_groups[]"]').each(function(){
      var uuid = String(this.value || '').toLowerCase();
      this.checked = !this.disabled && !!selected[uuid];
    }).trigger('change');
  }

  function restoreTemplateSelections(selections) {
    if (!isPlainObject(selections)) return;
    Object.keys(selections).forEach(function(network){
      if (!/^[a-z0-9_]+$/i.test(network) || !isString(selections[network])) return;
      var $select = $('#calliope_sp_publish_form select[name="calliope_spp_template_selection[' + network + ']"]');
      if (!$select.length || !$select.find('option[value="' + selections[network].replace(/"/g, '\\"') + '"]').length) return;
      $select.val(selections[network]).trigger('change');
    });
  }

  function restoreDraft() {
    if (!isDashboardComposer()) {
      return;
    }

    var draft = readDraft();
    if (!draft || !hasDraftContent(draft)) {
      return;
    }

    restoringDraft = true;
    try {
      var fields = draft.fields;
      var restoredPublicationType = restorePublicationType(fields.publicationType);
      setFieldIfEmpty('#calliope_sp_title', fields.title);
      setFieldIfEmpty('#calliope_sp_content', fields.content);
      setFieldIfEmpty('#calliope_sp_hashtags', fields.hashtags);
      setFieldIfEmpty('#calliope_sp_link', fields.link);
      setFieldIfEmpty('#calliope_sp_ai_prompt', fields.prompt);
      setFieldIfEmpty('#calliope_sp_link_context', fields.linkContext);
      setFieldIfEmpty('#calliope_sp_source_post_id', fields.sourcePostId);
      if (String(fields.aiUsed || '') === '1') $('#calliope_sp_ai_used').val('1');
      setFieldIfEmpty('#calliope_sp_alt_text', fields.altText);
      restoreImageFormat(fields.imageFormat);
      restoreImage(fields);
      restoreNetworks(draft.selectedNetworks, restoredPublicationType ? fields.publicationType : '');
      restoreAccountGroups(draft.selectedAccountGroups);
      restoreTemplateSelections(draft.templateSelections);
    } finally {
      restoringDraft = false;
    }
  }

  try {
    window.CALLIOPE_SP_MANUAL_DRAFT = {
      save: saveDraftNow,
      remove: removeDraft,
      clearAfterSuccessfulPublish: clearDraftAfterSuccessfulPublish
    };
  } catch (e) {}

  $(function(){
    if (shouldClearDraftFromUrl()) {
      clearDraftAfterSuccessfulPublish();
      clearComposerFieldsAfterPublish();
    } else {
      restoreDraft();
    }

    $(document).on('input change', [
      '#calliope_sp_title',
      '#calliope_sp_content',
      '#calliope_sp_hashtags',
      '#calliope_sp_link',
      '#calliope_sp_ai_prompt',
      '#calliope_sp_link_context',
      '#calliope_sp_source_post_id',
      '#calliope_sp_ai_used',
      '#calliope_sp_alt_text',
      '#calliope_sp_data',
      '#calliope_sp_image_format',
      '#calliope_sp_publish_form select[name^="calliope_spp_template_selection"]',
      '#calliope_sp_publish_form input[name="calliope_sp_publication_type"]',
      '#calliope_sp_publish_form input[type="checkbox"][name^="post_to_"]'
    ].join(','), scheduleDraftSave);

    $(document).on('click', 'a[href*="page=calliope-social-publisher"]', saveDraftNow);
    $(document).on('submit', '#calliope_sp_publish_form', saveDraftNow);
    $(window).on('beforeunload', saveDraftNow);
  });
})(jQuery);

(function($){
  'use strict';

  $(function(){
    var cfg = window.CALLIOPE_SP_JOB_RUNNER || {};
    var jobs = Array.isArray(cfg.jobs) ? cfg.jobs : [];
    if (!jobs.length || !cfg.ajaxUrl || !cfg.nonce) return;

    var i18n = cfg.i18n || {};
    var labels = cfg.networkLabels || {};
    var jobStates = {};
    var workerActive = true;
    var finalPinterestOutcome = '';
    var finalPinterestWarning = '';
    var finalNeedsReview = false;

    function initialOutcomeFromResult(result) {
      result = result || {};
      var classification = String(result.classification || '').toLowerCase();
      var code = String(result.error_code || '').toLowerCase();
      var uiStatus = String(result.ui_status || result.status || '').toLowerCase();
      if (result.skipped || code === 'duplicate_skipped' || classification.indexOf('duplicate_skipped') !== -1) return 'skipped';
      if (uiStatus === 'warning') return 'warning';
      return result.ok === false ? 'failed' : 'published';
    }

    var destinationLabels = {};
    jobs.forEach(function(job){
      if (job && job.destination_labels && typeof job.destination_labels === 'object' && !Array.isArray(job.destination_labels)) {
        Object.keys(job.destination_labels).forEach(function(key){ destinationLabels[key] = String(job.destination_labels[key] || ''); });
      }
      if (!job || !job.job_id) return;
      var completedResults = job.completed_results && typeof job.completed_results === 'object' && !Array.isArray(job.completed_results)
        ? job.completed_results
        : {};
      var outcomes = {};
      var failedNetworks = [];
      Object.keys(completedResults).forEach(function(network){
        var result = completedResults[network] || {};
        if (!result.network) result.network = network;
        var outcome = initialOutcomeFromResult(result);
        outcomes[network] = outcome;
        if (outcome === 'failed' || outcome === 'skipped') failedNetworks.push(network);
      });
      jobStates[job.job_id] = {
        destinations: Array.isArray(job.destinations) ? job.destinations.slice() : [],
        completed: Array.isArray(job.completed) ? job.completed.slice() : [],
        failedNetworks: unique(failedNetworks),
        outcomes: outcomes,
        current: '',
        pendingProgress: {},
        done: false,
        failed: failedNetworks.length > 0
      };
    });

    function networkLabel(network) {
      network = String(network || '');
      return destinationLabels[network] || labels[network] || network.charAt(0).toUpperCase() + network.slice(1);
    }
    function format(template) {
      var args = Array.prototype.slice.call(arguments, 1);
      template = String(template || '');
      args.forEach(function(arg, index){
        template = template.replace(new RegExp('%' + (index + 1) + '\\$[sd]', 'g'), String(arg));
        template = template.replace(/%[sd]/, String(arg));
      });
      return template;
    }
    function unique(values) {
      var seen = {};
      return (values || []).filter(function(value){
        value = String(value || '');
        if (!value || seen[value]) return false;
        seen[value] = true;
        return true;
      });
    }
    function totals() {
      var total = 0, completed = 0, progressUnits = 0;
      Object.keys(jobStates).forEach(function(id){
        var state = jobStates[id];
        total += state.destinations.length;
        completed += state.completed.length;
        progressUnits += state.completed.length;
        state.destinations.forEach(function(network){
          if (state.completed.indexOf(network) !== -1) return;
          var pending = Number((state.pendingProgress || {})[network] || 0);
          if (isFinite(pending) && pending > 0) progressUnits += Math.min(99, Math.max(0, pending)) / 100;
        });
      });
      return { total: total, completed: completed, percent: total ? Math.min(100, Math.round((progressUnits / total) * 100)) : 100 };
    }
    function nextNetwork(job) {
      var state = jobStates[job.job_id];
      if (!state) return '';
      for (var i = 0; i < state.destinations.length; i++) {
        if (state.completed.indexOf(state.destinations[i]) === -1) return state.destinations[i];
      }
      return '';
    }
    function pinterestOutcome(result) {
      result = result || {};
      var failure = String(result.failure_kind || (result.data && result.data.failure_kind) || '').toLowerCase();
      var code = String(result.error_code || result.code || '').toLowerCase();
      var classification = String(result.classification || '').toLowerCase();
      if (classification.indexOf('link_omitted') !== -1 || String(result.warning_code || '').toLowerCase() === 'pinterest_link_omitted' || result.link_omitted) {
        finalPinterestWarning = String(result.user_message || result.message || i18n.pinterestLinkOmitted || 'Pinterest published without the destination link because Pinterest blocked that URL.');
        return 'warning';
      }
      if (result.ok !== false && (result.warning || String(result.ui_status || result.status || '').toLowerCase() === 'warning' || String(result.warning_code || '') !== '')) {
        finalPinterestWarning = String(result.user_message || result.message || 'Pinterest published with some selected images omitted.');
        return 'warning';
      }
      if (failure === 'access_tier' || code === 'pinterest_publish_access_denied' || classification.indexOf('access_denied') !== -1) return 'access_tier';
      if (failure === 'permission' || code === 'pinterest_scope_missing' || classification.indexOf('permission') !== -1 || classification.indexOf('scope_missing') !== -1) return 'permission';
      if (failure === 'environment' || code === 'pinterest_environment_mismatch' || classification.indexOf('environment_mismatch') !== -1) return 'auth';
      if (failure === 'auth' || code === 'pinterest_auth_invalid' || code === 'pinterest_token_invalid' || classification.indexOf('auth_invalid') !== -1) return 'auth';
      return result.ok === false ? 'failed' : 'published';
    }
    function markCompleted(job, network, ok, outcome) {
      var state = jobStates[job.job_id];
      if (!state || !network) return;
      var finalOutcome = outcome || (ok ? 'published' : 'failed');
      state.completed = unique(state.completed.concat([network]));
      state.current = '';
      if (state.pendingProgress) delete state.pendingProgress[network];
      state.outcomes[network] = finalOutcome;
      if (finalOutcome === 'failed' || finalOutcome === 'skipped' || (!ok && finalOutcome !== 'warning')) {
        state.failedNetworks = unique(state.failedNetworks.concat([network]));
      } else {
        // The server result/report is authoritative. A confirmed success must clear any
        // stale client-side failure left by an earlier transient state or retry.
        state.failedNetworks = state.failedNetworks.filter(function(item){ return item !== network; });
      }
      state.failed = state.failedNetworks.length > 0;
    }
    function hasFailures() {
      return Object.keys(jobStates).some(function(id){ return !!jobStates[id].failed; });
    }
    function successCount() {
      var count = 0;
      Object.keys(jobStates).forEach(function(id){
        var state = jobStates[id];
        state.completed.forEach(function(network){
          var outcome = state.outcomes[network] || 'published';
          if (outcome === 'published' || outcome === 'warning') count += 1;
        });
      });
      return count;
    }
    function markRemainingFailed(state) {
      if (!state) return;
      state.destinations.forEach(function(network){
        if (state.completed.indexOf(network) === -1) {
          state.completed = unique(state.completed.concat([network]));
          state.failedNetworks = unique(state.failedNetworks.concat([network]));
          state.outcomes[network] = 'failed';
        }
      });
    }
    function enablePublishButton() {
      var $form = $('#calliope_sp_publish_form');
      $form.removeData('calliopeSpSubmitting');
      $form.find('button[type="submit"]').prop('disabled', false).removeClass('is-busy').each(function(){
        var $button = $(this);
        var original = $button.data('original-label');
        if (original) $button.text(original);
      });
    }
    function disablePinterest() {
      $('input[name="post_to_pinterest"]').prop('checked', false).prop('disabled', true).attr('aria-disabled', 'true');
    }
    function removeQueuedServerNotice() {
      $('.wrap .notice').each(function(){
        var $notice = $(this);
        var text = String($notice.text() || '');
        if ($notice.attr('id') !== 'calliope-sp-job-runner-notice' && (text.indexOf('Publication queued') !== -1 || text.indexOf('browser worker') !== -1)) $notice.remove();
      });
    }
    function makeNotice() {
      var $wrap = $('.wrap').first();
      if (!$wrap.length) return $();
      removeQueuedServerNotice();
      var $notice = $('#calliope-sp-job-runner-notice');
      if ($notice.length) return $notice;
      $notice = $('<div/>', { id: 'calliope-sp-job-runner-notice', 'class': 'notice notice-info calliope-sp-job-runner-notice', 'aria-live': 'polite', 'aria-atomic': 'true' });
      var $panel = $('<div/>', { 'class': 'calliope-sp-job-progress' });
      var $header = $('<div/>', { 'class': 'calliope-sp-job-progress__header' });
      $header.append($('<div/>', { 'class': 'calliope-sp-job-progress__title' }).text(i18n.progressTitle || 'Publication in progress'));
      $header.append($('<div/>', { 'class': 'calliope-sp-job-progress__percent' }).text('0%'));
      $header.append($('<button/>', { type: 'button', 'class': 'notice-dismiss calliope-sp-job-progress__close', 'aria-label': i18n.closeNotice || 'Close publication notice', disabled: true }).append($('<span/>', { 'class': 'screen-reader-text' }).text(i18n.closeNotice || 'Close publication notice')));
      $panel.append($header);
      $panel.append($('<div/>', { 'class': 'calliope-sp-job-progress__status' }).text(i18n.queued || 'Publication queued.'));
      $panel.append($('<div/>', { 'class': 'calliope-sp-job-progress__bar', role: 'progressbar', 'aria-valuemin': '0', 'aria-valuemax': '100', 'aria-valuenow': '0' }).append($('<span/>', { 'class': 'calliope-sp-job-progress__bar-fill' })));
      $panel.append($('<div/>', { 'class': 'calliope-sp-job-progress__meta' }));
      $panel.append($('<div/>', { 'class': 'calliope-sp-job-progress__networks' }));
      $panel.append($('<div/>', { 'class': 'calliope-sp-job-progress__help' }).text(i18n.progressHelp || 'Keep this tab open until the process finishes.'));
      $notice.append($panel);
      $wrap.prepend($notice);
      return $notice;
    }
    function outcomeText(outcome) {
      if (outcome === 'published') return i18n.chipPublished || 'Published';
      if (outcome === 'skipped') return i18n.chipSkipped || 'Skipped';
      if (outcome === 'warning') return i18n.chipWarning || 'Warning';
      if (outcome === 'permission') return i18n.chipPermission || 'Permission required';
      if (outcome === 'access_tier') return i18n.chipAccessDenied || 'Production access denied';
      if (outcome === 'auth') return i18n.chipReconnect || 'Reconnection required';
      if (outcome === 'failed') return i18n.chipFailed || 'Failed';
      return i18n.waiting || 'Waiting…';
    }
    function publishOutcome(network, result) {
      result = result || {};
      if (!result.network) result.network = network;
      var actualNetwork = String(result.network || network || '');
      if (actualNetwork === 'pinterest') return applyPinterestOutcome(result);
      var classification = String(result.classification || '').toLowerCase();
      var code = String(result.error_code || '').toLowerCase();
      var uiStatus = String(result.ui_status || result.status || '').toLowerCase();
      if (result.skipped || code === 'duplicate_skipped' || classification.indexOf('duplicate_skipped') !== -1) return 'skipped';
      if (uiStatus === 'warning') return 'warning';
      return result.ok === false ? 'failed' : 'published';
    }
    function outcomeCountsAsOk(outcome, result) {
      if (outcome === 'failed' || outcome === 'skipped') return false;
      return !result || result.ok !== false;
    }
    function renderChips($notice) {
      var $networks = $notice.find('.calliope-sp-job-progress__networks').empty();
      Object.keys(jobStates).forEach(function(id){
        var state = jobStates[id];
        state.destinations.forEach(function(network){
          var cls = 'is-pending';
          var text = i18n.waiting || 'Waiting…';
          if (state.completed.indexOf(network) !== -1) {
            var outcome = state.outcomes[network] || (state.failedNetworks.indexOf(network) !== -1 ? 'failed' : 'published');
            cls = outcome === 'published' ? 'is-complete' : ((outcome === 'warning' || outcome === 'skipped') ? 'is-warning' : 'is-error');
            text = outcomeText(outcome);
          } else if (state.current === network) {
            cls = 'is-current'; text = '…';
          }
          var label = networkLabel(network);
          $networks.append($('<span/>', { 'class': 'calliope-sp-job-progress__chip ' + cls, 'aria-label': label + ' — ' + text }).append($('<strong/>').text(label)).append($('<em/>').text(text)));
        });
      });
    }
    function setProgressTitle($notice, title) {
      $notice.find('.calliope-sp-job-progress__title').text(title || i18n.progressTitle || 'Publication in progress');
    }
    function updateNotice(text, cssClass, assertive, title) {
      var $notice = makeNotice();
      if (!$notice.length) return;
      var currentTotals = totals();
      $notice.removeClass('notice-info notice-success notice-error notice-warning').addClass(cssClass || 'notice-info');
      $notice.attr('aria-live', assertive ? 'assertive' : 'polite');
      if (assertive) $notice.attr('role', 'alert'); else $notice.removeAttr('role');
      if (title) setProgressTitle($notice, title);
      $notice.find('.calliope-sp-job-progress__status').text(text || '');
      $notice.find('.calliope-sp-job-progress__percent').text(currentTotals.percent + '%');
      $notice.find('.calliope-sp-job-progress__bar').attr('aria-valuenow', String(currentTotals.percent));
      $notice.find('.calliope-sp-job-progress__bar-fill').css('width', currentTotals.percent + '%');
      $notice.find('.calliope-sp-job-progress__meta').text(format(i18n.progressCount || '%1$d of %2$d networks processed', currentTotals.completed, currentTotals.total));
      renderChips($notice);
    }
    $(document).on('click', '#calliope-sp-job-runner-notice .calliope-sp-job-progress__close', function(){ if (!workerActive) $('#calliope-sp-job-runner-notice').remove(); });

    function applyPinterestOutcome(result) {
      var outcome = pinterestOutcome(result);
      if (outcome !== 'published' && outcome !== 'failed') {
        finalPinterestOutcome = outcome;
        disablePinterest();
      }
      return outcome;
    }
    function applySafeResult(job, data) {
      if (!data || !data.processed) return;
      var outcome = publishOutcome(data.processed, data);
      markCompleted(job, data.processed, outcomeCountsAsOk(outcome, data), outcome);
      if (data.needs_review) finalNeedsReview = true;
    }
    function markFromReport(job, report) {
      if (!report || !report.results) return false;
      Object.keys(report.results).forEach(function(network){
        var result = report.results[network] || {};
        var outcome = publishOutcome(network, result);
        markCompleted(job, network, outcomeCountsAsOk(outcome, result), outcome);
        if (result.needs_review || result.stage === 'needs_review') finalNeedsReview = true;
      });
      return true;
    }
    function appendPinterestAction($notice, linkText) {
      if (!cfg.pinterestReconnectUrl || !linkText) return;
      var $status = $notice.find('.calliope-sp-job-progress__status');
      if ($status.find('a.calliope-sp-pinterest-action').length) return;
      $status.append(document.createTextNode(' '));
      $('<a/>', { href: cfg.pinterestReconnectUrl, 'class': 'calliope-sp-pinterest-action' }).text(linkText).appendTo($status);
    }
    function finishAllJobs() {
      workerActive = false;
      enablePublishButton();
      var $notice = makeNotice();
      $notice.find('.calliope-sp-job-progress__close').prop('disabled', false);
      $notice.find('.calliope-sp-job-progress__help').text('');
      var hasSuccessfulDestination = successCount() > 0;
      var errorTitle = hasSuccessfulDestination ? (i18n.progressPartial || 'Publication completed with errors') : (i18n.progressFailed || 'Publication failed');
      var errorClass = hasSuccessfulDestination ? 'notice-warning' : 'notice-error';
      if (finalPinterestOutcome === 'auth') {
        updateNotice(i18n.authError || 'Pinterest authorization is invalid or expired.', errorClass, true, errorTitle);
        appendPinterestAction($notice, i18n.reconnectPinterest || 'Reconnect Pinterest');
      } else if (finalPinterestOutcome === 'permission') {
        updateNotice(i18n.permissionError || 'Pinterest needs additional publishing permissions.', errorClass, true, errorTitle);
        appendPinterestAction($notice, i18n.reconnectPinterest || 'Reconnect Pinterest');
      } else if (finalPinterestOutcome === 'access_tier') {
        var accessMessage = cfg.pinterestEnvironment === 'sandbox'
          ? (i18n.sandboxAccessError || 'Pinterest accepted the connection but denied Pin publishing in Sandbox.')
          : (i18n.productionAccessError || 'Pinterest accepted the connection but denied Pin publishing in Production.');
        updateNotice(accessMessage, errorClass, true, errorTitle);
        appendPinterestAction($notice, i18n.reviewPinterestSettings || 'Review Pinterest settings');
      } else if (finalNeedsReview) {
        updateNotice(i18n.needsReview || 'The publication needs manual review.', 'notice-warning', true, i18n.progressNeedsReview || 'Publication requires review');
      } else if (finalPinterestWarning && !hasFailures()) {
        updateNotice(finalPinterestWarning, 'notice-warning', false, i18n.progressWarnings || 'Publication completed with warnings');
      } else if (hasFailures()) {
        var currentTotals = totals();
        var failedCount = 0;
        Object.keys(jobStates).forEach(function(id){ failedCount += jobStates[id].failedNetworks.length; });
        var partialTitle = i18n.progressPartial || 'Publication completed with errors';
        if (currentTotals.completed > failedCount) updateNotice(i18n.partial || i18n.doneWithErrors || 'Published to some destinations. Review the errors below.', 'notice-warning', true, partialTitle);
        else updateNotice(i18n.generalError || 'The selected destinations could not be published.', 'notice-error', true, i18n.progressFailed || 'Publication failed');
      } else {
        var selectedNetworks = [];
        Object.keys(jobStates).forEach(function(id){ selectedNetworks = selectedNetworks.concat(jobStates[id].destinations); });
        selectedNetworks = unique(selectedNetworks);
        var successText = selectedNetworks.length === 1 ? format(i18n.completedNetwork || '%s published.', networkLabel(selectedNetworks[0])) : (i18n.done || 'Published successfully.');
        updateNotice(successText, 'notice-success', false, i18n.progressCompleted || 'Publication completed');
        if (window.CALLIOPE_SP_MANUAL_DRAFT && typeof window.CALLIOPE_SP_MANUAL_DRAFT.clearAfterSuccessfulPublish === 'function') window.CALLIOPE_SP_MANUAL_DRAFT.clearAfterSuccessfulPublish();
      }
      var historyRetryFinished = validJobs.some(function(job){ return job && job.source === 'history_retry'; });
      var activeTab = '';
      try { activeTab = (new URLSearchParams(window.location.search)).get('tab') || ''; } catch (e) { activeTab = ''; }
      if (historyRetryFinished && activeTab === 'history') {
        window.setTimeout(function(){ window.location.reload(); }, 1200);
      }
    }
    function hasValidJob(job) { return !!(job && job.job_id && job.token && jobStates[job.job_id]); }
    function runStep(job, done) {
      if (!hasValidJob(job)) { done(); return; }
      var state = jobStates[job.job_id];
      var current = nextNetwork(job);
      state.current = current;
      updateNotice(current ? format(i18n.runningNetwork || 'Publishing %s…', networkLabel(current)) : (i18n.running || 'Publishing in safe steps…'), 'notice-info', false, i18n.progressTitle || 'Publication in progress');
      $.ajax({
        url: cfg.ajaxUrl, method: 'POST', dataType: 'json', timeout: 120000,
        data: { action: 'calliope_sp_run_publish_job_step', nonce: cfg.nonce, job_id: job.job_id, token: job.token }
      }).done(function(response){
        if (!response || !response.success) {
          state.failed = true; state.current = ''; state.done = true; markRemainingFailed(state);
          updateNotice(i18n.failed || 'The browser worker could not continue. Review the error and try again manually.', 'notice-error', true, i18n.progressFailed || 'Publication failed');
          done(); return;
        }
        var data = response.data || {};
        if (data.pending) {
          state.current = data.current_network || current || '';
          if (!state.pendingProgress) state.pendingProgress = {};
          if (state.current) state.pendingProgress[state.current] = Math.max(0, Math.min(100, Number(data.progress || 0)));
          updateNotice(data.message || format(i18n.uploading || 'Uploading %1$s: %2$d%%', networkLabel(state.current), Number(data.progress || 0)), 'notice-info', false, i18n.progressTitle || 'Publication in progress');
          window.setTimeout(function(){ runStep(job, done); }, Math.max(1000, Math.min(300000, Number(data.retry_after || 5) * 1000)));
          return;
        }
        applySafeResult(job, data);
        if (data.processed) {
          if (data.ok === false) {
            var outcome = publishOutcome(data.processed, data);
            var message = data.message || format(i18n.failedNetwork || '%s failed. Continuing with the next network…', networkLabel(data.processed));
            if (outcome === 'skipped') message = data.message || format(i18n.skippedNetwork || '%s skipped. Continuing with the next network...', networkLabel(data.processed));
            if (outcome === 'auth') message = i18n.authError || 'Pinterest authorization is invalid or expired.';
            else if (outcome === 'permission') message = i18n.permissionError || 'Pinterest needs additional publishing permissions.';
            else if (outcome === 'access_tier') message = cfg.pinterestEnvironment === 'sandbox' ? (i18n.sandboxAccessError || message) : (i18n.productionAccessError || message);
            updateNotice(message, (outcome === 'failed' || outcome === 'skipped' || outcome === 'warning') ? 'notice-warning' : 'notice-error', outcome !== 'failed' && outcome !== 'skipped' && outcome !== 'warning', i18n.progressTitle || 'Publication in progress');
          } else if (String(data.classification || '').toLowerCase().indexOf('link_omitted') !== -1) {
            finalPinterestWarning = data.message || i18n.pinterestLinkOmitted || 'Pinterest published without the destination link because Pinterest blocked that URL.';
            updateNotice(finalPinterestWarning, 'notice-warning', false, i18n.progressTitle || 'Publication in progress');
          } else updateNotice(format(i18n.completedNetwork || '%s published.', networkLabel(data.processed)), 'notice-info', false, i18n.progressTitle || 'Publication in progress');
        }
        if (data.done) {
          if (!markFromReport(job, data.report || null)) state.completed = unique(state.completed.concat(state.destinations));
          state.current = ''; state.done = true; done(); return;
        }
        window.setTimeout(function(){ runStep(job, done); }, 900);
      }).fail(function(){
        state.failed = true; state.current = ''; state.done = true; markRemainingFailed(state);
        updateNotice(i18n.failed || 'The browser worker could not continue. Review the error and try again manually.', 'notice-error', true, i18n.progressFailed || 'Publication failed');
        done();
      });
    }

    var validJobs = jobs.filter(hasValidJob);
    var index = 0;
    function nextJob() {
      if (index >= validJobs.length) { finishAllJobs(); return; }
      runStep(validJobs[index], function(){ index += 1; nextJob(); });
    }
    updateNotice(i18n.queued || 'Publication queued.', 'notice-info', false, i18n.progressTitle || 'Publication in progress');
    nextJob();
  });
})(jQuery);

(function($){
  'use strict';

  $(function(){
    var cfg = window.CALLIOPE_SP_AI || {};
    var i18n = cfg.i18n || {};
    var $status = $('#calliope_sp_ai_status');
    var aiRequestActive = false;

    function setStatus(message, tone) {
      if (!$status.length) {
        return;
      }
      $status.removeClass('is-error is-success is-loading');
      if (tone) {
        $status.addClass('is-' + tone);
      }
      $status.text(message || '');
    }

    function collectPayload(field) {
      return {
        action: 'calliope_sp_ai_generate',
        nonce: cfg.nonce || '',
        field: field,
        prompt: $('#calliope_sp_ai_prompt').val() || '',
        title: $('#calliope_sp_title').val() || '',
        content: $('#calliope_sp_content').val() || '',
        link: $('#calliope_sp_link').val() || '',
        hashtags: $('#calliope_sp_hashtags').val() || '',
        link_context: $('#calliope_sp_link_context').val() || '',
        destinations: $('#calliope_sp_publish_form input[type="checkbox"][name^="post_to_"]:checked').map(function(){ return String(this.name || '').replace(/^post_to_/, ''); }).get()
      };
    }

    function getAIContextState() {
      return {
        prompt: String($('#calliope_sp_ai_prompt').val() || '').trim(),
        link: String($('#calliope_sp_link').val() || '').trim(),
        linkContext: String($('#calliope_sp_link_context').val() || '').trim()
      };
    }

    function hasAIContext() {
      var context = getAIContextState();
      return context.prompt.length > 0 || context.link.length > 0 || context.linkContext.length > 0;
    }

    function updateAIButtonsState() {
      var enabled = !!cfg.isConfigured && hasAIContext() && !aiRequestActive;
      var hint = cfg.isConfigured
        ? (i18n.needsContext || '')
        : (i18n.missingApiKey || '');
      $('.calliope-sp-ai-btn').each(function(){
        var $btn = $(this);
        if ($btn.data('loading')) {
          return;
        }
        $btn.prop('disabled', !enabled);
        if (enabled) {
          $btn.removeAttr('aria-disabled').removeAttr('title');
        } else {
          $btn.attr('aria-disabled', 'true').attr('title', hint);
        }
      });

      if (!enabled && $status.length && $status.hasClass('is-success')) {
        setStatus('', '');
      }
    }

    function applyResult(field, text) {
      var selector = '';
      if (field === 'title') selector = '#calliope_sp_title';
      if (field === 'content') selector = '#calliope_sp_content';
      if (field === 'hashtags') selector = '#calliope_sp_hashtags';
      if (!selector) return;
      $(selector).val(text).trigger('input').trigger('change');
    }

    function setAIButtonsBusy(isBusy, $activeButton, loadingLabel) {
      $('.calliope-sp-ai-btn').each(function(){
        var $btn = $(this);
        var isActive = $activeButton && $activeButton.length && this === $activeButton[0];

        if (isBusy) {
          $btn.prop('disabled', true).attr('aria-disabled', 'true');
          if (isActive) {
            $btn.data('loading', true).attr('aria-busy', 'true').text(loadingLabel || $btn.text());
          } else {
            $btn.removeAttr('aria-busy');
          }
          return;
        }

        if (isActive) {
          $btn.data('loading', false).removeAttr('aria-busy');
          $btn.text($btn.attr('data-default-label') || i18n.generate || $btn.text());
        } else {
          $btn.data('loading', false).removeAttr('aria-busy');
        }
      });
    }

    function isUsableGeneratedString(value) {
      return typeof value === 'string' && value.trim().length > 0;
    }

    function applyCompleteResult(data) {
      if (!data || data.field !== 'complete') {
        return false;
      }

      var title = data.title;
      var content = data.content;
      var hashtags = data.hashtags;
      if (!isUsableGeneratedString(title) || !isUsableGeneratedString(content) || !isUsableGeneratedString(hashtags)) {
        return false;
      }

      var $title = $('#calliope_sp_title');
      var $content = $('#calliope_sp_content');
      var $hashtags = $('#calliope_sp_hashtags');

      $title.val(title);
      $content.val(content);
      $hashtags.val(hashtags);

      $title.trigger('input').trigger('change');
      $content.trigger('input').trigger('change');
      $hashtags.trigger('input').trigger('change');
      $title.trigger('focus');
      $(document).trigger('calliope_sp_ai_complete_applied', [data]);

      return true;
    }

    function getAIErrorMessage(response, xhr, fallback) {
      if (response && response.data && response.data.message) {
        return response.data.message;
      }
      if (xhr && xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
        return xhr.responseJSON.data.message;
      }
      return fallback || i18n.requestFailed || '';
    }

    var contentSearchState = {
      page: 1,
      term: '',
      hasMore: false,
      request: null,
      timer: null,
      ids: {},
      selectedId: '',
      selectedItem: null
    };

    function setContentSearchExpanded(expanded) {
      var $results = $('#calliope_sp_link_results');
      var $input = $('#calliope_sp_link_search');
      expanded = !!expanded && $results.children().length > 0;
      $results.prop('hidden', !expanded);
      $input.attr('aria-expanded', expanded ? 'true' : 'false');
    }

    function getContentResultOptions() {
      return $('#calliope_sp_link_results .calliope-sp-link-result');
    }

    function focusContentResult(index) {
      var $options = getContentResultOptions();
      if (!$options.length) return;
      index = Math.max(0, Math.min(index, $options.length - 1));
      var node = $options.get(index);
      if (!node) return;
      node.focus();
      if (typeof node.scrollIntoView === 'function') node.scrollIntoView({ block: 'nearest' });
    }

    function renderSelectedContent(item) {
      var $selected = $('#calliope_sp_selected_context');
      var $text = $('#calliope_sp_selected_context_text');
      if (!$selected.length || !$text.length || !item) return;
      var label = String($selected.attr('data-selected-label') || 'Selected content:');
      $text.text(label + ' ' + String(item.title || ''));
      $selected.prop('hidden', false);
    }

    function clearSelectedContent() {
      contentSearchState.selectedId = '';
      contentSearchState.selectedItem = null;
      $('#calliope_sp_selected_context').prop('hidden', true);
      $('#calliope_sp_selected_context_text').text('');
      getContentResultOptions().removeClass('is-selected').attr('aria-selected', 'false');
    }

    function renderContentSearchMessage(message, className, append) {
      var $results = $('#calliope_sp_link_results');
      if (!$results.length) return;
      if (!append) {
        $results.empty();
      } else {
        $results.find('.calliope-sp-link-results__more, .calliope-sp-link-results__more-note').remove();
      }
      $results.attr('aria-busy', className === 'is-loading' ? 'true' : 'false');
      $('<div/>', { 'class': 'calliope-sp-link-results__message ' + (className || '') }).text(message || '').appendTo($results);
      setContentSearchExpanded(true);
    }

    function renderContentSearchResults(items, append, hasMore) {
      var $results = $('#calliope_sp_link_results');
      if (!$results.length) return;
      var previousScroll = append ? $results.scrollTop() : 0;
      if (!append) {
        $results.empty();
        contentSearchState.ids = {};
      } else {
        $results.find('.calliope-sp-link-results__message, .calliope-sp-link-results__more, .calliope-sp-link-results__more-note').remove();
      }
      $results.attr('aria-busy', 'false');
      if (!Array.isArray(items) || !items.length) {
        if (!append) renderContentSearchMessage(i18n.contentNoResults || 'No matching posts, pages or products were found.', 'is-empty', false);
        return;
      }
      items.forEach(function(item){
        item = item || {};
        var id = String(item.id || '');
        if (!id || contentSearchState.ids[id]) return;
        contentSearchState.ids[id] = true;
        var resultId = 'calliope_sp_link_result_' + id.replace(/[^A-Za-z0-9_-]/g, '_');
        var selected = contentSearchState.selectedId === id;
        var $button = $('<button/>', {
          type: 'button',
          id: resultId,
          role: 'option',
          'aria-selected': selected ? 'true' : 'false',
          'class': 'calliope-sp-link-result' + (selected ? ' is-selected' : '')
        }).data('item', item);
        $('<strong/>').text(item.title || '').appendTo($button);
        var meta = [item.type || '', item.status || ''];
        if (item.sku) meta.push('SKU: ' + item.sku);
        $('<span/>', { 'class': 'calliope-sp-link-result__meta' }).text(meta.filter(Boolean).join(' · ')).appendTo($button);
        if (item.excerpt) $('<span/>', { 'class': 'calliope-sp-link-result__excerpt' }).text(item.excerpt).appendTo($button);
        $button.appendTo($results);
      });
      if (hasMore) {
        var $more = $('<button/>', { type: 'button', id: 'calliope_sp_link_load_more', 'class': 'button button-secondary calliope-sp-link-results__more' }).text(i18n.contentMore || 'Load more results');
        $results.append($more);
        $('<div/>', { 'class': 'screen-reader-text calliope-sp-link-results__more-note' }).text(i18n.contentHasMore || 'More results are available.').appendTo($results);
      }
      setContentSearchExpanded(true);
      if (append) $results.scrollTop(previousScroll);
    }

    function searchContentForLink(loadMore) {
      var term = String($('#calliope_sp_link_search').val() || '').trim().replace(/\s+/g, ' ');
      if (term.length < 2) {
        contentSearchState.term = '';
        contentSearchState.page = 1;
        renderContentSearchMessage(i18n.contentNoResults || 'Enter at least two characters.', 'is-empty', false);
        return;
      }
      if (!cfg.ajaxUrl || !cfg.searchNonce) {
        renderContentSearchMessage(i18n.contentSearchFail || 'Could not search content. Try again.', 'is-error', false);
        return;
      }
      if (!loadMore || contentSearchState.term !== term) {
        contentSearchState.term = term;
        contentSearchState.page = 1;
        contentSearchState.ids = {};
      } else {
        contentSearchState.page += 1;
      }
      if (contentSearchState.request && typeof contentSearchState.request.abort === 'function') contentSearchState.request.abort();
      renderContentSearchMessage(i18n.searchingContent || 'Searching content…', 'is-loading', !!loadMore);
      contentSearchState.request = $.ajax({
        url: cfg.ajaxUrl,
        method: 'POST',
        dataType: 'json',
        data: { action: 'calliope_sp_search_content', nonce: cfg.searchNonce, term: term, page: contentSearchState.page, per_page: 20 }
      }).done(function(response){
        if (!response || !response.success || !response.data) {
          renderContentSearchMessage(i18n.contentSearchFail || 'Could not search content. Try again.', 'is-error', !!loadMore);
          return;
        }
        contentSearchState.hasMore = !!response.data.has_more;
        renderContentSearchResults(response.data.items || [], !!loadMore, contentSearchState.hasMore);
      }).fail(function(xhr, status){
        if (status === 'abort') return;
        renderContentSearchMessage(i18n.contentSearchFail || 'Could not search content. Try again.', 'is-error', !!loadMore);
      }).always(function(){ contentSearchState.request = null; });
    }

    $(document).on('click', '#calliope_sp_link_search_btn', function(){ searchContentForLink(false); });
    $(document).on('click', '#calliope_sp_link_load_more', function(){ if (contentSearchState.hasMore) searchContentForLink(true); });
    $(document).on('click', '#calliope_sp_change_selection', function(){
      setContentSearchExpanded(true);
      var $options = getContentResultOptions();
      var selectedIndex = $options.index($options.filter('[aria-selected="true"]').first());
      focusContentResult(selectedIndex >= 0 ? selectedIndex : 0);
    });
    $(document).on('focus', '#calliope_sp_link_search', function(){
      if (getContentResultOptions().length) setContentSearchExpanded(true);
    });
    $(document).on('input', '#calliope_sp_link_search', function(){
      window.clearTimeout(contentSearchState.timer);
      if ($('#calliope_sp_link_results').children().length) setContentSearchExpanded(true);
      contentSearchState.timer = window.setTimeout(function(){ searchContentForLink(false); }, 350);
    });
    $(document).on('keydown', '#calliope_sp_link_search', function(e){
      if (e.key === 'Enter') {
        e.preventDefault();
        window.clearTimeout(contentSearchState.timer);
        searchContentForLink(false);
      } else if (e.key === 'ArrowDown') {
        if (getContentResultOptions().length) {
          e.preventDefault();
          setContentSearchExpanded(true);
          focusContentResult(0);
        }
      } else if (e.key === 'Escape') {
        setContentSearchExpanded(false);
      }
    });

    $(document).on('keydown', '.calliope-sp-link-result', function(e){
      var $options = getContentResultOptions();
      var index = $options.index(this);
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        focusContentResult(index + 1);
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        if (index <= 0) {
          $('#calliope_sp_link_search').trigger('focus');
        } else {
          focusContentResult(index - 1);
        }
      } else if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        $(this).trigger('click');
      } else if (e.key === 'Escape') {
        e.preventDefault();
        setContentSearchExpanded(false);
        $('#calliope_sp_link_search').trigger('focus');
      }
    });

    $(document).on('click', '.calliope-sp-link-result', function(){
      var item = $(this).data('item') || {};
      var id = String(item.id || '');
      if (item.url) $('#calliope_sp_link').val(item.url).trigger('input').trigger('change');
      if (!String($('#calliope_sp_title').val() || '').trim() && item.title) $('#calliope_sp_title').val(item.title).trigger('input').trigger('change');
      $('#calliope_sp_link_context').val(item.context || '');
      $('#calliope_sp_source_post_id').val(id).trigger('change');
      contentSearchState.selectedId = id;
      contentSearchState.selectedItem = item;
      getContentResultOptions().each(function(){
        var selected = String(($(this).data('item') || {}).id || '') === id;
        $(this).toggleClass('is-selected', selected).attr('aria-selected', selected ? 'true' : 'false');
      });
      renderSelectedContent(item);
      setContentSearchExpanded(false);
      setStatus(i18n.contentSelected || 'Selected content was added as AI context.', 'success');
      updateAIButtonsState();
    });

    $(document).on('input change', '#calliope_sp_link', function(e){
      if (e.originalEvent) {
        $('#calliope_sp_link_context').val('');
        $('#calliope_sp_source_post_id').val('').trigger('change');
        clearSelectedContent();
      }
      updateAIButtonsState();
    });

    $(document).on('input change', '#calliope_sp_ai_prompt', function(){
      updateAIButtonsState();
    });

    updateAIButtonsState();

    $(document).on('click', '.calliope-sp-ai-btn', function(){
      var $btn = $(this);
      var field = String($btn.attr('data-ai-field') || '');
      var loadingLabel = field === 'complete'
        ? ($btn.attr('data-loading-label') || i18n.completeGenerating || i18n.generating || $btn.text())
        : (i18n.generating || $btn.text());

      if (!cfg.ajaxUrl || !cfg.nonce) {
        setStatus(i18n.requestFailed || 'The AI request failed. Check Settings and try again.', 'error');
        return;
      }

      if (aiRequestActive) {
        return;
      }

      if (!hasAIContext()) {
        setStatus(i18n.needsContext || 'AI generation needs context. Add an AI prompt or a link for this publication first.', 'error');
        updateAIButtonsState();
        return;
      }

      if (!cfg.isConfigured) {
        setStatus(i18n.missingApiKey || 'Add your Gemini API key in Settings before using AI generation.', 'error');
        if (cfg.settingsUrl) {
          window.setTimeout(function(){ window.location.href = cfg.settingsUrl; }, 900);
        }
        return;
      }

      aiRequestActive = true;
      setAIButtonsBusy(true, $btn, loadingLabel);
      setStatus(loadingLabel, 'loading');

      $.post(cfg.ajaxUrl, collectPayload(field))
        .done(function(response){
          if (field === 'complete') {
            if (!response || response.success !== true || !response.data || !applyCompleteResult(response.data)) {
              setStatus(getAIErrorMessage(response, null, i18n.completeFailed || i18n.requestFailed), 'error');
              return;
            }
            $('#calliope_sp_ai_used').val('1').trigger('change');
            setStatus(i18n.completeSuccess || '', 'success');
            return;
          }

          if (!response || !response.success || !response.data || !response.data.text) {
            var msg = response && response.data && response.data.message ? response.data.message : (i18n.requestFailed || 'The AI request failed. Check Settings and try again.');
            setStatus(msg, 'error');
            return;
          }
          applyResult(field, response.data.text);
          $('#calliope_sp_ai_used').val('1').trigger('change');
          setStatus('', 'success');
        })
        .fail(function(xhr){
          var msg = getAIErrorMessage(null, xhr, field === 'complete' ? (i18n.completeFailed || i18n.requestFailed) : i18n.requestFailed);
          setStatus(msg, 'error');
        })
        .always(function(){
          aiRequestActive = false;
          setAIButtonsBusy(false, $btn, '');
          updateAIButtonsState();
        });
    });
  });
})(jQuery);
