(function($){
  function ajax(action, data){
    return $.post(FALCIFY.ajax, $.extend({ action: action, nonce: FALCIFY.nonce }, data || {}));
  }
  function setUsage($el, d){
    if (!d || !d.success){ $el.html('<p class="falcify-muted">Données indisponibles. Vérifiez votre clé API.</p>'); return; }
    var pct = d.usage_percent || 0;
    $el.html(
      '<p><strong>Plan :</strong> ' + (d.plan || '-') + '</p>' +
      '<p><strong>Crédits utilisés :</strong> ' + d.words_used_current_month + ' / ' + d.monthly_word_limit + ' mots</p>' +
      '<div class="falcify-progress"><span style="width:' + Math.min(100,pct) + '%"></span></div>' +
      '<p class="falcify-muted">' + pct + '% consommé · Reste ' + d.remaining_words + ' mots · Réinitialisation : ' + (d.reset_date ? new Date(d.reset_date).toLocaleDateString() : '—') + '</p>'
    );
    $('[data-generations]').text(d.generations_count || 0);
  }
  function setConn(ok, label){
    $('[data-connection-dot]').removeClass('is-ok is-err').addClass(ok ? 'is-ok' : 'is-err');
    $('[data-connection-text]').text(label);
  }

  function closeModal(){ $('#falcify-modal').remove(); }
  function fmt(n){ return (n||0).toLocaleString('fr-FR'); }

  function openEstimateModal(d, $box){
    closeModal();
    var allowed = !!d.allowed;
    var pctAfter = d.usage_percent_after_generation || 0;
    var warn = '';
    if (allowed && pctAfter >= 95) warn = '<p class="falcify-warn">Votre quota est presque terminé. Pensez à changer de forfait.</p>';
    else if (allowed && pctAfter >= 80) warn = '<p class="falcify-warn">Vous aurez utilisé plus de 80% de votre quota mensuel.</p>';

    var html = '' +
    '<div id="falcify-modal" class="falcify-modal-backdrop">' +
      '<div class="falcify-modal">' +
        '<h2>' + (allowed ? 'Confirmer la génération FALC' : 'Quota insuffisant') + '</h2>' +
        (allowed
          ? ('<p>Cette génération va consommer environ <strong>' + fmt(d.estimated_words) + ' mots</strong> sur votre forfait <strong>' + (d.plan||'-') + '</strong>.</p>')
          : ('<p>Vous avez atteint la limite de votre forfait <strong>' + (d.plan||'-') + '</strong>. Passez au forfait supérieur pour continuer à générer des contenus FALC.</p>')) +
        '<ul class="falcify-modal-stats">' +
          '<li><span>Mots estimés</span><strong>' + fmt(d.estimated_words) + '</strong></li>' +
          '<li><span>Quota mensuel</span><strong>' + fmt(d.monthly_word_limit) + '</strong></li>' +
          '<li><span>Utilisés</span><strong>' + fmt(d.words_used_current_month) + '</strong></li>' +
          '<li><span>Restants</span><strong>' + fmt(d.remaining_words) + '</strong></li>' +
          '<li><span>Restants après</span><strong>' + fmt(d.remaining_after_generation) + '</strong></li>' +
        '</ul>' +
        '<div class="falcify-progress"><span style="width:' + Math.min(100, pctAfter) + '%"></span></div>' +
        '<p class="falcify-muted">' + pctAfter + '% consommé après génération</p>' +
        warn +
        '<div class="falcify-modal-actions">' +
          (allowed
            ? '<button type="button" class="button falcify-modal-cancel">Annuler</button><button type="button" class="button button-primary falcify-modal-confirm">Confirmer la génération</button>'
            : '<button type="button" class="button falcify-modal-cancel">Fermer</button><a class="button button-primary" target="_blank" href="' + (d.upgrade_url || '#') + '">Passer au forfait supérieur</a>') +
        '</div>' +
      '</div>' +
    '</div>';
    $('body').append(html);
    $('#falcify-modal').data('box', $box);
  }

  function runGenerate($box){
    var pid = $box.data('post-id');
    var $btn = $box.find('.falcify-btn-generate').prop('disabled', true);
    var $r = $box.find('.falcify-result').show().removeClass('is-error is-ok').text(FALCIFY.i18n.generating);
    var mode = 'strict';
    ajax('falcify_generate', { post_id: pid, mode: mode })
      .done(function(r){
        $r.addClass('is-ok').text(FALCIFY.i18n.success + ' (' + (r.data.word_count || 0) + ' mots, reste ' + (r.data.remaining_words || 0) + ')');
        var html = (r.data.pictos_html || r.data.falc_content || '');
        var editorId = $box.find('.falcify-btn-save').data('editor-id');
        if (editorId) {
          if (window.tinymce) {
            var ed = window.tinymce.get(editorId);
            if (ed && !ed.isHidden()) { ed.setContent(html); }
            else { $('#' + editorId).val(html); }
          } else { $('#' + editorId).val(html); }
        }
        setTimeout(function(){ location.reload(); }, 800);
      })
      .fail(function(r){
        var msg = (r.responseJSON && r.responseJSON.data && (r.responseJSON.data.error || r.responseJSON.data.message)) || '';
        $r.addClass('is-error').text(FALCIFY.i18n.error + ' : ' + msg);
        if (r.responseJSON && r.responseJSON.data && r.responseJSON.data.upgrade_required) {
          openEstimateModal(r.responseJSON.data, $box);
        }
      })
      .always(function(){ $btn.prop('disabled', false); });
  }

  $(function(){
    if ($('[data-usage]').length){
      ajax('falcify_refresh_usage').done(function(r){ setUsage($('[data-usage]'), r.data); })
        .fail(function(){ setUsage($('[data-usage]'), null); });
      ajax('falcify_test_connection').done(function(r){ setConn(true, 'Connecté · ' + (r.data.site_name || '')); })
        .fail(function(r){ setConn(false, (r.responseJSON && r.responseJSON.data && r.responseJSON.data.error) || 'Non connecté'); });
    }

    $(document).on('click', '.falcify-btn-test', function(e){
      e.preventDefault();
      var $b = $(this).prop('disabled', true).text('Test…');
      ajax('falcify_test_connection')
        .done(function(r){ setConn(true, 'Connecté'); alert('Connexion OK — Plan : ' + (r.data.plan || '-')); })
        .fail(function(r){ setConn(false, 'Erreur'); alert('Erreur : ' + ((r.responseJSON && r.responseJSON.data && r.responseJSON.data.error) || 'inconnue')); })
        .always(function(){ $b.prop('disabled', false).text('Tester la connexion'); });
    });

    $(document).on('click', '.falcify-btn-refresh-usage', function(e){
      e.preventDefault();
      var $b = $(this).prop('disabled', true).text('…');
      ajax('falcify_refresh_usage')
        .done(function(r){ setUsage($('[data-usage]'), r.data); })
        .fail(function(){ setUsage($('[data-usage]'), null); })
        .always(function(){ $b.prop('disabled', false).text('Actualiser'); });
    });

    // Metabox: estimate first, then confirm
    $(document).on('click', '.falcify-btn-generate', function(e){
      e.preventDefault();
      var $box = $(this).closest('.falcify-metabox');
      var pid = $box.data('post-id');
      var $btn = $(this).prop('disabled', true);
      var $r = $box.find('.falcify-result').show().removeClass('is-error is-ok').text('Estimation en cours…');
      var mode = 'strict';
      $box.data('mode', mode);
      ajax('falcify_estimate', { post_id: pid, mode: mode })
        .done(function(r){ $r.text(''); openEstimateModal(r.data, $box); })
        .fail(function(r){
          var d = (r.responseJSON && r.responseJSON.data) || {};
          $r.addClass('is-error').text((d.error || d.message) || 'Erreur d\'estimation');
        })
        .always(function(){ $btn.prop('disabled', false); });
    });

    $(document).on('click', '.falcify-modal-cancel', closeModal);
    $(document).on('click', '#falcify-modal', function(e){ if (e.target.id === 'falcify-modal') closeModal(); });
    $(document).on('click', '.falcify-modal-confirm', function(){
      var $box = $('#falcify-modal').data('box');
      closeModal();
      if ($box) runGenerate($box);
    });

    var STATUS_LABELS = { draft: 'Brouillon', validated: 'Validé', published: 'Publié' };

    $(document).on('click', '.falcify-btn-set-status', function(e){
      e.preventDefault();
      var $box = $(this).closest('.falcify-metabox');
      var pid = $box.data('post-id');
      var status = $(this).data('status');
      var editorId = $box.find('.falcify-btn-save').data('editor-id');
      var content = '';
      if (editorId) {
        if (window.tinymce) {
          var ed = window.tinymce.get(editorId);
          if (ed && !ed.isHidden()) { content = ed.getContent(); }
          else { content = $('#' + editorId).val() || ''; }
        } else {
          content = $('#' + editorId).val() || '';
        }
      }
      var $b = $(this).prop('disabled', true);
      ajax('falcify_set_status', { post_id: pid, status: status, content: content })
        .done(function(r){
          var st = r.data.status;
          $box.find('[data-falcify-status-pill]')
              .text(STATUS_LABELS[st] || st)
              .attr('class', 'falcify-status falcify-status-' + st);
          // Recharge l'aperçu pour rafraîchir les boutons disponibles
          location.reload();
        })
        .fail(function(){ alert('Erreur lors du changement de statut'); })
        .always(function(){ $b.prop('disabled', false); });
    });

    $(document).on('click', '.falcify-btn-edit', function(e){
      e.preventDefault();
      $(this).closest('.falcify-metabox').find('.falcify-editor').prop('hidden', false);
    });
    $(document).on('click', '.falcify-btn-cancel-edit', function(e){
      e.preventDefault();
      $(this).closest('.falcify-metabox').find('.falcify-editor').prop('hidden', true);
    });
    $(document).on('click', '.falcify-btn-save', function(e){
      e.preventDefault();
      var $btn = $(this);
      var $box = $btn.closest('.falcify-metabox');
      var pid = $box.data('post-id');
      var editorId = $btn.data('editor-id');
      var content = '';
      if (window.tinymce) {
        var ed = window.tinymce.get(editorId);
        if (ed && !ed.isHidden()) { content = ed.getContent(); }
        else { content = $('#' + editorId).val(); }
      } else {
        content = $('#' + editorId).val();
      }
      var $b = $btn.prop('disabled', true).text('Enregistrement…');
      ajax('falcify_save_content', { post_id: pid, content: content })
        .done(function(){ location.reload(); })
        .fail(function(){ alert('Erreur d\'enregistrement'); })
        .always(function(){ $b.prop('disabled', false).text('Enregistrer'); });
    });
    $(document).on('click', '.falcify-btn-copy', function(e){
      e.preventDefault();
      var txt = $(this).closest('.falcify-metabox').find('.falcify-preview-content').text();
      navigator.clipboard.writeText(txt).then(function(){ alert(FALCIFY.i18n.copied); });
    });
    $(document).on('click', '.falcify-btn-view', function(e){
      e.preventDefault();
      $(this).closest('.falcify-metabox').find('.falcify-preview').prop('hidden', false).attr('open', true);
    });

    // Support form submission
    $(document).on('submit', '#falcify-support-form', function(e){
      e.preventDefault();
      var $f = $(this);
      var $btn = $f.find('button[type=submit]');
      var $status = $f.find('[data-support-status]').removeClass('is-ok is-err').text('');
      var data = {
        subject:  $f.find('[name=subject]').val(),
        message:  $f.find('[name=message]').val(),
        category: $f.find('[name=category]').val(),
        priority: $f.find('[name=priority]').val()
      };
      $btn.prop('disabled', true).text('Envoi…');
      ajax('falcify_submit_ticket', data)
        .done(function(){
          $status.addClass('is-ok').text('Ticket envoye. Notre equipe vous repond par email sous 24h ouvrees.');
          $f[0].reset();
        })
        .fail(function(xhr){
          var err = (xhr.responseJSON && xhr.responseJSON.data && (xhr.responseJSON.data.error || xhr.responseJSON.data.message)) || 'Erreur lors de l envoi';
          $status.addClass('is-err').text(err);
        })
        .always(function(){ $btn.prop('disabled', false).text('Envoyer le ticket'); });
    });

  });

})(jQuery);

