(function($){
  'use strict';

  var cfg = window.CALLIOPE_SP_PLATFORM_PREVIEW || {};
  var i18n = cfg.i18n || {};
  var labels = cfg.networkLabels || {};
  var $form;
  var $root;
  var $section;
  var $tabs;
  var $body;
  var $empty;
  var $summary;
  var $publishStatus;
  var request = null;
  var timer = null;
  var sequence = 0;
  var currentItems = {};
  var activeNetwork = '';
  var dirty = true;
  var lastSignature = '';
  var allowSubmitOnce = false;

  function esc(value) {
    return $('<div>').text(value == null ? '' : String(value)).html();
  }

  function normalizeNetwork(value) {
    value = String(value || '').replace(/^post_to_/, '').toLowerCase();
    if (value === 'bsky') return 'bluesky';
    if (value === 'remote_wordpress') return 'wordpress_remote';
    return value;
  }

  function selectedNetworks() {
    var out = [];
    if (!$form || !$form.length) return out;

    // Restrict discovery to the standard Publisher destination block. The Pro
    // video composer can contain checkboxes with the same post_to_* names while
    // hidden; reading the whole form could therefore make Preview observe the
    // wrong composer. Explicit data attributes are preferred, with field names
    // retained as a backwards-compatible fallback.
    var $scope = $form.find('.calliope-sp-destinations-section:visible').first();
    if (!$scope.length) $scope = $form.find('.calliope-sp-destinations-section').first();
    if (!$scope.length) $scope = $form;

    $scope.find('input[type="checkbox"][name^="post_to_"]:checked').each(function(){
      var explicit = String($(this).attr('data-calliope-preview-network') || '').trim();
      var network = normalizeNetwork(explicit || this.name);
      if (network && out.indexOf(network) === -1) out.push(network);
    });

    // Account Groups are selection aliases for concrete destinations. Pro exposes
    // their ready network slugs as data only; the preview remains read-only and
    // never resolves or publishes anything from the browser.
    $scope.find('input[data-calliope-group-checkbox]:checked').each(function(){
      String($(this).attr('data-calliope-preview-networks') || '').split(',').forEach(function(value){
        var network = normalizeNetwork(value.trim());
        if (network && out.indexOf(network) === -1) out.push(network);
      });
    });
    return out;
  }

  function imageSrc() {
    var src = String($('#final-img').attr('src') || '').trim();
    return src;
  }

  function mediaType() {
    var publicationType = String($form.find('input[name="calliope_sp_publication_type"]:checked').val() || 'standard');
    if (publicationType === 'video') return 'video';

    var mode = String($form.find('input[name="calliope_spp_media_mode"]:checked').val() || '');
    if (mode === 'multiple_images') return 'carousel';
    if (mode === 'video') return 'video';

    if (imageSrc() || String($('#calliope_sp_data').val() || '') || String($('#calliope_sp_single_image_attachment_id').val() || '')) {
      return 'image';
    }
    return 'none';
  }

  function formFieldValue(name, fallback) {
    var form = $form && $form.length ? $form.get(0) : null;
    var field = form && form.elements && form.elements.namedItem ? form.elements.namedItem(name) : null;
    if (!field) return fallback == null ? '' : String(fallback);
    if (field.length && !field.tagName) {
      for (var i = 0; i < field.length; i++) {
        if ((field[i].type === 'radio' || field[i].type === 'checkbox') && field[i].checked) return String(field[i].value || '');
      }
      return fallback == null ? '' : String(fallback);
    }
    return String(field.value == null ? (fallback == null ? '' : fallback) : field.value);
  }

  function snapshot() {
    var media = mediaType();
    var templateSelections = {};
    $form.find('select[name^="calliope_spp_template_selection"]').each(function(){
      var match = String(this.name || '').match(/^calliope_spp_template_selection\[([a-z0-9_]+)\]$/i);
      if (match) templateSelections[match[1]] = String($(this).val() || '');
    });
    var data = {
      networks: selectedNetworks(),
      title: String($('#calliope_sp_title').val() || ''),
      content: String($('#calliope_sp_content').val() || ''),
      hashtags: String($('#calliope_sp_hashtags').val() || ''),
      link: String($('#calliope_sp_link').val() || ''),
      alt_text: String($('#calliope_sp_alt_text').val() || ''),
      post_id: String($('#calliope_sp_source_post_id').val() || '0'),
      image_format: String($('#calliope_sp_image_format').val() || 'original'),
      media_type: media,
      image_present: media === 'image' || media === 'carousel' ? '1' : '0',
      template_selection: templateSelections,
      remote_wordpress: {
        account_id: formFieldValue('calliope_spp_remote_wordpress[account_id]', ''),
        post_type: formFieldValue('calliope_spp_remote_wordpress[post_type]', 'posts'),
        status: formFieldValue('calliope_spp_remote_wordpress[status]', 'draft'),
        slug: formFieldValue('calliope_spp_remote_wordpress[slug]', ''),
        excerpt: formFieldValue('calliope_spp_remote_wordpress[excerpt]', ''),
        category_ids: formFieldValue('calliope_spp_remote_wordpress[category_ids]', ''),
        tag_ids: formFieldValue('calliope_spp_remote_wordpress[tag_ids]', '')
      },
      custom_webhook: {
        endpoint_id: formFieldValue('calliope_spp_custom_webhook[endpoint_id]', '')
      }
    };
    return data;
  }

  function hasDraftContent(data) {
    data = data || snapshot();
    if (String(data.title || '').trim()) return true;
    if (String(data.content || '').trim()) return true;
    if (String(data.hashtags || '').trim()) return true;
    if (String(data.link || '').trim()) return true;
    if (String(data.alt_text || '').trim()) return true;
    if (parseInt(data.post_id || '0', 10) > 0) return true;

    var imageData = String($('#calliope_sp_data').val() || '').trim();
    var imageAttachment = parseInt($('#calliope_sp_single_image_attachment_id').val() || '0', 10);
    if (imageData || imageAttachment > 0) return true;

    // Pro media fields may be injected dynamically. Count them only when they
    // contain an actual selected attachment/media value, not merely because a
    // publication mode radio is selected.
    var actualMedia = false;
    $('#calliope-spp-media-hidden-fields').find('input, textarea, select').each(function(){
      if ((this.type === 'radio' || this.type === 'checkbox') && !this.checked) return;
      var value = $(this).val();
      if (Array.isArray(value) ? value.length : String(value || '').trim()) {
        actualMedia = true;
        return false;
      }
    });
    return actualMedia;
  }

  function setPreviewVisibility(visible) {
    if (!$section || !$section.length) return;
    $section.prop('hidden', !visible);
    if (!visible) {
      if (request && request.abort) request.abort();
      request = null;
      currentItems = {};
      activeNetwork = '';
      $tabs.empty().prop('hidden', true);
      $body.empty().prop('hidden', true);
      $summary.empty();
      $publishStatus.empty();
      setLoading(false);
    }
  }

  function signature(data) {
    try { return JSON.stringify(data); } catch (e) { return String(Date.now()); }
  }

  function setLoading(loading) {
    $root.toggleClass('is-loading', !!loading);
    $('#calliope-sp-platform-preview-refresh').prop('disabled', !!loading).text(loading ? (i18n.loading || 'Updating preview…') : (i18n.refresh || 'Refresh preview'));
  }

  function statusClass(status) {
    status = String(status || 'ready');
    return status === 'invalid' ? 'is-invalid' : (status === 'warning' ? 'is-warning' : 'is-ready');
  }

  function statusLabel(item) {
    return item && item.status_label ? String(item.status_label) : String(item && item.status || '');
  }

  function renderSummary(summary) {
    summary = summary || {};
    var pieces = [];
    var ready = parseInt(summary.ready || 0, 10);
    var warning = parseInt(summary.warning || 0, 10);
    var invalid = parseInt(summary.invalid || 0, 10);
    if (ready) pieces.push('<span class="is-ready">' + ready + ' ' + esc(i18n.ready || 'Ready') + '</span>');
    if (warning) pieces.push('<span class="is-warning">' + warning + ' ' + esc(i18n.warning || 'Warning') + '</span>');
    if (invalid) pieces.push('<span class="is-invalid">' + invalid + ' ' + esc(i18n.invalid || 'Invalid') + '</span>');
    $summary.html(pieces.join('<span class="calliope-sp-preview-summary-sep">·</span>'));
  }

  function renderTabs(items, networks) {
    var html = '';
    networks.forEach(function(network){
      var item = items[network];
      if (!item) return;
      var selected = network === activeNetwork;
      html += '<button type="button" class="calliope-sp-platform-preview__tab ' + statusClass(item.status) + (selected ? ' is-active' : '') + '" role="tab" aria-selected="' + (selected ? 'true' : 'false') + '" data-preview-network="' + esc(network) + '">' +
        '<span>' + esc(item.label || labels[network] || network) + '</span>' +
        '<span class="calliope-sp-platform-preview__tab-state">' + esc(statusLabel(item)) + '</span>' +
      '</button>';
    });
    $tabs.html(html).prop('hidden', !html);
  }

  function mediaLabel(type) {
    switch (String(type || 'none')) {
      case 'image': return i18n.image || 'Image';
      case 'carousel': return i18n.carousel || 'Carousel';
      case 'video': return i18n.video || 'Video';
      default: return i18n.noMedia || 'No media selected';
    }
  }

  function renderPanel(network) {
    var item = currentItems[network];
    if (!item) {
      $body.prop('hidden', true).empty();
      return;
    }

    activeNetwork = network;
    $tabs.find('[data-preview-network]').each(function(){
      var active = String($(this).data('preview-network') || '') === network;
      $(this).toggleClass('is-active', active).attr('aria-selected', active ? 'true' : 'false');
    });

    var count = parseInt(item.character_count || 0, 10);
    var limit = parseInt(item.character_limit || 0, 10);
    var counter = limit > 0 ? count + ' / ' + limit + ' ' + (i18n.characters || 'characters') : count + ' ' + (i18n.characters || 'characters');
    var title = String(item.title || '').trim();
    var text = String(item.text || '').trim();
    var link = String(item.link || '').trim();
    var hashtags = String(item.hashtags || '').trim();
    var src = imageSrc();
    var media = String(item.media_type || mediaType());
    var messages = Array.isArray(item.messages) ? item.messages : [];

    var html = '<article class="calliope-sp-platform-card calliope-sp-platform-card--' + esc(network) + '">';
    html += '<header class="calliope-sp-platform-card__head">' +
      '<div><strong>' + esc(item.label || labels[network] || network) + '</strong>' +
      (item.template_applied ? '<span class="calliope-sp-platform-card__template">' + esc(i18n.templateApplied || 'Social Template applied') + '</span>' : '') +
      (item.tracking_applied ? '<span class="calliope-sp-platform-card__tracking">' + esc(i18n.utmTracking || 'UTM tracking') + '</span>' : '') +
      (item.short_link_applied ? '<span class="calliope-sp-platform-card__short-link">' + esc(i18n.shortLink || 'Short link') + '</span>' : '') + '</div>' +
      '<div class="calliope-sp-platform-card__head-right"><span class="calliope-sp-platform-preview__status ' + statusClass(item.status) + '">' + esc(statusLabel(item)) + '</span><small>' + esc(counter) + '</small></div>' +
    '</header>';

    html += '<div class="calliope-sp-platform-card__content">';
    if (title) html += '<h4>' + esc(title) + '</h4>';
    html += '<div class="calliope-sp-platform-card__text" data-empty="' + (!text ? '1' : '0') + '">' + (text ? esc(text).replace(/\n/g, '<br>') : '<span>—</span>') + '</div>';

    if (link) {
      html += '<div class="calliope-sp-platform-card__field"><strong>' + esc(i18n.link || 'Link') + '</strong><a href="' + esc(link) + '" target="_blank" rel="noopener noreferrer">' + esc(link) + '</a></div>';
    }
    if (hashtags) {
      html += '<div class="calliope-sp-platform-card__field"><strong>' + esc(i18n.hashtags || 'Hashtags') + '</strong><span>' + esc(hashtags) + '</span></div>';
    }

    html += '<div class="calliope-sp-platform-card__media"><div class="calliope-sp-platform-card__media-head"><strong>' + esc(i18n.media || 'Media') + '</strong><span>' + esc(mediaLabel(media)) + '</span></div>';
    if (media === 'image' && src) {
      html += '<img src="' + esc(src) + '" alt="" />';
    } else if (media === 'carousel') {
      html += '<div class="calliope-sp-platform-card__media-placeholder is-carousel"><span class="dashicons dashicons-images-alt2" aria-hidden="true"></span>' + esc(i18n.carousel || 'Carousel') + '</div>';
    } else if (media === 'video') {
      html += '<div class="calliope-sp-platform-card__media-placeholder is-video"><span class="dashicons dashicons-video-alt3" aria-hidden="true"></span>' + esc(i18n.video || 'Video') + '</div>';
    } else {
      html += '<div class="calliope-sp-platform-card__media-placeholder"><span class="dashicons dashicons-format-image" aria-hidden="true"></span>' + esc(i18n.noMedia || 'No media selected') + '</div>';
    }
    html += '</div></div>';

    html += '<div class="calliope-sp-platform-card__validation ' + statusClass(item.status) + '"><ul>';
    messages.forEach(function(message){ html += '<li>' + esc(message) + '</li>'; });
    html += '</ul></div></article>';

    $body.html(html).prop('hidden', false).attr('role', 'tabpanel');
  }

  function clientFallbackItem(network, data) {
    data = data || snapshot();
    var title = String(data.title || '').trim();
    var content = String(data.content || '').trim();
    var link = String(data.link || '').trim();
    var hashtags = String(data.hashtags || '').trim();
    var media = String(data.media_type || mediaType());
    var text = [content, link, hashtags].filter(function(value){ return String(value || '').trim() !== ''; }).join('\n\n');
    var messages = [i18n.previewFallback || 'Preview generated locally.'];
    var status = 'warning';

    if ((network === 'instagram' || network === 'pinterest') && media === 'none') {
      status = 'invalid';
      messages = [network === 'instagram' ? (i18n.instagramMediaRequired || 'Instagram requires media for this publication.') : (i18n.pinterestMediaRequired || 'Pinterest requires media for this publication.')];
    }

    if (network === 'wordpress_remote') {
      if (!title) {
        status = 'invalid';
        messages = [i18n.remoteTitleRequired || 'Remote WordPress requires a title.'];
      }
    }

    if (network === 'custom_webhook') {
      // Custom Webhook preview is intentionally human-facing. The endpoint still
      // receives the full technical schema, but the Publisher preview should show
      // only what the user is actually publishing.
      text = content;
      messages = [i18n.ready || 'Ready'];
      status = 'ready';
    }

    return {
      network: network,
      label: labels[network] || network,
      status: status,
      status_label: status === 'invalid' ? (i18n.invalid || 'Invalid') : (status === 'warning' ? (i18n.warning || 'Warning') : (i18n.ready || 'Ready')),
      messages: messages,
      title: title,
      text: text,
      link: link,
      hashtags: hashtags,
      media_type: media,
      character_count: text.length,
      character_limit: 0,
      template_applied: false,
      tracking_applied: false,
      short_link_applied: false,
      client_fallback: true
    };
  }

  function summaryFromItems(items, networks) {
    var summary = {ready:0, warning:0, invalid:0};
    networks.forEach(function(network){
      var item = items[network];
      if (!item) return;
      var state = String(item.status || 'ready');
      if (!Object.prototype.hasOwnProperty.call(summary, state)) state = 'ready';
      summary[state]++;
    });
    return summary;
  }

  function renderResult(data, networks) {
    currentItems = data && data.items ? data.items : {};
    var currentSnapshot = snapshot();

    // A Pro add-on, stale browser asset or temporary AJAX mismatch must never
    // turn real checked destinations into the misleading empty-state message.
    // Fill only missing items locally; server-generated provider previews always
    // take precedence whenever they are available.
    networks.forEach(function(network){
      if (!currentItems[network]) currentItems[network] = clientFallbackItem(network, currentSnapshot);
    });
    renderSummary(summaryFromItems(currentItems, networks));

    var available = networks.filter(function(network){ return !!currentItems[network]; });
    if (!available.length) {
      activeNetwork = '';
      $tabs.empty().prop('hidden', true);
      $body.empty().prop('hidden', true);
      $empty.text(networks.length ? (i18n.requestFailed || 'The platform preview could not be updated. Try again.') : (i18n.empty || 'Select at least one destination to see its preview.')).prop('hidden', false);
      return;
    }

    $empty.prop('hidden', true);
    if (!activeNetwork || available.indexOf(activeNetwork) === -1) activeNetwork = available[0];
    renderTabs(currentItems, available);
    renderPanel(activeNetwork);
  }

  function refresh(force) {
    if (!$form || !$form.length) return $.Deferred().resolve(null).promise();
    var data = snapshot();
    var sig = signature(data);
    var networks = data.networks.slice(0);

    if (!hasDraftContent(data)) {
      dirty = true;
      lastSignature = '';
      setPreviewVisibility(false);
      return $.Deferred().resolve({items:{},summary:{},emptyDraft:true}).promise();
    }

    setPreviewVisibility(true);

    if (!networks.length) {
      if (request && request.abort) request.abort();
      request = null;
      dirty = false;
      lastSignature = sig;
      currentItems = {};
      renderResult({items:{},summary:{}}, []);
      return $.Deferred().resolve({items:{},summary:{}}).promise();
    }

    if (!force && !dirty && sig === lastSignature && Object.keys(currentItems).length) {
      return $.Deferred().resolve({items:currentItems}).promise();
    }

    if (request && request.abort) request.abort();
    var seq = ++sequence;
    setLoading(true);
    $publishStatus.text('');

    request = $.ajax({
      url: cfg.ajaxUrl || window.ajaxurl,
      method: 'POST',
      dataType: 'json',
      data: $.extend({}, data, {
        action: 'calliope_sp_platform_preview',
        nonce: cfg.nonce || ''
      })
    });

    request.done(function(response){
      if (seq !== sequence) return;
      if (!response || !response.success || !response.data) {
        $publishStatus.text((response && response.data && response.data.message) ? response.data.message : (i18n.requestFailed || 'The platform preview could not be updated. Try again.'));
        return;
      }
      dirty = false;
      lastSignature = sig;
      renderResult(response.data, networks);
    }).fail(function(xhr, status){
      if (status === 'abort' || seq !== sequence) return;
      renderResult({items:{},summary:{}}, networks);
      $publishStatus.text(i18n.requestFailed || 'The platform preview could not be updated. Try again.');
    }).always(function(){
      if (seq === sequence) setLoading(false);
    });

    return request;
  }

  function markDirtyAndSchedule() {
    dirty = true;
    if (timer) window.clearTimeout(timer);
    if (!hasDraftContent(snapshot())) {
      setPreviewVisibility(false);
      lastSignature = '';
      return;
    }
    setPreviewVisibility(true);
    timer = window.setTimeout(function(){ refresh(false); }, 400);
  }

  function firstInvalidNetwork() {
    var networks = selectedNetworks();
    for (var i = 0; i < networks.length; i++) {
      var item = currentItems[networks[i]];
      if (item && item.status === 'invalid') return networks[i];
    }
    return '';
  }

  function handleSubmitCapture(event) {
    if (allowSubmitOnce) {
      allowSubmitOnce = false;
      return;
    }
    if (!$form || !$form.length || event.target !== $form.get(0)) return;

    if (!hasDraftContent(snapshot())) {
      setPreviewVisibility(false);
      return;
    }

    event.preventDefault();
    event.stopPropagation();
    $publishStatus.text(i18n.checkingBeforePublish || 'Checking destination previews before publishing…');
    var submitter = event.submitter || null;

    refresh(true).done(function(response){
      if (!response || (response.success === false)) return;
      var invalid = firstInvalidNetwork();
      if (invalid) {
        activeNetwork = invalid;
        renderTabs(currentItems, selectedNetworks());
        renderPanel(invalid);
        $publishStatus.text(i18n.invalidBlocked || 'Fix invalid destination previews before publishing.');
        var node = document.getElementById('calliope-sp-platform-preview');
        if (node && node.scrollIntoView) node.scrollIntoView({behavior:'smooth', block:'center'});
        return;
      }

      $publishStatus.text('');
      allowSubmitOnce = true;
      var form = $form.get(0);
      if (form.requestSubmit) {
        try { form.requestSubmit(submitter && submitter.form === form ? submitter : undefined); return; } catch (e) {}
      }
      form.submit();
    });
  }

  $(function(){
    $form = $('#calliope_sp_publish_form');
    $root = $('#calliope-sp-platform-preview');
    $section = $('#calliope-sp-platform-preview-section');
    if (!$form.length || !$root.length || !$section.length) return;
    $tabs = $('#calliope-sp-platform-preview-tabs');
    $body = $('#calliope-sp-platform-preview-body');
    $empty = $('#calliope-sp-platform-preview-empty');
    $summary = $('#calliope-sp-platform-preview-summary');
    $publishStatus = $('#calliope-sp-preview-publish-status');

    $(document).on('click', '#calliope-sp-platform-preview-refresh', function(){ dirty = true; refresh(true); });
    $(document).on('click', '#calliope-sp-platform-preview-tabs [data-preview-network]', function(){ renderPanel(String($(this).data('preview-network') || '')); });

    $(document).on('input change', [
      '#calliope_sp_title', '#calliope_sp_content', '#calliope_sp_hashtags', '#calliope_sp_link',
      '#calliope_sp_alt_text', '#calliope_sp_source_post_id', '#calliope_sp_image_format',
      '#calliope_sp_data', '#calliope_sp_single_image_attachment_id',
      '#calliope_sp_publish_form input[name="calliope_sp_publication_type"]',
      '#calliope_sp_publish_form input[name="calliope_spp_media_mode"]',
      '#calliope_sp_publish_form input[type="checkbox"][name^="post_to_"]',
      '#calliope_sp_publish_form input[data-calliope-group-checkbox]',
      '#calliope_sp_publish_form select[name^="calliope_spp_template_selection"]',
      '#calliope_sp_publish_form [name^="calliope_spp_remote_wordpress"]',
      '#calliope_sp_publish_form [name^="calliope_spp_custom_webhook"]'
    ].join(','), markDirtyAndSchedule);

    $(document).on('load', '#final-img', markDirtyAndSchedule);
    $(document).on('click', '#btn-del, #btn-ok', function(){ window.setTimeout(markDirtyAndSchedule, 50); });

    $form.get(0).addEventListener('submit', handleSubmitCapture, true);

    var finalImage = document.getElementById('final-img');
    if (finalImage && window.MutationObserver) {
      new MutationObserver(function(mutations){
        for (var i = 0; i < mutations.length; i++) {
          if (mutations[i].type === 'attributes' && mutations[i].attributeName === 'src') {
            markDirtyAndSchedule();
            break;
          }
        }
      }).observe(finalImage, {attributes:true, attributeFilter:['src']});
    }

    if (hasDraftContent(snapshot())) {
      setPreviewVisibility(true);
      refresh(true);
    } else {
      setPreviewVisibility(false);
    }
  });
})(jQuery);