/* === Falcify v2.7.1 — Metabox v2 : score de lisibilité + modale pictos === */
(function($){
  // Score aligné sur class-falcify-list-columns.php::compute_score() :
  //   - pénalité avg mots/phrase si > 8  (max −40)
  //   - pénalité % mots > 8 lettres si > 10 % (max −40)
  //   - bonus +5 si h2/h3 présents (structure)
  // Seuils couleur identiques PHP : ≥ 80 vert, ≥ 60 orange, < 60 rouge.
  function computeScore(text, htmlContent){
    if (!text) return null;
    var clean = text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
    if (!clean) return null;
    var sentences = clean.split(/[.!?]+\s+/).filter(function(s){ return s.trim().length > 0; });
    if (!sentences.length) return null;
    var wordCounts = sentences.map(function(s){ return s.split(/\s+/).filter(Boolean).length; });
    var total = wordCounts.reduce(function(a, b){ return a + b; }, 0);
    var avg = total / sentences.length;
    var words = clean.split(/\s+/).filter(Boolean);
    var longCount = words.filter(function(w){ return w.replace(/[^A-Za-zÀ-ÿÀ-ɏ]/g, '').length > 8; }).length;
    var pctLong = total > 0 ? (longCount / total) * 100 : 0;
    var score = 100;
    if (avg > 8)      score -= Math.min(40, (avg - 8) * 4);
    if (pctLong > 10) score -= Math.min(40, (pctLong - 10) * 1.5);
    if (htmlContent && /<h[23]\b/i.test(htmlContent)) score += 5;
    return Math.max(0, Math.min(100, Math.round(score)));
  }

  function refreshScore($box){
    var $score = $box.find('[data-falcify-score]');
    if (!$score.length) return;
    var editorId = $box.find('.falcify-btn-save').data('editor-id');
    var text = '', html = '';
    if (editorId) {
      if (window.tinymce) {
        var ed = window.tinymce.get(editorId);
        if (ed && !ed.isHidden()) {
          text = ed.getContent({ format: 'text' });
          html = ed.getContent();
        } else {
          text = html = $('#' + editorId).val() || '';
        }
      } else {
        text = html = $('#' + editorId).val() || '';
      }
    }
    var s = computeScore(text, html);
    if (s === null) { $score.find('.falcify-score-value').text('—'); return; }
    $score.find('.falcify-score-value').text(s);
    $score.removeClass('is-good is-mid is-bad');
    if (s >= 80)      $score.addClass('is-good');
    else if (s >= 60) $score.addClass('is-mid');
    else              $score.addClass('is-bad');
  }

  $(function(){
    $('.falcify-card-v2').each(function(){ refreshScore($(this)); });

    // Recalcule le score à la frappe ou quand TinyMCE déclenche un input.
    $(document).on('input keyup', '.falcify-split-right textarea, .falcify-split-right .wp-editor-area', function(){
      refreshScore($(this).closest('.falcify-card-v2'));
    });
    if (window.tinymce) {
      window.tinymce.on('AddEditor', function(ev){
        ev.editor.on('Change KeyUp', function(){
          var id = ev.editor.id;
          var $box = $('[data-editor-id="' + id + '"]').closest('.falcify-card-v2');
          if ($box.length) refreshScore($box);
        });
      });
    }

  });
})(jQuery);

/* === Banque de pictogrammes (insertion manuelle) — v2.7.10 ============== */
(function($){
  function normalize(s){
    if (!s) return '';
    s = String(s).toLowerCase();
    try { s = s.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); } catch (e) {}
    return s;
  }
  function buildPictoHtml(p, baseUrl){
    var src = baseUrl + p.file;
    var label = (p.label || p.file || '').replace(/"/g, '&quot;');
    return '<span class="falc-picto" role="img" aria-label="' + label +
      '" title="' + label + '" data-picto="' + p.file +
      '"><img src="' + src + '" alt="' + label + '" width="32" height="32" loading="lazy" /></span>&nbsp;';
  }
  function insertIntoEditor(editorId, html){
    if (window.tinymce){
      var ed = window.tinymce.get(editorId);
      if (ed && !ed.isHidden()){
        ed.focus();
        ed.execCommand('mceInsertContent', false, html);
        ed.fire('Change');
        return true;
      }
    }
    var ta = document.getElementById(editorId);
    if (ta && 'selectionStart' in ta){
      var start = ta.selectionStart, end = ta.selectionEnd, val = ta.value;
      ta.value = val.slice(0, start) + html + val.slice(end);
      var pos = start + html.length;
      ta.selectionStart = ta.selectionEnd = pos;
      ta.focus();
      $(ta).trigger('input').trigger('change');
      return true;
    }
    return false;
  }
  function renderGrid($grid, list, baseUrl){
    var html = '';
    for (var i = 0; i < list.length; i++){
      var p = list[i];
      var src = baseUrl + p.file;
      var label = (p.label || p.file || '').replace(/"/g, '&quot;');
      html += '<button type="button" class="falcify-picker-item" role="listitem" ' +
        'data-picker-file="' + p.file + '" title="' + label + '" aria-label="' + label + '">' +
        '<img src="' + src + '" alt="" loading="lazy" />' +
        '<span class="falcify-picker-label">' + label + '</span>' +
        '</button>';
    }
    $grid.html(html);
  }
  function ensureLoaded($dlg){
    if ($dlg.data('falcify-picker-loaded')) return;
    var pictos = (window.FALCIFY && FALCIFY.pictos) || [];
    var baseUrl = (window.FALCIFY && FALCIFY.pictosBaseUrl) || '';
    var $grid = $dlg.find('[data-falcify-picker-grid]');
    var $count = $dlg.find('[data-falcify-picker-count]');
    renderGrid($grid, pictos, baseUrl);
    $count.text(pictos.length + ' pictogrammes');
    $dlg.data('falcify-picker-loaded', true);
    $dlg.data('falcify-picker-base', baseUrl);
    $dlg.data('falcify-picker-list', pictos);
  }
  $(document).on('click', '.falcify-btn-open-picker', function(e){
    e.preventDefault();
    var editorId = $(this).data('editor-id');
    var $box = $(this).closest('.falcify-card-v2');
    var $dlg = $box.find('[data-falcify-picker-modal]');
    if (!$dlg.length) return;
    $dlg.attr('data-editor-id', editorId);
    ensureLoaded($dlg);
    var dlg = $dlg[0];
    if (dlg.showModal) dlg.showModal(); else dlg.setAttribute('open', '');
    setTimeout(function(){ $dlg.find('[data-falcify-picker-search]').trigger('focus'); }, 30);
  });
  $(document).on('click', '[data-picker-close]', function(e){
    e.preventDefault();
    var dlg = $(this).closest('dialog')[0];
    if (dlg){ if (dlg.close) dlg.close(); else dlg.removeAttribute('open'); }
  });
  $(document).on('click', '.falcify-picker-modal', function(e){
    if (e.target === this){
      if (this.close) this.close(); else this.removeAttribute('open');
    }
  });
  $(document).on('input', '[data-falcify-picker-search]', function(){
    var q = normalize($(this).val()).trim();
    var $dlg = $(this).closest('dialog');
    var list = $dlg.data('falcify-picker-list') || [];
    var baseUrl = $dlg.data('falcify-picker-base') || '';
    var $grid = $dlg.find('[data-falcify-picker-grid]');
    var $empty = $dlg.find('[data-falcify-picker-empty]');
    var $count = $dlg.find('[data-falcify-picker-count]');
    var filtered;
    if (!q){
      filtered = list;
    } else {
      var tokens = q.split(/\s+/).filter(Boolean);
      filtered = list.filter(function(p){
        var hay = normalize(p.label) + ' ' + (p.kw || []).map(normalize).join(' ') + ' ' + normalize(p.file);
        return tokens.every(function(t){ return hay.indexOf(t) !== -1; });
      });
    }
    renderGrid($grid, filtered, baseUrl);
    $empty.prop('hidden', filtered.length > 0);
    $count.text(filtered.length + ' / ' + list.length);
  });
  $(document).on('click', '.falcify-picker-item', function(e){
    e.preventDefault();
    var $dlg = $(this).closest('dialog');
    var editorId = $dlg.attr('data-editor-id');
    var file = $(this).data('picker-file');
    var list = $dlg.data('falcify-picker-list') || [];
    var baseUrl = $dlg.data('falcify-picker-base') || '';
    var picto = null;
    for (var i = 0; i < list.length; i++){ if (list[i].file === file){ picto = list[i]; break; } }
    if (!picto) return;
    var html = buildPictoHtml(picto, baseUrl);
    var ok = insertIntoEditor(editorId, html);
    if (!ok){
      window.alert((FALCIFY && FALCIFY.i18n && FALCIFY.i18n.noEditor) || 'Editor not found');
      return;
    }
    var dlg = $dlg[0];
    if (dlg.close) dlg.close(); else dlg.removeAttribute('open');
  });
})(jQuery);

/* === Onboarding tour ===================================================== */
(function($){
  $(function(){
    var $tour = $('#falcify-tour');
    if (!$tour.length) return;
    var $app  = $('.falcify-app');
    var current = 1, total = 3;

    function show(n){
      current = Math.max(1, Math.min(total, n));
      $tour.find('.falcify-tour-step').attr('hidden', true);
      $tour.find('.falcify-tour-step[data-step="'+current+'"]').removeAttr('hidden');
      $tour.find('.falcify-tour-progress span').each(function(i){
        var step = i + 1;
        $(this).removeClass('is-active is-done');
        if (step < current) $(this).addClass('is-done');
        else if (step === current) $(this).addClass('is-active');
      });
    }
    function open(){ $tour.removeAttr('hidden'); show(1); }
    function close(persist){
      $tour.attr('hidden', true);
      if (persist){
        $.post(FALCIFY.ajax, { action: 'falcify_dismiss_onboarding', nonce: FALCIFY.nonce });
      }
    }

    $tour.on('click', '[data-tour-next]', function(){ show(current + 1); });
    $tour.on('click', '[data-tour-prev]', function(){ show(current - 1); });
    $tour.on('click', '[data-tour-skip]', function(e){ e.preventDefault(); close(true); });
    $tour.on('click', '[data-tour-finish]', function(){ close(true); });
    $tour.on('click', function(e){ if (e.target === this) close(true); });
    $(document).on('keydown.falcifyTour', function(e){
      if ($tour.is('[hidden]')) return;
      if (e.key === 'Escape') close(true);
      if (e.key === 'ArrowRight') show(current + 1);
      if (e.key === 'ArrowLeft') show(current - 1);
    });
    $(document).on('click', '[data-tour-open]', function(e){ e.preventDefault(); open(); });

    if ($app.attr('data-falcify-tour-autostart') === '1') open();
  });
})(jQuery);

/* === v2.7.11 — Réglage taille des pictos : presets + aperçu live === */
(function($){
  function syncPreview(val){
    var $live = $('#falcify-picto-live');
    if ($live.length){ $live[0].style.setProperty('--falc-picto-size', val + 'px'); }
  }
  $(document).on('click', '.falcify-picto-presets [data-picto-size]', function(e){
    e.preventDefault();
    var v = $(this).data('picto-size');
    $('#falcify-picto-size-input').val(v).trigger('input');
    syncPreview(v);
  });
  $(document).on('input change', '#falcify-picto-size-input', function(){
    var v = parseFloat($(this).val());
    if (!isNaN(v)) syncPreview(v);
  });
})(jQuery);
