﻿import React, {
  useState,
  useEffect,
  useCallback,
  useRef,
  memo,
  useDeferredValue,
} from "react";
import { TemplateState } from "../../types/elements";
import { useBuilder } from "../../contexts/builder/BuilderContext";
// Preview system removed

import { useCanvasSettings } from "../../contexts/CanvasSettingsContext";
import { getEditorFeatureFlags } from "../../utils/editorFeatures";
import { debugLog, debugError, debugWarn } from "../../utils/debug";

interface HeaderProps {
  templateName: string;
  templateDescription: string;
  canvasWidth: number;
  canvasHeight: number;
  showGuides: boolean;
  snapToGrid: boolean;
  isNewTemplate: boolean;
  isModified: boolean;
  isSaving: boolean;
  isLoading: boolean;
  isEditingExistingTemplate: boolean;
  onSave: () => void;
  onPreview: () => void;
  onNewTemplate: () => void;
  onUpdateTemplateSettings: (settings: Partial<TemplateState>) => void;
}

// ── PDF Simulation HTML helpers (module-level, aucune fermeture sur state) ──

function pdfSimBuildSpacing(value: any): string {
  if (!value) return "";
  if (typeof value === "number") return `${value}px`;
  if (typeof value === "object") {
    return `${value.top || 0}px ${value.right || 0}px ${value.bottom || 0}px ${value.left || 0}px`;
  }
  return "";
}

function pdfSimBuildBorder(border: any): string {
  if (!border?.width) return "";
  return `${border.width || 1}px ${border.style || "solid"} ${border.color || "#e5e7eb"}`;
}

function pdfSimBuildFlexLayout(layout: string | undefined, gap: number = 8): string {
  if (!layout) return "";
  if (layout === "horizontal") return `display: flex; flex-direction: row; gap: ${gap}px;`;
  if (layout === "vertical") return `display: flex; flex-direction: column; gap: ${gap}px;`;
  return "";
}

function pdfSimBuildGlobalStyles(el: any): string {
  let s = "";
  if (el.fontFamily) s += `font-family: ${el.fontFamily};`;
  if (el.fontWeight && el.fontWeight !== "normal") s += `font-weight: ${el.fontWeight};`;
  if (el.fontStyle && el.fontStyle !== "normal") s += `font-style: ${el.fontStyle};`;
  if (el.textDecoration && el.textDecoration !== "none") s += `text-decoration: ${el.textDecoration};`;
  if (el.textTransform && el.textTransform !== "none") s += `text-transform: ${el.textTransform};`;
  if (el.wordSpacing && el.wordSpacing !== "normal") s += `word-spacing: ${el.wordSpacing};`;
  return s;
}

function pdfSimCalcAdjustedDimensions(
  width: number, height: number, padding: any,
): { width: number; height: number; paddingStyle: string } {
  if (!padding) return { width, height, paddingStyle: "" };
  const top = (padding?.top || 0) as number;
  const bottom = (padding?.bottom || 0) as number;
  const left = (padding?.left || 0) as number;
  const right = (padding?.right || 0) as number;
  return {
    width: Math.max(0, width - left - right),
    height: Math.max(0, height - top - bottom),
    paddingStyle: `padding: ${top}px ${right}px ${bottom}px ${left}px;`,
  };
}

function pdfSimBuildFontStyles(el: any, ah: number): string {
  let s = "";
  if (el.fontSize) s += ` font-size: ${el.fontSize}px;`;
  if (el.fontFamily) s += ` font-family: ${el.fontFamily};`;
  if (el.fontWeight && el.fontWeight !== "normal") s += ` font-weight: ${el.fontWeight};`;
  if (el.fontStyle && el.fontStyle !== "normal") s += ` font-style: ${el.fontStyle};`;
  if (el.textDecoration && el.textDecoration !== "none") s += ` text-decoration: ${el.textDecoration};`;
  if (el.wordSpacing && el.wordSpacing !== "normal") s += ` word-spacing: ${el.wordSpacing};`;
  if (el.textTransform && el.textTransform !== "none") s += ` text-transform: ${el.textTransform};`;
  if (el.textAlign) s += ` text-align: ${el.textAlign};`;
  if (el.verticalAlign && el.verticalAlign !== "baseline") s += ` line-height: ${ah}px;`;
  return s;
}

function pdfSimBuildColorStyles(el: any): string {
  let s = "";
  if (el.textColor) s += ` color: ${el.textColor};`;
  if (el.backgroundColor && el.backgroundColor !== "transparent" && el.showBackground !== false) {
    s += ` background-color: ${el.backgroundColor};`;
  }
  return s;
}

function pdfSimBuildBoxStyles(el: any, paddingStyle: string): string {
  let s = "";
  if (el.borderWidth && el.borderWidth > 0) s += ` border: ${el.borderWidth}px solid ${el.borderColor || "#e5e7eb"};`;
  if (el.borderRadius && el.borderRadius > 0) s += ` border-radius: ${el.borderRadius}px;`;
  if (paddingStyle) s += ` ${paddingStyle}`;
  if (el.shadowBlur && el.shadowBlur > 0) {
    s += ` box-shadow: ${el.shadowOffsetX || 0}px ${el.shadowOffsetY || 0}px ${el.shadowBlur}px ${el.shadowColor || "#000000"};`;
  }
  if (el.rotation && el.rotation !== 0) s += ` transform: rotate(${el.rotation}deg);`;
  if (el.opacity !== undefined && el.opacity < 1) s += ` opacity: ${el.opacity};`;
  return s;
}

function pdfSimBuildBaseStyles(
  el: any, x: number, y: number, aw: number, ah: number, paddingStyle: string,
): string {
  return `left: ${x}px; top: ${y}px; width: ${aw}px; height: ${ah}px;`
    + pdfSimBuildFontStyles(el, ah)
    + pdfSimBuildColorStyles(el)
    + pdfSimBuildBoxStyles(el, paddingStyle);
}

function pdfSimGetJustify(textAlign?: string): string {
  if (textAlign === "center") return "center";
  if (textAlign === "right") return "flex-end";
  return "flex-start";
}

function pdfSimGetAlign(verticalAlign?: string): string {
  if (verticalAlign === "middle" || verticalAlign === "center") return "center";
  if (verticalAlign === "bottom") return "flex-end";
  return "flex-start";
}

function pdfSimWrapVerticalAlign(content: string, el: any): string {
  const isTop = !el.verticalAlign || el.verticalAlign === "top";
  if (isTop) {
    return el.textAlign
      ? `<div style="text-align: ${el.textAlign}; width: 100%; height: 100%; overflow: hidden;">${content}</div>`
      : content;
  }
  const justifyValue = pdfSimGetJustify(el.textAlign);
  const alignValue = (el.verticalAlign === "middle" || el.verticalAlign === "center") ? "center" : "flex-end";
  return `<div style="width: 100%; height: 100%; display: flex; flex-direction: row; align-items: ${alignValue}; justify-content: ${justifyValue}; flex-wrap: wrap;">${content}</div>`;
}

function pdfSimRenderText(el: any): { content: string; stylesAddition: string } {
  let content: string = el.text || el.content || "Texte";
  const gs = pdfSimBuildGlobalStyles(el);
  let sa = gs;
  const ms = pdfSimBuildSpacing(el.margin);
  if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border);
  if (bs) sa += ` border: ${bs};`;
  content = pdfSimWrapVerticalAlign(content, el);
  return { content, stylesAddition: sa };
}

function pdfSimRenderDocumentType(el: any): { content: string; stylesAddition: string } {
  let content: string = el.title || el.text || el.content || "FACTURE";
  const gs = pdfSimBuildGlobalStyles(el);
  let sa = gs;
  const ms = pdfSimBuildSpacing(el.margin);
  if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border);
  if (bs) sa += ` border: ${bs};`;
  const jv = pdfSimGetJustify(el.textAlign);
  const av = pdfSimGetAlign(el.verticalAlign);
  content = `<div style="width: 100%; height: 100%; display: flex; align-items: ${av}; justify-content: ${jv};">${content}</div>`;
  return { content, stylesAddition: sa };
}

function pdfSimRenderImage(el: any): { content: string; stylesAddition: string } {
  let content: string;
  if (el.src) {
    const gs = pdfSimBuildGlobalStyles(el);
    let imgStyles = `width: 100%; height: 100%; display: block; object-fit: ${el.objectFit || "cover"};`;
    if (el.opacity !== undefined && el.opacity < 1) imgStyles += ` opacity: ${el.opacity};`;
    if (el.borderRadius && el.borderRadius > 0) imgStyles += ` border-radius: ${el.borderRadius}px;`;
    if (gs) imgStyles += ` ${gs}`;
    content = `<img src="${el.src}" style="${imgStyles}" />`;
  } else {
    content = "📦";
  }
  let sa = "";
  const ms = pdfSimBuildSpacing(el.margin);
  if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border);
  if (bs) sa += ` border: ${bs};`;
  return { content, stylesAddition: sa };
}

function pdfSimRenderLine(el: any): { content: string; stylesAddition: string } {
  const lw = el.strokeWidth || 1;
  const lc = el.strokeColor || "#000000";
  const ls = el.style || el.borderStyle || "solid";
  let innerStyle: string;
  if (ls === "dashed") {
    innerStyle = `border-bottom: ${lw}px dashed ${lc}; width: 100%; margin: auto 0;`;
  } else if (ls === "dotted") {
    innerStyle = `border-bottom: ${lw}px dotted ${lc}; width: 100%; margin: auto 0;`;
  } else {
    innerStyle = `background-color: ${lc}; height: ${lw}px; width: 100%; margin: auto 0;`;
  }
  let sa = " display: flex; align-items: center;";
  const ms = pdfSimBuildSpacing(el.margin);
  if (ms) sa += ` margin: ${ms};`;
  return { content: `<div style="${innerStyle}"></div>`, stylesAddition: sa };
}

function pdfSimGetSectionMeta(section: string): { colorProp: string | null; bgProp: string | null; prefix: string } {
  const colorProps: Record<string, string> = { header: "headerTextColor", total: "totalTextColor", row: "rowTextColor" };
  const bgProps: Record<string, string> = { header: "headerBackgroundColor", cell: "bodyBackgroundColor" };
  const prefixes: Record<string, string> = { header: "header", cell: "body" };
  return { colorProp: colorProps[section] ?? null, bgProp: bgProps[section] ?? null, prefix: prefixes[section] ?? section };
}

function pdfSimApplySectionFonts(el: any, prefix: string): string {
  const size = el[`${prefix}FontSize`];
  const family = el[`${prefix}FontFamily`];
  const weight = el[`${prefix}FontWeight`];
  const style = el[`${prefix}FontStyle`];
  let s = "";
  if (size) s += ` font-size: ${size}px;`;
  if (family) s += ` font-family: ${family};`;
  if (weight) s += ` font-weight: ${weight};`;
  if (style) s += ` font-style: ${style};`;
  return s;
}

function pdfSimBuildTableSectionStyles(el: any, section: "header" | "cell" | "row" | "total"): string {
  let s = "padding: 8px; overflow: hidden; text-overflow: ellipsis;";
  if (el.textAlign) s += ` text-align: ${el.textAlign};`;
  if (el.verticalAlign && el.verticalAlign !== "baseline") s += ` vertical-align: ${el.verticalAlign};`;
  if (el.showBorders && el.borderWidth) s += ` border: ${el.borderWidth}px solid ${el.borderColor || "#e5e7eb"};`;
  const { colorProp, bgProp, prefix } = pdfSimGetSectionMeta(section);
  if (colorProp && el[colorProp]) s += ` color: ${el[colorProp]};`;
  else if (el.textColor) s += ` color: ${el.textColor};`;
  s += pdfSimApplySectionFonts(el, prefix);
  if (bgProp && el[bgProp] && el[bgProp] !== "transparent") s += ` background-color: ${el[bgProp]};`;
  if (section === "total") s += " font-weight: bold;";
  return s;
}

function pdfSimGetTableCellValue(col: string | null, element: any): string {
  const baseAmount = 100;
  const quantity = 1;
  const shippingCost = element.shippingCost || 10;
  const globalDiscount = element.globalDiscount || 0;
  const taxRate = element.taxRate || 0.2;
  const taxAmount = (baseAmount - globalDiscount) * taxRate;
  if (col === "SKU") return "SKU001";
  if (col === "Produit") return "Produit Exemple";
  if (col === "Description") return "Description du produit";
  if (col === "Qty" || col === "Quantité") return String(quantity);
  if (col === "Prix Unit.") return baseAmount.toFixed(2) + " €";
  if (col === "Total") return (baseAmount * quantity).toFixed(2) + " €";
  if (col === "Shipping") return shippingCost.toFixed(2) + " €";
  if (col === "Tax") return taxAmount.toFixed(2) + " €";
  return "N/A";
}

function pdfSimRenderTable(el: any): { content: string; stylesAddition: string } {
  let tableStyles = "border-collapse: collapse; width: 100%; table-layout: fixed;";
  if (el.globalFontSize) tableStyles += ` font-size: ${el.globalFontSize}px;`;
  else if (el.fontSize) tableStyles += ` font-size: ${el.fontSize}px;`;
  if (el.globalFontFamily) tableStyles += ` font-family: ${el.globalFontFamily};`;
  else if (el.fontFamily) tableStyles += ` font-family: ${el.fontFamily};`;
  const headerStyle = pdfSimBuildTableSectionStyles(el, "header");
  const cellStyles = pdfSimBuildTableSectionStyles(el, "cell");
  const rowStyle = pdfSimBuildTableSectionStyles(el, "row");
  const totalStyle = pdfSimBuildTableSectionStyles(el, "total");
  const tableId = `table-${el.id}`;
  let tableCSS = "";
  if (el.showAlternatingRows && el.alternateRowColor) {
    tableCSS = `<style>#${tableId} tbody tr:nth-child(odd) td { background-color: ${el.alternateRowColor}; }</style>`;
  }
  let content: string;
  if (el.content) {
    const wrapped = el.content
      .replaceAll(/<th([^>]*)>/g, `<th style="${headerStyle}"$1>`)
      .replaceAll(/<td([^>]*)>/g, `<td style="${cellStyles}"$1>`);
    content = tableCSS + `<table id="${tableId}" style="${tableStyles}">${wrapped}</table>`;
  } else {
    content = pdfSimBuildTableFromProps(el, tableId, tableStyles, tableCSS, headerStyle, rowStyle, totalStyle);
  }
  let sa = "";
  const ms = pdfSimBuildSpacing(el.margin);
  if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border);
  if (bs) sa += ` border: ${bs};`;
  return { content, stylesAddition: sa };
}

function pdfSimBuildTableFromProps(
  el: any, tableId: string, tableStyles: string, tableCSS: string,
  headerStyle: string, rowStyle: string, totalStyle: string,
): string {
  const cols = [
    el.showSku ? "SKU" : null,
    "Produit",
    el.showDescription ? "Description" : null,
    el.showQuantity ? "Qty" : "Quantité",
    "Prix Unit.", "Total",
    el.showShipping ? "Shipping" : null,
    el.showTax ? "Tax" : null,
  ].filter(Boolean);
  const baseAmount = 100;
  const shippingCost = el.shippingCost || 10;
  const globalDiscount = el.globalDiscount || 0;
  const taxRate = el.taxRate || 0.2;
  const taxAmount = (baseAmount - globalDiscount) * taxRate;
  const total = baseAmount + shippingCost - globalDiscount + taxAmount + (el.orderFees || 0);
  let html = tableCSS + `<table id="${tableId}" style="${tableStyles}">`;
  if (el.showHeaders !== false) {
    const headerCells = cols.map(c => `<th style="${headerStyle}">${c}</th>`).join("");
    html += `<thead><tr>${headerCells}</tr></thead>`;
  }
  html += "<tbody><tr>";
  html += cols.map(col => `<td style="${rowStyle}">${pdfSimGetTableCellValue(col, el)}</td>`).join("");
  html += "</tr>";
  if (el.showGlobalDiscount && globalDiscount > 0) {
    html += `<tr><td colspan="${cols.length - 1}" style="${rowStyle}">Discount:</td><td style="${rowStyle}">-${globalDiscount.toFixed(2)} €</td></tr>`;
  }
  html += "<tr>";
  html += cols.map((col, idx) => {
    let val: string;
    if (idx === cols.length - 1) val = total.toFixed(2) + " €";
    else if (col === "Produit") val = "TOTAL";
    else val = "";
    return `<td style="${totalStyle}">${val}</td>`;
  }).join("");
  html += "</tr></tbody></table>";
  return html;
}

function pdfSimConvertToString(value: any): string {
  if (!value) return "";
  if (typeof value === "string") return value;
  if (typeof value === "object") {
    if (value.value) return String(value.value);
    if (value[0]) return String(value[0]);
    if (value.phone) return String(value.phone);
    return JSON.stringify(value);
  }
  return String(value);
}

function pdfSimGetCompanyData(el: any): Record<string, string> {
  const pc = (globalThis as any).pdfBuilderData?.company || {};
  const c = pdfSimConvertToString;
  return {
    name: c(el.companyName || pc.name || ""),
    address: c(el.companyAddress || pc.address || ""),
    city: c(el.companyCity || pc.city || ""),
    phone: c(el.companyPhone || pc.phone || ""),
    email: c(el.companyEmail || pc.email || ""),
    website: c(el.companyWebsite || pc.website || ""),
    siret: c(el.companySiret || pc.siret || ""),
    tva: c(el.companyTva || pc.vat || ""),
    rcs: c(el.companyRcs || pc.rcs || ""),
    capital: c(el.companyCapital || pc.capital || ""),
  };
}

function pdfSimIsValidValue(value: string): boolean {
  return !!(value && value.trim() !== "" && value !== "Non indiqué" && value !== "{}");
}

function pdfSimHeaderDiv(text: string, el: any, gs: string): string {
  const fsz = el.headerFontSize || el.fontSize || 14;
  const fw = el.headerFontWeight || "bold";
  const col = el.headerTextColor || el.textColor || "#000000";
  return `<div style="font-size: ${fsz}px; font-weight: ${fw}; color: ${col}; ${gs}">${text}</div>`;
}

function pdfSimBodyDiv(text: string, el: any, gs: string): string {
  const fsz = el.bodyFontSize || el.fontSize || 12;
  const fw = el.bodyFontWeight || el.fontWeight || "normal";
  const col = el.bodyTextColor || el.textColor || "#666666";
  return `<div style="font-size: ${fsz}px; font-weight: ${fw}; color: ${col}; ${gs}">${text}</div>`;
}

function pdfSimPushCompanyField(
  parts: string[], el: any, flag: string, value: string, display: string, gs: string, isHeader = false,
): void {
  if (el[flag] !== false && pdfSimIsValidValue(value)) {
    parts.push(isHeader ? pdfSimHeaderDiv(display, el, gs) : pdfSimBodyDiv(display, el, gs));
  }
}

function pdfSimRenderCompanyInfoVertical(el: any, d: Record<string, string>, gs: string): string {
  const parts: string[] = [];
  pdfSimPushCompanyField(parts, el, "showCompanyName", d.name, d.name, gs, true);
  if (el.showAddress !== false && pdfSimIsValidValue(d.address)) {
    const addr = pdfSimIsValidValue(d.city) ? `${d.address}, ${d.city}` : d.address;
    parts.push(pdfSimBodyDiv(addr, el, gs));
  }
  pdfSimPushCompanyField(parts, el, "showEmail", d.email, `Email: ${d.email}`, gs);
  pdfSimPushCompanyField(parts, el, "showPhone", d.phone, `Tél: ${d.phone}`, gs);
  pdfSimPushCompanyField(parts, el, "showSiret", d.siret, `SIRET: ${d.siret}`, gs);
  pdfSimPushCompanyField(parts, el, "showRcs", d.rcs, `RCS: ${d.rcs}`, gs);
  pdfSimPushCompanyField(parts, el, "showVat", d.tva, `TVA: ${d.tva}`, gs);
  if (el.showCapital !== false && pdfSimIsValidValue(d.capital)) parts.push(pdfSimBodyDiv(`Capital: ${d.capital} €`, el, gs));
  const gap = Math.round((el.fontSize || 12) * 0.1);
  return `<div style="display: flex; flex-direction: column; gap: ${gap}px;">${parts.join("")}</div>`;
}

function pdfSimGetLegalFields(el: any, d: Record<string, string>): string[] {
  return [
    el.showSiret !== false && pdfSimIsValidValue(d.siret) ? d.siret : "",
    el.showRcs !== false && pdfSimIsValidValue(d.rcs) ? d.rcs : "",
    el.showVat !== false && pdfSimIsValidValue(d.tva) ? d.tva : "",
    el.showCapital !== false && pdfSimIsValidValue(d.capital) ? d.capital + " €" : "",
  ].filter((v): v is string => Boolean(v));
}

function pdfSimRenderCompanyInfoHorizontal(el: any, d: Record<string, string>, gs: string): string {
  const parts: string[] = [];
  if (el.showCompanyName !== false && pdfSimIsValidValue(d.name)) {
    parts.push(`<div style="font-size: ${el.headerFontSize || el.fontSize || 14}px; font-weight: ${el.headerFontWeight || "bold"}; color: ${el.headerTextColor || el.textColor || "#000000"}; width: 100%; ${gs}">${d.name}</div>`);
  }
  const addrParts = [
    el.showAddress !== false && pdfSimIsValidValue(d.address) ? d.address : "",
    pdfSimIsValidValue(d.city) ? d.city : "",
  ].filter(Boolean);
  if (addrParts.length) parts.push(pdfSimBodyDiv(addrParts.join(", "), el, `width: 100%; ${gs}`));
  const contact = [
    el.showEmail !== false && pdfSimIsValidValue(d.email) ? d.email : "",
    el.showPhone !== false && pdfSimIsValidValue(d.phone) ? d.phone : "",
  ].filter(Boolean).join(" | ");
  if (contact) parts.push(pdfSimBodyDiv(contact, el, `width: 100%; ${gs}`));
  const legal = pdfSimGetLegalFields(el, d).join(" | ");
  if (legal) parts.push(pdfSimBodyDiv(legal, el, `width: 100%; ${gs}`));
  return `<div style="display: flex; flex-direction: column; gap: 4px;">${parts.join("")}</div>`;
}

function pdfSimRenderCompanyInfoCompact(el: any, d: Record<string, string>, gs: string): string {
  const parts: string[] = [];
  if (el.showCompanyName !== false && pdfSimIsValidValue(d.name)) {
    parts.push(`<div style="font-size: ${el.headerFontSize || el.fontSize || 14}px; font-weight: ${el.headerFontWeight || "bold"}; color: ${el.headerTextColor || el.textColor || "#000000"}; width: 100%; ${gs}">${d.name}</div>`);
  }
  const addrWithCity = pdfSimIsValidValue(d.city) ? `${d.address}, ${d.city}` : d.address;
  const addrStr = el.showAddress !== false && pdfSimIsValidValue(d.address) ? addrWithCity : "";
  const contactFields = [
    el.showEmail !== false && pdfSimIsValidValue(d.email) ? d.email : "",
    el.showPhone !== false && pdfSimIsValidValue(d.phone) ? d.phone : "",
  ];
  const fields = [addrStr, ...contactFields, ...pdfSimGetLegalFields(el, d)].filter(Boolean).join(" • ");
  if (fields) {
    const fsz = el.bodyFontSize || el.fontSize || 12;
    const fw = el.bodyFontWeight || el.fontWeight || "normal";
    const col = el.bodyTextColor || el.textColor || "#666666";
    parts.push(`<div style="font-size: ${fsz}px; font-weight: ${fw}; color: ${col}; width: 100%; word-wrap: break-word; ${gs}">${fields}</div>`);
  }
  return `<div style="display: flex; flex-direction: column; gap: 4px;">${parts.join("")}</div>`;
}

function pdfSimBuildCompanyContent(el: any, d: Record<string, string>, gs: string): string {
  const custom = el.content || el.text || "";
  if (custom) return custom;
  if (el.layout === "horizontal") return pdfSimRenderCompanyInfoHorizontal(el, d, gs);
  if (el.layout === "compact") return pdfSimRenderCompanyInfoCompact(el, d, gs);
  return pdfSimRenderCompanyInfoVertical(el, d, gs);
}

function pdfSimApplyLayoutStyle(sa: string, el: any, gap?: number): string {
  if (!el.layout) return sa;
  const ls = gap === undefined ? pdfSimBuildFlexLayout(el.layout) : pdfSimBuildFlexLayout(el.layout, gap);
  return ls ? sa + ` ${ls}` : sa;
}

function pdfSimBuildCompanyBoxStyles(el: any): string {
  let sa = "";
  if (el.showBackground && el.backgroundColor && el.backgroundColor !== "transparent") sa += ` background-color: ${el.backgroundColor};`;
  if (el.borderWidth && el.borderWidth > 0 && el.borderColor) sa += ` border: ${el.borderWidth}px solid ${el.borderColor};`;
  if (el.rotation && el.rotation !== 0) sa += ` transform: rotate(${el.rotation}deg);`;
  if (el.borderRadius && el.borderRadius > 0) sa += ` border-radius: ${el.borderRadius}px;`;
  return sa;
}

function pdfSimBuildCompanyInfoStyles(el: any): string {
  let sa = pdfSimBuildCompanyBoxStyles(el);
  if (el.padding) { const ps = pdfSimBuildSpacing(el.padding); if (ps) sa += ` padding: ${ps};`; } else sa += " padding: 8px;";
  const ms = pdfSimBuildSpacing(el.margin); if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border); if (bs) sa += ` border: ${bs};`;
  if (el.separator) sa += ` border-bottom: 1px solid ${el.borderColor || "#e5e7eb"};`;
  return pdfSimApplyLayoutStyle(sa, el) + " overflow: auto;";
}

function pdfSimRenderCompanyInfo(el: any): { content: string; stylesAddition: string } {
  const d = pdfSimGetCompanyData(el);
  const gs = pdfSimBuildGlobalStyles(el);
  const content = pdfSimBuildCompanyContent(el, d, gs) || "<div>Entreprise non configurée</div>";
  return { content, stylesAddition: pdfSimBuildCompanyInfoStyles(el) };
}

function pdfSimBuildCustomerContent(el: any): string {
  const fsz = el.bodyFontSize || 12;
  const ff = el.bodyFontFamily || "Arial";
  const fw = el.bodyFontWeight || "normal";
  const fi = el.bodyFontStyle || "normal";
  const tc = el.textColor || "#374151";
  const hfsz = el.headerFontSize || 14;
  const hff = el.headerFontFamily || "Arial";
  const hfw = el.headerFontWeight || "bold";
  const hfi = el.headerFontStyle || "normal";
  const htc = el.headerTextColor || "#111827";
  const base = `font-size: ${fsz}px; font-family: ${ff}; font-weight: ${fw}; font-style: ${fi}; color: ${tc}; margin: 0;`;
  const hBase = `font-size: ${hfsz}px; font-family: ${hff}; font-weight: ${hfw}; font-style: ${hfi}; color: ${htc}; margin-bottom: 4px;`;
  const parts: string[] = [];
  if (el.showHeaders !== false) parts.push(`<div style="${hBase}">Client</div>`);
  if (el.showFullName !== false) parts.push(`<div style="${base}">Prénom Nom</div>`);
  if (el.showAddress !== false) parts.push(`<div style="${base}">123 Rue de la Paix, 75000 Paris</div>`);
  if (el.showEmail !== false) parts.push(`<div style="${base} line-height: 1.1;">client@example.com</div>`);
  if (el.showPhone !== false) parts.push(`<div style="${base}">+01 23 45 67 89</div>`);
  return parts.join("");
}

function pdfSimBuildCustomerStyles(el: any): string {
  let sa = pdfSimBuildGlobalStyles(el);
  if (el.backgroundColor && el.backgroundColor !== "transparent" && el.showBackground !== false) sa += ` background-color: ${el.backgroundColor};`;
  if (el.padding) { const ps = pdfSimBuildSpacing(el.padding); if (ps) sa += ` padding: ${ps};`; } else sa += " padding: 8px;";
  const ms = pdfSimBuildSpacing(el.margin); if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border); if (bs) sa += ` border: ${bs};`;
  if (el.borderRadius && el.borderRadius > 0) sa += ` border-radius: ${el.borderRadius}px;`;
  const gap = Math.round((el.fontSize || 12) * 0.1);
  return pdfSimApplyLayoutStyle(sa, el, gap) + " overflow: auto;";
}

function pdfSimRenderCustomerInfo(el: any): { content: string; stylesAddition: string } {
  return {
    content: el.content || el.text || pdfSimBuildCustomerContent(el),
    stylesAddition: pdfSimBuildCustomerStyles(el),
  };
}

function pdfSimBuildMentionsContent(el: any): string {
  const pc = (globalThis as any).pdfBuilderData?.company || {};
  const mentionParts: string[] = [];
  if (el.showEmail !== false && (el.email || pc.email)?.trim()) mentionParts.push(el.email || pc.email);
  if (el.showPhone !== false && (el.phone || pc.phone)?.trim()) mentionParts.push(el.phone || pc.phone);
  if (el.showSiret !== false && (el.siret || pc.siret)?.trim()) mentionParts.push(`SIRET: ${el.siret || pc.siret}`);
  if (el.showVat !== false && (el.tva || pc.vat)?.trim()) mentionParts.push(`TVA: ${el.tva || pc.vat}`);
  return mentionParts.join(el.separator || " • ");
}

function pdfSimRenderMentions(el: any): { content: string; stylesAddition: string } {
  const content = el.content || el.text || pdfSimBuildMentionsContent(el);
  let sa = pdfSimBuildGlobalStyles(el);
  const ps = pdfSimBuildSpacing(el.padding); if (ps) sa += ` padding: ${ps};`;
  const ms = pdfSimBuildSpacing(el.margin); if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border); if (bs) sa += ` border: ${bs};`;
  if (el.borderRadius && el.borderRadius > 0) sa += ` border-radius: ${el.borderRadius}px;`;
  if (el.showBackground && el.backgroundColor && el.backgroundColor !== "transparent") sa += ` background-color: ${el.backgroundColor};`;
  if (el.showSeparator) sa += ` border-bottom: 1px solid ${el.borderColor || "#e5e7eb"};`;
  const gap = Math.round((el.fontSize || 12) * 0.1);
  return { content, stylesAddition: pdfSimApplyLayoutStyle(sa, el, gap) };
}

function pdfSimRenderInvoiceNumber(el: any): { content: string; stylesAddition: string } {
  const invoiceNum = el.text || el.content || "001";
  const invoiceFormat = el.format || "FAC-{order_number}";
  let invoiceContent = invoiceFormat.replace("{order_number}", invoiceNum);
  const gs = pdfSimBuildGlobalStyles(el);
  const jv = pdfSimGetJustify(el.textAlign);
  const av = pdfSimGetAlign(el.verticalAlign);
  let sa = ` display: flex; align-items: ${av}; justify-content: ${jv};`;
  if (el.showLabel && el.labelText) {
    const labelText = el.labelText || "Invoice:";
    const hfsz = el.headerFontSize || el.fontSize || 12;
    const nfsz = el.numberFontSize || el.fontSize || 14;
    const lc = el.headerTextColor || el.textColor || "#000000";
    const nc = el.textColor || "#000000";
    invoiceContent = `<div style="display: flex; flex-direction: column; gap: 4px;"><div style="font-size: ${hfsz}px; color: ${lc}; font-weight: ${el.headerFontWeight || "normal"}; ${gs}">${labelText}</div><div style="font-size: ${nfsz}px; color: ${nc}; font-weight: ${el.fontWeight || "normal"}; ${gs}">${invoiceContent}</div></div>`;
  }
  if (el.contentAlign) sa += ` text-align: ${el.contentAlign};`;
  const ps2 = pdfSimBuildSpacing(el.padding); if (ps2) sa += ` padding: ${ps2};`;
  const ms = pdfSimBuildSpacing(el.margin); if (ms) sa += ` margin: ${ms};`;
  const bs = pdfSimBuildBorder(el.border); if (bs) sa += ` border: ${bs};`;
  return { content: invoiceContent, stylesAddition: sa };
}

function pdfSimRenderElementContent(el: any): { content: string; stylesAddition: string } {
  switch (el.type) {
    case "text":
    case "dynamic_text":    return pdfSimRenderText(el);
    case "document_type":   return pdfSimRenderDocumentType(el);
    case "company_logo":
    case "image":           return pdfSimRenderImage(el);
    case "line":
    case "separator":       return pdfSimRenderLine(el);
    case "product_table":
    case "table":           return pdfSimRenderTable(el);
    case "company_info":    return pdfSimRenderCompanyInfo(el);
    case "customer_info":   return pdfSimRenderCustomerInfo(el);
    case "mentions":
    case "note":            return pdfSimRenderMentions(el);
    case "woocommerce_invoice_number": return pdfSimRenderInvoiceNumber(el);
    default: return { content: el.text || el.content || el.label || `[${el.type}]`, stylesAddition: "" };
  }
}

function pdfSimRenderOneElement(element: any): string {
  if (element.visible === false) return "";
  const { width: aw, height: ah, paddingStyle } = pdfSimCalcAdjustedDimensions(
    element.width || 100, element.height || 50, element.padding,
  );
  let styles = pdfSimBuildBaseStyles(element, element.x || 0, element.y || 0, aw, ah, paddingStyle);
  const { content, stylesAddition } = pdfSimRenderElementContent(element);
  if (stylesAddition) styles += stylesAddition;
  if (["customer_info", "product_table", "company_info"].includes(element.type)) {
    styles = styles.replace("overflow: hidden", "overflow: auto");
  }
  return `<div class="element" style="${styles}">${content}</div>`;
}

function generatePDFSimulationHTML(elementsInput?: any[], canvasInput?: any, templateInput?: any): string {
  const w = canvasInput?.width || templateInput?.canvasWidth || 794;
  const h = canvasInput?.height || templateInput?.canvasHeight || 1123;
  const elements: any[] = elementsInput || [];
  const template: any = templateInput || {};
  const emptyContent = `<div style="padding: 40px; text-align: center; color: #999;">
    <p style="font-size: 14px; margin-bottom: 10px;">🎨 Canvas vide</p>
    <p style="font-size: 12px;">Aucun élément n'a été ajouté au template.</p>
  </div>`;
  const bodyContent = (elements.length > 0)
    ? elements.map(pdfSimRenderOneElement).join("")
    : emptyContent;
  return `<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Aperçu PDF - ${template.name || "Template"}</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    html, body { margin: 0; padding: 0; }
    body { padding: 20px; background: #f5f5f5; }
    .pdf-wrapper { display: flex; justify-content: center; }
    .pdf-page { width: ${w}px; height: ${h}px; position: relative; box-shadow: 0 0 10px rgba(0,0,0,0.1); background: white; font-family: Arial, sans-serif; }
    .element { position: absolute; box-sizing: border-box; overflow: hidden; padding: 0; margin: 0; font-family: Arial, sans-serif; font-size: 12px; white-space: pre-wrap; display: block; }
    .element > * { word-wrap: break-word; margin: 0; padding: 0; font-family: inherit; }
    .pdfb-element-flex { display: flex !important; align-items: center; }
    .pdfb-element-flex-start { align-items: flex-start !important; }
    .pdfb-element-flex-end { align-items: flex-end !important; }
    table { border-collapse: collapse; width: 100%; font-size: inherit; margin: 0; padding: 0; table-layout: fixed; }
    table td, table th { padding: 4px 6px; margin: 0; overflow: hidden; text-overflow: ellipsis; word-wrap: break-word; }
  </style>
</head>
<body>
  <div class="pdf-wrapper"><div class="pdf-page">${bodyContent}</div></div>
</body>
</html>`;
}

// ─── usePreviewActions ────────────────────────────────────────────────────────
function usePreviewActions(isPremium: boolean) {
  const { state } = useBuilder();
  const [showPreviewModal, setShowPreviewModal] = useState(false);
  const [previewOrderId, setPreviewOrderId] = useState("");
  const [isGeneratingPreview, setIsGeneratingPreview] = useState(false);
  const [availableOrders, setAvailableOrders] = useState<
    Array<{
      id: string;
      number: string;
      customer: string;
      date: string;
      total: string;
    }>
  >([]);
  const [isLoadingOrders, setIsLoadingOrders] = useState(false);
  const [activeEngine, setActiveEngine] = useState<{
    name: string;
    icon: string;
  } | null>(null);

  // État du compte à rebours (null = inactif, 1-10 = en cours)
  const [countdown, setCountdown] = useState<number | null>(null);
  // Position dans la file d'attente du service (null = inconnu ou non en file)
  const [queuePosition, setQueuePosition] = useState<number | null>(null);
  // Taille courante de la file pour afficher la progression côté UI
  const [queueSize, setQueueSize] = useState<number | null>(null);
  // Vrai dès qu'on entre dans la phase de file (avant countdown), faux dès que le countdown démarre
  const [isInQueuePhase, setIsInQueuePhase] = useState(false);
  // Refs pour la communication cross-closure entre le timer et le fetch
  const prefetchedPdfRef         = useRef<string | null>(null);
  const pdfReadyRef              = useRef<boolean>(false);
  const countdownDoneRef         = useRef<boolean>(false);
  const queuePollIntervalId      = useRef<ReturnType<typeof setInterval> | null>(null);
  const countdownIntervalRef     = useRef<ReturnType<typeof setInterval> | null>(null);
  const prefetchAbortControllerRef = useRef<AbortController | null>(null);

  const getAjaxUrl = () =>
    (globalThis as any).pdfBuilderAjax?.ajax_url ||
    (globalThis as any).pdfBuilderAjax?.url ||
    (globalThis as any).pdfBuilderData?.ajaxUrl ||
    "/wp-admin/admin-ajax.php";
  const getAjaxNonce = () =>
    (globalThis as any).pdfBuilderAjax?.nonce ||
    (globalThis as any).pdfBuilderData?.nonce ||
    (globalThis as any).pdfBuilderNonce ||
    "";

  const stopQueuePoll = () => {
    if (queuePollIntervalId.current !== null) {
      clearInterval(queuePollIntervalId.current);
      queuePollIntervalId.current = null;
    }
    setQueuePosition(null);
    setQueueSize(null);
  };

  const leaveQueue = () => {
    const fd = new FormData();
    fd.append("action", "pdfib_pdf_queue_leave");
    fd.append("nonce", getAjaxNonce());
    fetch(getAjaxUrl(), { method: "POST", body: fd }).catch(() => { /* best-effort */ });
  };

  const cancelQueuedPreview = () => {
    stopQueuePoll();
    leaveQueue();
    // Stopper le compte à rebours
    if (countdownIntervalRef.current !== null) {
      clearInterval(countdownIntervalRef.current);
      countdownIntervalRef.current = null;
    }
    // Annuler le fetch de préchargement PDF
    if (prefetchAbortControllerRef.current) {
      prefetchAbortControllerRef.current.abort();
      prefetchAbortControllerRef.current = null;
    }
    prefetchedPdfRef.current = null;
    pdfReadyRef.current = false;
    countdownDoneRef.current = false;
    setCountdown(null);
    setIsInQueuePhase(false);
    setIsGeneratingPreview(false);
  };

  // Charger le moteur PDF actif
  const loadActiveEngine = async () => {
    try {
      const response = await fetch(
        (globalThis as any).pdfBuilderData?.ajaxUrl || "",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          body: new URLSearchParams({
            action: "pdfib_get_active_engine",
            nonce: getAjaxNonce(),
          }),
        },
      );

      if (response.ok) {
        const data = await response.json();
        if (data.success && data.data) {
          setActiveEngine({
            name: data.data.display_name,
            icon: data.data.icon,
          });
        }
      }
    } catch (error) {
      debugError("Erreur lors du chargement du moteur PDF:", error);
    }
  };

  // Ouvrir la modale d'aperçu
  const handlePreview = async () => {
    setShowPreviewModal(true);
    setPreviewOrderId("");
    setIsLoadingOrders(true);

    // Charger le moteur actif en parallèle
    loadActiveEngine();

    try {
      // Récupérer la liste des commandes WooCommerce
      const response = await fetch(
        (globalThis as any).pdfBuilderData?.ajaxUrl || "",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          body: new URLSearchParams({
            action: "pdfib_get_orders_list",
            nonce: getAjaxNonce(),
          }),
        },
      );

      if (response.ok) {
        const data = await response.json();

        if (data.success && data.data) {
          setAvailableOrders(data.data);
        } else {
          alert(
            "Erreur lors du chargement des commandes: " +
              (data.data?.message || "Erreur inconnue"),
          );
        }
      } else {
        alert("Erreur réseau lors du chargement des commandes");
      }
    } catch (error) {
      debugError("Erreur lors du chargement des commandes:", error);
      alert(
        "Erreur: " + (error instanceof Error ? error.message : String(error)),
      );
    } finally {
      setIsLoadingOrders(false);
    }
  };

  // Ouvrir le HTML avec boutons Télécharger et Imprimer
  const openDebugHTML = async () => {
    if (!previewOrderId || previewOrderId.trim() === "") {
      alert("Veuillez sélectionner une commande");
      return;
    }

    const templateId = state.template?.id;
    if (!templateId) {
      alert("Erreur: Template ID manquant.");
      return;
    }

    try {
      // Récupérer le HTML via endpoint
      const formData = new FormData();
      formData.append("action", "pdfib_get_preview_html");
      formData.append("template_id", templateId.toString());
      formData.append("order_id", previewOrderId.trim());
      formData.append("nonce", getAjaxNonce());

      const response = await fetch(
        (globalThis as any).pdfBuilderData?.ajaxUrl || "/wp-admin/admin-ajax.php",
        {
          method: "POST",
          body: formData,
        },
      );

      if (!response.ok) {
        throw new Error(`Erreur serveur ${response.status}`);
      }

      const result = await response.json();
      if (!result.success) {
        throw new Error(result.data?.message || "Erreur inconnue");
      }

      const { html, order_number } = result.data;

      // Extraire les styles du head et le contenu du body
      const stylesMatch = html.match(/<head[^>]*>(.*?)<\/head>/is);
      const bodyMatch = html.match(/<body[^>]*>(.*?)<\/body>/is);
      const originalStyles = stylesMatch ? stylesMatch[1] : "";
      const bodyContent = bodyMatch ? bodyMatch[1] : html;

      // Créer une page HTML avec le contenu et les boutons
      const htmlPage = `
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Facture ${order_number} - HTML</title>
    ${originalStyles}
    <style>
        body {
            margin: 0;
            padding: 0;
            background: #f5f5f5;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        }
        .toolbar {
            position: fixed;
            top: 20px;
            right: 20px;
            display: flex;
            gap: 12px;
            z-index: 1000;
        }
        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 6px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: all 0.2s;
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        }
        .btn-download {
            background: #2271b1;
            color: white;
        }
        .btn-download:hover {
            background: #135e96;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(34,113,177,0.3);
        }
        .btn-print {
            background: #10b981;
            color: white;
        }
        .btn-print:hover {
            background: #059669;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(16,185,129,0.3);
        }
        .btn-zoom {
            background: #6b7280;
            color: white;
            padding: 12px 16px;
        }
        .btn-zoom:hover {
            background: #4b5563;
            transform: translateY(-1px);
            box-shadow: 0 4px 12px rgba(107,114,128,0.3);
        }
        .zoom-level {
            background: #f3f4f6;
            color: #374151;
            padding: 12px 16px;
            font-weight: bold;
            border-radius: 6px;
            min-width: 70px;
            text-align: center;
        }
        .content-wrapper {
            padding: 20px;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: flex-start;
            transition: transform 0.2s;
            transform-origin: center top;
        }
        @media print {
            body {
                background: white;
                padding: 0;
            }
            .toolbar {
                display: none !important;
            }
            .content-wrapper {
                padding: 0;
            }
        }
    </style>
</head>
<body>
    <div class="toolbar">
        <button class="btn btn-zoom" onclick="zoomOut()" title="Zoom arrière">
            <span>🔍➖</span>
        </button>
        <div class="zoom-level" id="zoomLevel">100%</div>
        <button class="btn btn-zoom" onclick="zoomIn()" title="Zoom avant">
            <span>🔍➕</span>
        </button>
        <button class="btn btn-download" onclick="downloadHTML()">
            <span>📥</span>
            <span>Télécharger HTML</span>
        </button>
        <button class="btn btn-print" onclick="window.print()">
            <span>🖨️</span>
            <span>Imprimer</span>
        </button>
    </div>
    
    <div class="content-wrapper" id="contentWrapper">
        ${bodyContent}
    </div>
    
    <script>
        let zoomScale = 1.0;
        const wrapper = document.getElementById('contentWrapper');
        const zoomLevelDisplay = document.getElementById('zoomLevel');
        
        function updateZoom() {
            wrapper.style.transform = 'scale(' + zoomScale + ')';
            zoomLevelDisplay.textContent = Math.round(zoomScale * 100) + '%';
        }
        
        function zoomIn() {
            if (zoomScale < 3.0) {
                zoomScale += 0.25;
                updateZoom();
            }
        }
        
        function zoomOut() {
            if (zoomScale > 0.25) {
                zoomScale -= 0.25;
                updateZoom();
            }
        }
        
        function downloadHTML() {
            const content = \`${html.replaceAll("`", "\\`").replaceAll("$", String.raw`\$`)}\`;
            const blob = new Blob([content], { type: 'text/html' });
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = 'facture-${order_number}.html';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(link.href);
        }
    </script>
</body>
</html>`;

      // Ouvrir dans un blob
      const htmlBlob = new Blob([htmlPage], { type: "text/html" });
      const htmlUrl = URL.createObjectURL(htmlBlob);
      globalThis.open(htmlUrl, "_blank");

      setTimeout(() => URL.revokeObjectURL(htmlUrl), 2000);
    } catch (error) {
      debugError("[HTML] Erreur:", error);
      alert("Erreur lors de la récupération du HTML");
    }
  };

  // Générer un PDF via AJAX – avec compte à rebours pour les utilisateurs gratuits
  const generatePDF = async () => {
    if (!previewOrderId || previewOrderId.trim() === "") {
      alert("Veuillez sélectionner une commande");
      return;
    }

    const templateId = state.template?.id;
    if (!templateId) {
      alert(
        "Erreur: Template ID manquant. Veuillez d'abord enregistrer le template.",
      );
      return;
    }

    setIsGeneratingPreview(true);

    // ── Utilisateurs gratuits : compte à rebours + préchargement en parallèle ──────
    // TODO: Pendant ce compte à rebours, afficher un slider publicitaire présentant
    //       d'autres plugins Threeaxe (ex. WooCommerce Booster, Invoice Pro…).
    //       Prévoir 3-4 slides avec image, titre, description courte et bouton CTA.
    //       Le PDF s'ouvre automatiquement dès que les 10 s sont écoulées ET que le
    //       fichier est prêt (le premier des deux événements qui survient le dernier).
    // ─────────────────────────────────────────────────────────────────────────────
    if (!isPremium) {
      prefetchedPdfRef.current = null;
      pdfReadyRef.current      = false;
      countdownDoneRef.current = false;

      setQueuePosition(0);  // défaut #1 affiché pendant le join
      setQueueSize(1);
      setIsInQueuePhase(true);

      const ajaxUrl      = getAjaxUrl();
      const nonce        = getAjaxNonce();
      // Token transmis à pdfib_generate_pdf pour le suivi interne Puppeteer
      const requestToken = crypto.randomUUID();

      const openPdf = (url: string) => {
        stopQueuePoll();
        leaveQueue();
        globalThis.open(url, "_blank");
        URL.revokeObjectURL(url);
        setShowPreviewModal(false);
        setIsGeneratingPreview(false);
        setCountdown(null);
      };

      // Démarre le compte à rebours (10 s) et la génération PDF en arrière-plan
      const startCountdownAndPrefetch = () => {
        setIsInQueuePhase(false);
        let currentCount = 10;
        setCountdown(currentCount);

        countdownIntervalRef.current = setInterval(() => {
          currentCount -= 1;
          setCountdown(currentCount);
          if (currentCount <= 0) {
            if (countdownIntervalRef.current !== null) {
              clearInterval(countdownIntervalRef.current);
              countdownIntervalRef.current = null;
            }
            countdownDoneRef.current = true;
            if (pdfReadyRef.current && prefetchedPdfRef.current) {
              openPdf(prefetchedPdfRef.current);
            }
          }
        }, 1000);

        // Préchargement du PDF en arrière-plan
        prefetchAbortControllerRef.current = new AbortController();
        const formData = new FormData();
        formData.append("action", "pdfib_generate_pdf");
        formData.append("template_id", templateId.toString());
        formData.append("order_id", previewOrderId.trim());
        formData.append("nonce", nonce);
        formData.append("request_token", requestToken);

        fetch(ajaxUrl, { method: "POST", body: formData, signal: prefetchAbortControllerRef.current.signal })
          .then(async (response) => {
            if (!response.ok) throw new Error("Erreur lors de la génération du PDF");
            const blob = await response.blob();
            prefetchedPdfRef.current = URL.createObjectURL(blob);
            pdfReadyRef.current = true;
            if (countdownDoneRef.current) {
              if (countdownIntervalRef.current !== null) {
                clearInterval(countdownIntervalRef.current);
                countdownIntervalRef.current = null;
              }
              openPdf(prefetchedPdfRef.current);
            }
          })
          .catch((error) => {
            if ((error as Error).name === "AbortError") return; // Annulé par l'utilisateur
            if (countdownIntervalRef.current !== null) {
              clearInterval(countdownIntervalRef.current);
              countdownIntervalRef.current = null;
            }
            cancelQueuedPreview();
            debugError("[PREVIEW] Erreur génération PDF:", error);
            alert("Erreur lors de la génération du PDF. Vérifiez la console pour plus de détails.");
          });
      };

      // ── File d'attente côté serveur (partagée avec la metabox WooCommerce) ──────
      try {
        const joinFd = new FormData();
        joinFd.append("action", "pdfib_pdf_queue_join");
        joinFd.append("nonce", nonce);
        const joinRes  = await fetch(ajaxUrl, { method: "POST", body: joinFd });
        const joinData = await joinRes.json();

        if (!joinData?.success) {
          throw new Error("Impossible de rejoindre la file d'attente");
        }

        // Toujours capturer la position retournée par le serveur (même si slot dispo)
        setQueuePosition(typeof joinData.data?.position === "number" ? joinData.data.position : 0);
        setQueueSize(typeof joinData.data?.queue_size === "number" ? joinData.data.queue_size : 1);

        if (joinData.data?.slot_available) {
          // Slot disponible immédiatement → démarrer directement
          startCountdownAndPrefetch();
        } else {
          // En attente dans la file → afficher la position et poller toutes les 2 s

          queuePollIntervalId.current = setInterval(async () => {
            try {
              const pollFd = new FormData();
              pollFd.append("action", "pdfib_pdf_queue_poll");
              pollFd.append("nonce", nonce);
              const pollRes  = await fetch(ajaxUrl, { method: "POST", body: pollFd });
              if (!pollRes.ok) return;
              const pollData = await pollRes.json();

              if (!pollData?.success) return;

              const pos = pollData.data?.position;
              const size = pollData.data?.queue_size;
              setQueuePosition(typeof pos === "number" ? pos : null);
              setQueueSize(typeof size === "number" ? size : null);

              if (pollData.data?.slot_available) {
                // Notre tour ! Arrêter le poll et démarrer
                stopQueuePoll();
                startCountdownAndPrefetch();
              }
            } catch { /* silencieux */ }
          }, 2000);
        }
      } catch (error) {
        cancelQueuedPreview();
        debugError("[QUEUE] Erreur d'accès à la file:", error);
        alert("Impossible de rejoindre la file d'attente PDF.");
      }

      return;
    }

    // ── Utilisateurs premium : génération directe, pas de délai ──────────────────
    try {
      const formData = new FormData();
      formData.append("action", "pdfib_generate_pdf");
      formData.append("template_id", templateId.toString());
      formData.append("order_id", previewOrderId.trim());
      formData.append("nonce", getAjaxNonce());

      const response = await fetch(
        (globalThis as any).pdfBuilderData?.ajaxUrl || "/wp-admin/admin-ajax.php",
        { method: "POST", body: formData },
      );

      if (!response.ok) throw new Error("Erreur lors de la génération du PDF");

      const blob = await response.blob();
      const url = URL.createObjectURL(blob);
      globalThis.open(url, "_blank");
      setShowPreviewModal(false);
    } catch (error) {
      debugError("[PREVIEW] Erreur génération PDF:", error);
      alert("Erreur lors de la génération du PDF. Vérifiez la console pour plus de détails.");
    } finally {
      setIsGeneratingPreview(false);
    }
  };

  return {
    showPreviewModal, setShowPreviewModal,
    previewOrderId, setPreviewOrderId,
    isGeneratingPreview,
    availableOrders, isLoadingOrders,
    activeEngine,
    loadActiveEngine, handlePreview, openDebugHTML, generatePDF,
    countdown, queuePosition, queueSize, isInQueuePhase, cancelQueuedPreview,
  };
}
// ─────────────────────────────────────────────────────────────────────────────

// ─── Scroll header hook ───────────────────────────────────────────────────────
function useHeaderScroll() {
  const [isHeaderFixed, setIsHeaderFixed] = useState(false);
  const [scrollTimeout, setScrollTimeout] = useState<ReturnType<typeof globalThis.setTimeout> | null>(null);

  const handleScroll = useCallback(() => {
    if (scrollTimeout) return;
    setScrollTimeout(
      globalThis.setTimeout(() => {
        const scrollTop = globalThis.pageYOffset || document.documentElement.scrollTop;
        setIsHeaderFixed(scrollTop > 120);
        setScrollTimeout(null);
      }, 50),
    );
  }, [scrollTimeout]);

  useEffect(() => {
    globalThis.addEventListener("scroll", handleScroll, { passive: true });
    return () => globalThis.removeEventListener("scroll", handleScroll);
  }, [handleScroll]);

  return { isHeaderFixed };
}

// ─── Modal drag hook ──────────────────────────────────────────────────────────
function useModalDrag(jsonModalMode: "json" | "html", showJsonModal: boolean) {
  const [modalPosition, setModalPosition] = useState<{ x: number; y: number }>({ x: 0, y: 0 });
  const [isDraggingModal, setIsDraggingModal] = useState(false);
  const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null);

  useEffect(() => {
    if (!isDraggingModal || !dragStart) return;
    const handleMouseMove = (e: MouseEvent) => {
      setModalPosition({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y });
    };
    const handleMouseUp = () => { setIsDraggingModal(false); setDragStart(null); };
    document.addEventListener("mousemove", handleMouseMove);
    document.addEventListener("mouseup", handleMouseUp);
    return () => {
      document.removeEventListener("mousemove", handleMouseMove);
      document.removeEventListener("mouseup", handleMouseUp);
    };
  }, [isDraggingModal, dragStart]);

  useEffect(() => {
    setIsDraggingModal(false);
    setDragStart(null);
  }, [jsonModalMode, showJsonModal]);

  return { modalPosition, isDraggingModal, setIsDraggingModal, setDragStart };
}

// ─── Button state helpers ──────────────────────────────────────────────────────
function getSaveButtonTitle(isLoading: boolean, isModified: boolean, isEditing: boolean): string {
  if (isLoading) return "Chargement du template...";
  if (isModified) return isEditing ? "Modifier le template" : "Enregistrer les modifications";
  return "Aucune modification";
}
function getSaveButtonLabel(isSaving: boolean, isEditing: boolean): string {
  if (isSaving) return "Enregistrement...";
  return isEditing ? "Modifier" : "Enregistrer";
}
function getTemplateStatusText(isSaving: boolean, isModified: boolean): string {
  if (isSaving) return "Enregistrement...";
  if (isModified) return "Modifié";
  return "Sauvegardé";
}
function computeHeaderButtonState(params: {
  deferredIsLoading: boolean;
  deferredIsModified: boolean;
  deferredIsSaving: boolean;
  deferredIsEditingExistingTemplate: boolean;
  isSaving: boolean;
  isPremium: boolean;
  previewOrderId: string;
}) {
  const { deferredIsLoading, deferredIsModified, deferredIsSaving, deferredIsEditingExistingTemplate, isSaving, isPremium, previewOrderId } = params;

  const noOrderSelected = "Veuillez sélectionner une commande";
  const premiumRequired = "Fonctionnalité premium - Activez votre licence";

  let newButtonOpacity: number;
  if (isSaving) { newButtonOpacity = 0.6; }
  else { newButtonOpacity = 1; }

  return {
    saveButtonTitle: getSaveButtonTitle(deferredIsLoading, deferredIsModified, deferredIsEditingExistingTemplate),
    saveButtonLabel: getSaveButtonLabel(deferredIsSaving, deferredIsEditingExistingTemplate),
    saveButtonIcon: deferredIsSaving ? "⟳" : "💾",
    templateStatusText: getTemplateStatusText(deferredIsSaving, deferredIsModified),
    newButtonOpacity,
  };
}

// ─── HTML preview hook ────────────────────────────────────────────────────────
function useHtmlPreview(
  state: ReturnType<typeof useBuilder>["state"],
  setJsonModalMode: (mode: "json" | "html") => void,
) {
  const [isGeneratingHtml, setIsGeneratingHtml] = useState(false);
  const [generatedHtml, setGeneratedHtml] = useState<string>("");

  const handleShowHtmlPreview = useCallback(async () => {
    setIsGeneratingHtml(true);
    try {
      const html = generatePDFSimulationHTML(state.elements, state.canvas, state.template);
      setGeneratedHtml(html);
      setJsonModalMode("html");
    } catch (error) {
      debugError("Erreur lors de la génération HTML:", error);
      alert(`❌ Erreur: ${error instanceof Error ? error.message : "Erreur inconnue"}`);
    } finally {
      setIsGeneratingHtml(false);
    }
  }, [state, setJsonModalMode]);

  return { isGeneratingHtml, generatedHtml, handleShowHtmlPreview };
}

// ─── Orientation permissions hook ──────────────────────────────────────────────
function useOrientationPermissions(): void {
  const [, setOrientationPermissions] = useState<{
    allowPortrait: boolean;
    allowLandscape: boolean;
    defaultOrientation: "portrait" | "landscape";
    availableOrientations: string[];
  }>({
    allowPortrait: true,
    allowLandscape: true,
    defaultOrientation: "portrait",
    availableOrientations: ["portrait", "landscape"],
  });
  useEffect(() => {
    try {
      const availableOrientations = (globalThis as any).availableOrientations || ["portrait", "landscape"];
      setOrientationPermissions({
        allowPortrait: availableOrientations.includes("portrait"),
        allowLandscape: availableOrientations.includes("landscape"),
        defaultOrientation: ((globalThis as any).pdfBuilderCanvasSettings?.default_canvas_orientation || "portrait") as "portrait" | "landscape",
        availableOrientations,
      });
    } catch (error) {
      debugError("Erreur lors du chargement des permissions d'orientation", error);
    }
  }, []);
}

// ─── Performance metrics hook ────────────────────────────────────────────────
function usePerformanceMetrics(enabled: boolean): { performanceMetrics: { fps: number; memoryUsage: number; lastUpdate: number } } {
  const [performanceMetrics, setPerformanceMetrics] = useState({ fps: 0, memoryUsage: 0, lastUpdate: 0 });
  useEffect(() => {
    if (!enabled) return;
    const updateMetrics = () => {
      const now = Date.now();
      setPerformanceMetrics(() => ({
        fps: Math.floor(Math.random() * 20) + 40,
        memoryUsage: Math.floor(Math.random() * 50) + 80,
        lastUpdate: now,
      }));
    };
    const interval = setInterval(updateMetrics, 2000);
    updateMetrics();
    return () => clearInterval(interval);
  }, [enabled]);
  return { performanceMetrics };
}

// ─── Container style helper ───────────────────────────────────────────────────
function buildHeaderContainerStyle(fixed: boolean): React.CSSProperties {
  const padding = fixed ? "16px" : "12px";
  return {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    padding,
    paddingLeft: padding,
    paddingRight: padding,
    backgroundColor: "#ffffff",
    borderBottom: "2px solid #e0e0e0",
    borderRadius: "0px",
    boxShadow: fixed
      ? "0 4px 12px rgba(0, 0, 0, 0.15), 0 2px 4px rgba(0, 0, 0, 0.1)"
      : "none",
    gap: "16px",
    position: fixed ? "fixed" : "relative",
    top: fixed ? "32px" : "auto",
    left: fixed ? "160px" : "auto",
    right: fixed ? "0" : "auto",
    width: fixed ? "calc(100% - 160px)" : "auto",
    zIndex: 1000,
    boxSizing: "border-box",
    transition: "all 0.25s ease-in-out",
  };
}

// ─── useHeaderSave hook ───────────────────────────────────────────────────────
function useHeaderSave(params: {
  templateName: string;
  deferredIsModified: boolean;
  deferredIsSaving: boolean;
  deferredIsLoading: boolean;
  canvasWidth: number;
  canvasHeight: number;
  showGuides: boolean;
  snapToGrid: boolean;
  state: ReturnType<typeof useBuilder>["state"];
  canvasSettings: ReturnType<typeof useCanvasSettings>;
  onSave: () => void;
}): () => Promise<void> {
  const {
    templateName, deferredIsModified, deferredIsSaving, deferredIsLoading,
    canvasWidth, canvasHeight, showGuides, snapToGrid, state, canvasSettings, onSave,
  } = params;
  return useCallback(async () => {
    const startTime = performance.now();
    debugLog("🚀 [PDF Builder] Bouton Enregistrer cliqué", {
      templateName, isModified: deferredIsModified, isSaving: deferredIsSaving, isLoading: deferredIsLoading,
      timestamp: new Date().toISOString(),
      canvasInfo: { width: canvasWidth, height: canvasHeight, showGuides, snapToGrid },
      elementsInfo: {
        totalElements: state.elements?.length || 0,
        elementTypes: state.elements?.reduce((acc: Record<string, number>, el) => {
          acc[el.type] = (acc[el.type] || 0) + 1;
          return acc;
        }, {}) || {},
      },
      builderState: {
        template: state.template
          ? { name: state.template.name, description: state.template.description, hasBackground: !!state.canvas.backgroundColor }
          : null,
        selectedElement: state.selection.selectedElements[0] || null,
        zoom: state.canvas.zoom || 1,
      },
      canvasSettings: { guidesEnabled: canvasSettings.guidesEnabled, memoryLimit: canvasSettings.memoryLimitJs },
    });
    try {
      debugLog("⏳ [PDF Builder] Début de la sauvegarde...");
      onSave();
      const saveDuration = performance.now() - startTime;
      debugLog("✅ [PDF Builder] Sauvegarde réussie", {
        templateName, timestamp: new Date().toISOString(), duration: `${saveDuration.toFixed(2)}ms`,
        performance: { saveTime: saveDuration, elementsCount: state.elements?.length || 0, templateSize: JSON.stringify(state.template).length, elementsSize: JSON.stringify(state.elements).length },
        postSaveState: { isModified: false, isSaving: false },
      });
      debugLog("📊 [PDF Builder] Métriques de sauvegarde", {
        duration: saveDuration,
        avgTimePerElement: state.elements?.length ? saveDuration / state.elements.length : 0,
        memoryUsage: (performance as any).memory
          ? { used: (performance as any).memory.usedJSHeapSize, total: (performance as any).memory.totalJSHeapSize, limit: (performance as any).memory.jsHeapSizeLimit }
          : "N/A",
      });
    } catch (error) {
      const failedDuration = performance.now() - startTime;
      debugError("❌ [PDF Builder] Erreur lors de la sauvegarde:", {
        error: error instanceof Error ? { message: error.message, stack: error.stack, name: error.name } : error,
        templateName, timestamp: new Date().toISOString(), duration: `${failedDuration.toFixed(2)}ms`,
        context: { isModified: deferredIsModified, isSaving: deferredIsSaving, elementsCount: state.elements?.length || 0 },
      });
      alert("Erreur lors de la sauvegarde: " + (error instanceof Error ? error.message : "Erreur inconnue"));
    }
  }, [templateName, deferredIsModified, deferredIsSaving, deferredIsLoading, canvasWidth, canvasHeight, showGuides, snapToGrid, state, canvasSettings, onSave]);
}

// ─── SettingsModal sub-component ─────────────────────────────────────────────
interface SettingsModalProps {
  show: boolean;
  onClose: () => void;
  originalTemplateName: string;
  editedTemplateName: string;
  setEditedTemplateName: React.Dispatch<React.SetStateAction<string>>;
  editedTemplateDescription: string;
  setEditedTemplateDescription: React.Dispatch<React.SetStateAction<string>>;
  editedCanvasWidth: number;
  editedCanvasHeight: number;
  isNewTemplate: boolean;
  deferredIsModified: boolean;
  isEditingExistingTemplate: boolean;
  templateStatusText: string;
  canvasSettings: ReturnType<typeof useCanvasSettings>;
  performanceMetrics: { fps: number; memoryUsage: number };
  showGuides: boolean;
  snapToGrid: boolean;
  onSaveSettings: (settings: { name: string; description: string; canvasWidth: number; canvasHeight: number; showGuides: boolean; snapToGrid: boolean }) => void;
}
function SettingsModal({
  show, onClose, originalTemplateName, editedTemplateName, setEditedTemplateName,
  editedTemplateDescription, setEditedTemplateDescription,
  editedCanvasWidth, editedCanvasHeight, isNewTemplate, deferredIsModified, isEditingExistingTemplate,
  templateStatusText, canvasSettings, performanceMetrics, showGuides, snapToGrid, onSaveSettings,
}: Readonly<SettingsModalProps>) {
  if (!show) return null;
  return (
    <div
      className="pdfb-canvas-modal-overlay"
      style={{ position: "fixed", top: 0, left: 0, width: "100%", height: "100%", background: "rgba(0, 0, 0, 0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 10000 }}
    >
      <div
        className="pdfb-canvas-modal-container"
        style={{ background: "#fff", borderRadius: "8px", boxShadow: "0 10px 40px rgba(0, 0, 0, 0.2)", width: "500px", maxWidth: "90vw", maxHeight: "85vh", overflow: "hidden", display: "flex", flexDirection: "column" }}
      >
        <div className="pdfb-canvas-modal-header" style={{ background: "#f5f5f5", borderBottom: "1px solid #ddd", padding: "20px 24px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <h3 style={{ margin: 0, fontSize: "16px", fontWeight: 600, color: "#333" }}>
            <span style={{ fontSize: "24px" }}>📄</span> Paramètres du template
          </h3>
          <button type="button" className="pdfb-canvas-modal-close" onClick={onClose} title="Fermer"
            style={{ background: "none", border: "none", cursor: "pointer", fontSize: "24px", color: "#666", padding: 0, width: "32px", height: "32px", display: "flex", alignItems: "center", justifyContent: "center" }}>
            &times;
          </button>
        </div>
        <div className="pdfb-canvas-modal-body" style={{ padding: "24px", overflowY: "auto", flex: 1 }}>
          <div className="pdfb-setting-group" style={{ marginBottom: "20px" }}>
            <label htmlFor="setting-template-name" className="pdfb-setting-label" style={{ display: "block", marginBottom: "8px", fontSize: "14px", fontWeight: 500, color: "#333" }}>
              Nom du template
            </label>
            <input id="setting-template-name" type="text" value={editedTemplateName} onChange={(e) => setEditedTemplateName(e.target.value)}
              className="pdfb-setting-input" placeholder="Entrez le nom du template" autoComplete="off" name="template_name_unique"
              style={{ width: "100%", padding: "8px 12px", border: "1px solid #ddd", borderRadius: "4px", fontSize: "14px" }} />
          </div>
          <div className="pdfb-setting-group" style={{ marginBottom: "20px" }}>
            <label htmlFor="setting-template-desc" className="pdfb-setting-label" style={{ display: "block", marginBottom: "8px", fontSize: "14px", fontWeight: 500, color: "#333" }}>
              Description
            </label>
            <textarea id="setting-template-desc" value={editedTemplateDescription} onChange={(e) => setEditedTemplateDescription(e.target.value)}
              className="pdfb-setting-textarea" placeholder="Description du template..." rows={3}
              style={{ width: "100%", padding: "8px 12px", border: "1px solid #ddd", borderRadius: "4px", fontSize: "14px", resize: "vertical" }} />
          </div>
          <div className="pdfb-setting-group" style={{ marginBottom: "20px" }}>
            <div className="pdfb-setting-label" style={{ display: "block", marginBottom: "8px", fontSize: "14px", fontWeight: 500, color: "#333" }}>Dimensions du canvas</div>
            <div className="pdfb-setting-input-group" style={{ display: "flex", alignItems: "center", gap: "8px" }}>
              <input type="number" value={editedCanvasWidth} disabled={true} className="pdfb-setting-input pdfb-setting-input-disabled" placeholder="Largeur"
                style={{ flex: 1, padding: "8px 12px", border: "1px solid #ddd", borderRadius: "4px", fontSize: "14px", background: "#f5f5f5", color: "#999" }} />
              <span className="pdfb-setting-input-separator" style={{ color: "#999", fontSize: "16px" }}>×</span>
              <input type="number" value={editedCanvasHeight} disabled={true} className="pdfb-setting-input pdfb-setting-input-disabled" placeholder="Hauteur"
                style={{ flex: 1, padding: "8px 12px", border: "1px solid #ddd", borderRadius: "4px", fontSize: "14px", background: "#f5f5f5", color: "#999" }} />
              <span className="pdfb-setting-unit" style={{ color: "#666", fontSize: "14px" }}>px</span>
            </div>
          </div>
          <div className="pdfb-setting-group" style={{ marginBottom: "20px" }}>
            <div className="pdfb-setting-label" style={{ display: "block", marginBottom: "8px", fontSize: "14px", fontWeight: 500, color: "#333" }}>Statut</div>
            <div className="pdfb-setting-status-tags" style={{ display: "flex", gap: "8px", flexWrap: "wrap" }}>
              {isNewTemplate && (
                <span className="pdfb-status-tag pdfb-status-new"
                  style={{ padding: "4px 12px", borderRadius: "12px", fontSize: "12px", fontWeight: 500, background: "#e7f3ff", color: "#0073aa", border: "1px solid #0073aa" }}>
                  Nouveau template
                </span>
              )}
              {deferredIsModified && (
                <span className="pdfb-status-tag pdfb-status-modified"
                  style={{ padding: "4px 12px", borderRadius: "12px", fontSize: "12px", fontWeight: 500, background: "#fff3cd", color: "#856404", border: "1px solid #ffc107" }}>
                  Modifié
                </span>
              )}
              {isEditingExistingTemplate && (
                <span className="pdfb-status-tag pdfb-status-editing"
                  style={{ padding: "4px 12px", borderRadius: "12px", fontSize: "12px", fontWeight: 500, background: "#d4edda", color: "#155724", border: "1px solid #28a745" }}>
                  Édition existante
                </span>
              )}
            </div>
          </div>
          <div className="pdfb-setting-group" style={{ marginBottom: "20px" }}>
            <div className="pdfb-setting-label" style={{ display: "block", marginBottom: "8px", fontSize: "14px", fontWeight: 500, color: "#333" }}>Informations système</div>
            <div className="pdfb-setting-info" style={{ fontSize: "12px", color: "#666", lineHeight: "1.6", background: "#f9f9f9", padding: "12px", borderRadius: "4px", border: "1px solid #e0e0e0" }}>
              <div>Template ID: {originalTemplateName || "N/A"}</div>
              <div>Dernière modification: {new Date().toLocaleString("fr-FR")}</div>
              <div>État: {templateStatusText}</div>
              {canvasSettings.performanceMonitoring && (
                <div>Performance: {performanceMetrics.fps} FPS, {performanceMetrics.memoryUsage}MB RAM</div>
              )}
              {canvasSettings.debugMode && (
                <div>Debug: FPS Target {canvasSettings.fpsTarget}, Memory Limit {canvasSettings.memoryLimitJs}MB</div>
              )}
            </div>
          </div>
        </div>
        <div className="pdfb-canvas-modal-footer"
          style={{ borderTop: "1px solid #ddd", padding: "16px 24px", display: "flex", justifyContent: "flex-end", gap: "12px", background: "#f9f9f9" }}>
          <button onClick={onClose} className="pdfb-canvas-modal-btn pdfb-canvas-modal-btn-secondary"
            style={{ padding: "10px 20px", border: "1px solid #ccc", borderRadius: "4px", background: "#fff", color: "#333", fontSize: "14px", fontWeight: 500, cursor: "pointer", transition: "all 0.2s" }}>
            Annuler
          </button>
          <button onClick={() => onSaveSettings({ name: editedTemplateName, description: editedTemplateDescription, canvasWidth: editedCanvasWidth, canvasHeight: editedCanvasHeight, showGuides, snapToGrid })}
            className="pdfb-canvas-modal-btn pdfb-canvas-modal-btn-primary"
            style={{ padding: "10px 20px", border: "none", borderRadius: "4px", background: "#0073aa", color: "#fff", fontSize: "14px", fontWeight: 500, cursor: "pointer", transition: "all 0.2s" }}>
            Sauvegarder
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── PreviewModal sub-component ──────────────────────────────────────────────
interface PreviewModalProps {
  show: boolean;
  onClose: () => void;
  previewOrderId: string;
  setPreviewOrderId: React.Dispatch<React.SetStateAction<string>>;
  isGeneratingPreview: boolean;
  availableOrders: Array<{ id: string; number: string; customer: string; date: string; total: string }>;
  isLoadingOrders: boolean;
  activeEngine: { name: string; icon: string } | null;
  generatePDF: () => void;
  openDebugHTML: () => void;
  isPremium: boolean;
  hasTemplateId: boolean;
  countdown: number | null;
}
function PreviewModal({ // NOSONAR
  show, onClose, previewOrderId, setPreviewOrderId, isGeneratingPreview, availableOrders,
  isLoadingOrders, activeEngine, generatePDF, openDebugHTML,
  isPremium, hasTemplateId, countdown,
}: Readonly<PreviewModalProps>) {
  if (!show) return null;
  const imageNotAvailable = isGeneratingPreview || !isPremium || !previewOrderId.trim() || !hasTemplateId;
  const pdfNotAvailable = isGeneratingPreview || !previewOrderId.trim() || !hasTemplateId;
  return (
    <div className="pdfb-canvas-modal-overlay" style={{ display: "flex" }}>
      <div className="pdfb-canvas-modal-container" style={{ maxWidth: "500px" }}>
        <div className="pdfb-canvas-modal-header">
          <h3>
            <span style={{ fontSize: "24px" }}>👁️</span> Générer un aperçu
            {activeEngine && (
              <span style={{ marginLeft: "12px", fontSize: "14px", color: "#059669", backgroundColor: "#d1fae5", padding: "4px 10px", borderRadius: "4px", fontWeight: "500" }}>
                {activeEngine.icon} {activeEngine.name}
              </span>
            )}
          </h3>
          <button type="button" className="pdfb-canvas-modal-close" onClick={onClose} title="Fermer">&times;</button>
        </div>
        <div className="pdfb-canvas-modal-body">
          <div className="pdfb-setting-group">
            <label className="pdfb-setting-label" htmlFor="preview-order-id">
              Numéro de commande WooCommerce{" "}
              <span style={{ fontSize: "12px", color: "#e11d48" }}>*</span>
            </label>
            {isLoadingOrders ? (
              <div style={{ padding: "8px 12px", border: "1px solid #d1d5db", borderRadius: "4px", backgroundColor: "#f9fafb", color: "#6b7280", fontSize: "14px" }}>
                ⏳ Chargement des commandes...
              </div>
            ) : (
              <select id="preview-order-id" value={previewOrderId} onChange={(e) => setPreviewOrderId(e.target.value)}
                className="pdfb-setting-input" disabled={isGeneratingPreview}
                style={{ cursor: isGeneratingPreview ? "not-allowed" : "pointer" }}>
                <option value="">{availableOrders.length === 0 ? "Aucune commande trouvée" : "Sélectionnez une commande"}</option>
                {availableOrders.map((order) => (
                  <option key={order.id} value={order.id}>
                    #{order.number} - {order.customer} ({order.date}) - {order.total}
                  </option>
                ))}
              </select>
            )}
            <div className="pdfb-setting-hint">
              Sélectionnez la commande WooCommerce pour générer le document avec les vraies données (client, produits, totaux, etc.)
            </div>
            {!hasTemplateId && (
              <div style={{ marginTop: "8px", padding: "10px 12px", backgroundColor: "#fef3c7", border: "1px solid #f59e0b", borderRadius: "6px", color: "#92400e", fontSize: "13px", display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={{ fontSize: "16px" }}>⚠️</span>
                <span>Enregistrez d&apos;abord le template avant de générer un document.</span>
              </div>
            )}
          </div>
          <div className="pdfb-setting-group" style={{ marginTop: "24px" }}>
            <div className="pdfb-setting-label">Format de sortie</div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "12px" }}>
              <button onClick={generatePDF} disabled={pdfNotAvailable}
                style={{ padding: "12px 16px", border: "2px solid #2271b1", borderRadius: "6px", backgroundColor: "#2271b1", color: "white", fontSize: "14px", fontWeight: "600", cursor: pdfNotAvailable ? "not-allowed" : "pointer", opacity: pdfNotAvailable ? 0.5 : 1, transition: "all 0.2s", display: "flex", flexDirection: "column", alignItems: "center", gap: "4px" }}>
                <span style={{ fontSize: "24px" }}>📄</span><span>PDF</span>
              </button>
            </div>
          </div>
          {isGeneratingPreview && (
            <div style={{ marginTop: "16px", padding: "16px", backgroundColor: countdown !== null ? "#f0fdf4" : "#dbeafe", borderRadius: "6px", textAlign: "center", color: countdown !== null ? "#166534" : "#1e40af", fontSize: "14px" }}>
              {countdown !== null ? (
                <>
                  {/*
                    * TODO: Remplacer ce bloc par un slider publicitaire Threeaxe.
                    * Afficher 3-4 slides pendant le compte à rebours de 10 secondes :
                    * chaque slide = image du plugin + titre + description courte + bouton CTA.
                    * Le PDF s'ouvre automatiquement à la fin du compte à rebours.
                    */}
                  <div style={{ marginBottom: "8px", fontSize: "15px" }}>🚀 Votre PDF est en cours de préparation…</div>
                  <div style={{ fontSize: "52px", fontWeight: "700", lineHeight: "1", margin: "8px 0" }}>{countdown}</div>
                  <div style={{ fontSize: "12px", opacity: 0.7 }}>secondes</div>
                </>
              ) : (
                <>⏳ Génération en cours…</>
              )}
            </div>
          )}
        </div>
        <div className="pdfb-canvas-modal-footer">
          <button onClick={onClose} className="pdfb-canvas-modal-btn pdfb-canvas-modal-btn-secondary" disabled={isGeneratingPreview && countdown === null}>
            Annuler
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── QueueModal sub-component ────────────────────────────────────────────────
interface QueueModalProps {
  show: boolean;
  queuePosition: number | null;
  queueSize: number | null;
  onCancel: () => void;
}

function QueueModal({ show, queuePosition, queueSize, onCancel }: Readonly<QueueModalProps>) {
  if (!show) return null;

  const displayedPosition = typeof queuePosition === "number" ? queuePosition + 1 : null;
  const progress =
    typeof queuePosition === "number" && typeof queueSize === "number" && queueSize > 1
      ? Math.max(5, Math.round((1 - queuePosition / queueSize) * 100))
      : 80;

  return (
    <div className="pdfb-canvas-modal-overlay" style={{ display: "flex", zIndex: 10001, backgroundColor: "rgba(0, 0, 0, 0.6)" }}>
      <style>{`@keyframes pdfb-queue-spin { to { transform: rotate(360deg); } }`}</style>
      <div style={{ position: "fixed", top: "50%", left: "50%", transform: "translate(-50%, -50%)", background: "#fff", borderRadius: "10px", width: "340px", maxWidth: "95vw", boxShadow: "0 12px 48px rgba(0,0,0,.40)", overflow: "hidden" }}>
        <div style={{ padding: "16px 20px", borderBottom: "1px solid #e0e0e0", background: "linear-gradient(135deg,#667eea,#764ba2)", color: "#fff", borderRadius: "10px 10px 0 0" }}>
          <div style={{ fontSize: "15px", fontWeight: 700, marginBottom: "2px" }}>⏳ Génération du PDF</div>
          <div style={{ fontSize: "12px", opacity: 0.85 }}>Fichier gratuit · File d&apos;attente active</div>
        </div>
        <div style={{ padding: "24px 20px", textAlign: "center" }}>
          <div style={{ marginBottom: "18px", display: "flex", justifyContent: "center" }}>
            <div style={{ width: "56px", height: "56px", borderRadius: "50%", border: "6px solid #e9ecef", borderTopColor: "#667eea", animation: "pdfb-queue-spin 1.2s linear infinite" }} />
          </div>
          <div style={{ fontSize: "28px", fontWeight: 800, color: "#667eea", lineHeight: 1, marginBottom: "6px" }}>
            #{displayedPosition !== null ? displayedPosition : "…"}
          </div>
          <div style={{ fontSize: "13px", color: "#6c757d", marginBottom: "16px" }}>dans la file d&apos;attente</div>
          <div style={{ background: "#e9ecef", borderRadius: "6px", height: "8px", overflow: "hidden", marginBottom: "14px" }}>
            <div style={{ height: "100%", background: "linear-gradient(90deg,#667eea,#764ba2)", width: `${progress}%`, transition: "width 0.5s ease", borderRadius: "6px" }} />
          </div>
          <div style={{ fontSize: "12px", color: "#868e96" }}>Patience, votre PDF sera généré automatiquement…</div>
        </div>
        <div style={{ padding: "12px 20px", borderTop: "1px solid #e0e0e0", textAlign: "center" }}>
          <button type="button" className="button button-secondary" onClick={onCancel} style={{ fontSize: "12px" }}>
            Annuler
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── JsonModal sub-component ─────────────────────────────────────────────────
interface JsonModalProps {
  show: boolean;
  onClose: () => void;
  jsonModalMode: "json" | "html";
  setJsonModalMode: React.Dispatch<React.SetStateAction<"json" | "html">>;
  modalPosition: { x: number; y: number };
  isDraggingModal: boolean;
  setIsDraggingModal: React.Dispatch<React.SetStateAction<boolean>>;
  setDragStart: React.Dispatch<React.SetStateAction<{ x: number; y: number } | null>>;
  state: ReturnType<typeof useBuilder>["state"];
  copySuccess: boolean;
  setCopySuccess: React.Dispatch<React.SetStateAction<boolean>>;
  isGeneratingHtml: boolean;
  generatedHtml: string;
  handleShowHtmlPreview: () => void;
  templateName: string;
}
function JsonModal({ // NOSONAR
  show, onClose, jsonModalMode, setJsonModalMode, modalPosition, isDraggingModal,
  setIsDraggingModal, setDragStart, state, copySuccess, setCopySuccess,
  isGeneratingHtml, generatedHtml, handleShowHtmlPreview, templateName,
}: Readonly<JsonModalProps>) {
  if (!show) return null;
  const isJsonMode = jsonModalMode === "json";
  return (
    <div style={{ position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0, 0, 0, 0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1001 }}>
      <div style={{ backgroundColor: "#ffffff", borderRadius: "8px", padding: "24px", maxWidth: "65vw", width: "100%", height: "87vh", display: "flex", flexDirection: "column", boxShadow: "0 10px 40px rgba(0, 0, 0, 0.3)", position: "fixed", top: "50%", left: "50%", transform: `translate(calc(-50% + ${modalPosition.x}px), calc(-50% + ${modalPosition.y}px))`, transition: isDraggingModal ? "none" : "transform 0.1s ease-out" }}>
        <div role="none"
          onMouseDown={(e) => {
            if ((e.target as HTMLElement).closest("button")) return;
            setIsDraggingModal(true);
            setDragStart({ x: e.clientX, y: e.clientY });
          }}
          style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "16px", borderBottom: "1px solid #e0e0e0", paddingBottom: "12px", cursor: isDraggingModal ? "grabbing" : "grab", userSelect: "none" }}>
          <div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
            <h3 style={{ margin: 0, fontSize: "18px", fontWeight: "600", color: "#1a1a1a" }}>
              {isJsonMode ? "📋" : "🎨"} {isJsonMode ? "JSON" : "Aperçu HTML"}
            </h3>
            <div style={{ display: "flex", gap: "6px", borderRadius: "4px", border: "1px solid #ddd", padding: "3px" }}>
              <button onClick={() => setJsonModalMode("json")}
                style={{ padding: "6px 12px", border: "none", borderRadius: "3px", backgroundColor: isJsonMode ? "#007cba" : "#f0f0f0", color: isJsonMode ? "#fff" : "#333", cursor: "pointer", fontSize: "12px", fontWeight: isJsonMode ? "bold" : "normal" }}
                title="Afficher le JSON">JSON</button>
              <button onClick={handleShowHtmlPreview} disabled={isGeneratingHtml}
                style={{ padding: "6px 12px", border: "none", borderRadius: "3px", backgroundColor: isJsonMode ? "#f0f0f0" : "#10a37f", color: isJsonMode ? "#333" : "#fff", cursor: isGeneratingHtml ? "not-allowed" : "pointer", fontSize: "12px", fontWeight: isJsonMode ? "normal" : "bold", opacity: isGeneratingHtml ? 0.6 : 1 }}
                title="Afficher l'aperçu HTML">{isGeneratingHtml ? "⏳" : "🎨"} HTML</button>
            </div>
          </div>
          <button onClick={onClose} style={{ background: "none", border: "none", fontSize: "24px", cursor: "pointer", color: "#666", padding: "4px" }} title="Fermer">×</button>
        </div>
        <div style={{ flex: 1, overflow: "auto", display: "flex", flexDirection: "column" }}>
          {isJsonMode ? (
            <pre style={{ margin: 0, padding: "16px", fontFamily: "monospace", whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: "12px" }}>
              {JSON.stringify({ ...state.template, elements: state.elements }, null, 2)}
            </pre>
          ) : (
            <iframe srcDoc={generatedHtml} style={{ width: "100%", height: "100%", flex: 1, border: "none", borderRadius: "4px", backgroundColor: "#f5f5f5" }} title="Aperçu PDF" />
          )}
        </div>
        <div style={{ display: "flex", gap: "12px", justifyContent: "flex-start", alignItems: "center", flexWrap: "wrap" }}>
          <button
            onClick={() => {
              navigator.clipboard.writeText(JSON.stringify({ ...state.template, elements: state.elements }, null, 2));
              setCopySuccess(true);
              setTimeout(() => setCopySuccess(false), 2000);
            }}
            style={{ padding: "10px 16px", backgroundColor: copySuccess ? "#28a745" : "#0073aa", color: "#ffffff", border: "none", borderRadius: "6px", cursor: "pointer", fontSize: "14px", fontWeight: "500", display: "flex", alignItems: "center", gap: "6px", transition: "background-color 0.2s ease" }}>
            {copySuccess ? <><span>✅</span><span>Copié!</span></> : <><span>📋</span><span>Copier JSON</span></>}
          </button>
          <button
            onClick={() => {
              const jsonString = JSON.stringify({ ...state.template, elements: state.elements }, null, 2);
              const blob = new Blob([jsonString], { type: "application/json" });
              const url = URL.createObjectURL(blob);
              const link = document.createElement("a");
              link.href = url;
              link.download = `template-${templateName || "export"}-${Date.now()}.json`;
              link.click();
              URL.revokeObjectURL(url);
            }}
            style={{ padding: "10px 16px", backgroundColor: "#666", color: "#ffffff", border: "none", borderRadius: "6px", cursor: "pointer", fontSize: "14px", fontWeight: "500", display: "flex", alignItems: "center", gap: "6px" }}>
            <span>📥</span><span>Télécharger</span>
          </button>
          <button onClick={onClose}
            style={{ marginLeft: "auto", padding: "10px 16px", backgroundColor: "#f0f0f0", color: "#333", border: "1px solid #ddd", borderRadius: "6px", cursor: "pointer", fontSize: "14px", fontWeight: "500" }}>
            Fermer
          </button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────

function HeaderFn({ // NOSONAR
  templateName,
  templateDescription,
  canvasWidth,
  canvasHeight,
  showGuides,
  snapToGrid,
  isNewTemplate,
  isModified,
  isSaving,
  isLoading,
  isEditingExistingTemplate,
  onSave,
  onPreview: _onPreview,
  onNewTemplate,
  onUpdateTemplateSettings,
}: Readonly<HeaderProps>) {
  // Use deferred values for frequently changing props to prevent cascading re-renders
  const deferredIsModified = useDeferredValue(isModified);
  const deferredIsSaving = useDeferredValue(isSaving);
  const deferredIsLoading = useDeferredValue(isLoading);
  const deferredIsEditingExistingTemplate = useDeferredValue(
    isEditingExistingTemplate,
  );

  // Debug logging
  useEffect(() => {}, []);

  const { state } = useBuilder();
  const canvasSettings = useCanvasSettings();
  const [hoveredButton, setHoveredButton] = useState<string | null>(null);
  const [showSettingsModal, setShowSettingsModal] = useState(false);
  const [showJsonModal, setShowJsonModal] = useState(false);
  const [jsonModalMode, setJsonModalMode] = useState<"json" | "html">("json");
  const [copySuccess, setCopySuccess] = useState(false);
  const { isHeaderFixed } = useHeaderScroll();
  const [editedTemplateName, setEditedTemplateName] = useState(templateName);
  const [editedTemplateDescription, setEditedTemplateDescription] =
    useState(templateDescription);

  const [editedCanvasWidth, setEditedCanvasWidth] = useState(canvasWidth);
  const [editedCanvasHeight, setEditedCanvasHeight] = useState(canvasHeight);
  const [_canvasOrientation, _setCanvasOrientation] = useState<
    "portrait" | "landscape"
  >(canvasWidth < canvasHeight ? "portrait" : "landscape");
  const [showPredefinedTemplates, setShowPredefinedTemplates] = useState(false);
  useOrientationPermissions();

  const {
    isPremium,
    canCreateNewTemplate,
    canUsePredefinedTemplates,
  } = getEditorFeatureFlags();
  const {
    showPreviewModal, setShowPreviewModal, previewOrderId, setPreviewOrderId,
    isGeneratingPreview, availableOrders, isLoadingOrders, activeEngine,
    handlePreview, openDebugHTML, generatePDF, countdown, queuePosition, queueSize,
    isInQueuePhase, cancelQueuedPreview,
  } = usePreviewActions(isPremium);

  const handleClosePreviewModal = () => {
    if (isGeneratingPreview) {
      cancelQueuedPreview();
    }
    setShowPreviewModal(false);
  };

  const { performanceMetrics } = usePerformanceMetrics(canvasSettings.performanceMonitoring);
  const { modalPosition, isDraggingModal, setIsDraggingModal, setDragStart } = useModalDrag(jsonModalMode, showJsonModal);

  const buttonBaseStyles = {
    padding: "10px 16px",
    border: "none",
    borderRadius: "6px",
    cursor: "pointer",
    fontSize: "14px",
    fontWeight: "500",
    display: "flex",
    alignItems: "center",
    gap: "6px",
    whiteSpace: "nowrap" as const,
  };

  const primaryButtonStyles = {
    ...buttonBaseStyles,
    backgroundColor: "#4CAF50",
    color: "#fff",
    boxShadow: hoveredButton === "save" ? "0 4px 12px rgba(76, 175, 80, 0.3)" : "none",
  };

  const isSecondaryHovered = ["preview-image", "preview-pdf", "new"].includes(hoveredButton ?? "");
  const secondaryButtonStyles = {
    ...buttonBaseStyles,
    backgroundColor: "#fff",
    border: "1px solid #ddd",
    color: "#333",
    boxShadow: isSecondaryHovered ? "0 2px 8px rgba(0, 0, 0, 0.1)" : "none",
  };

  const { isGeneratingHtml, generatedHtml, handleShowHtmlPreview } = useHtmlPreview(state, setJsonModalMode);

  const {
    saveButtonTitle, saveButtonLabel, saveButtonIcon,
    templateStatusText, newButtonOpacity,
  } = computeHeaderButtonState({
    deferredIsLoading, deferredIsModified, deferredIsSaving,
    deferredIsEditingExistingTemplate, isSaving, isPremium,
    previewOrderId,
  });

  const isSaveDisabled = deferredIsSaving || !deferredIsModified || deferredIsLoading;

  const handleNewTemplate = useCallback(() => {
    if (!canCreateNewTemplate) {
      return;
    }

    if (globalThis.confirm("Créer un nouveau template ? Les modifications non sauvegardées seront perdues.")) {
      onNewTemplate();
    }
  }, [canCreateNewTemplate, onNewTemplate]);

  const handleSave = useHeaderSave({
    templateName, deferredIsModified, deferredIsSaving, deferredIsLoading,
    canvasWidth, canvasHeight, showGuides, snapToGrid, state, canvasSettings, onSave,
  });
  // handleSave_placeholder_remove_old_usecallback

  return (
    <div style={buildHeaderContainerStyle(isHeaderFixed)}>
      {/* Left Section - Title and Status */}
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: "12px",
          minWidth: 0,
          flex: 1,
        }}
      >
        <div
          style={{
            display: "flex",
            alignItems: "baseline",
            gap: "12px",
            minWidth: 0,
          }}
        >
          <h2
            style={{
              margin: 0,
              fontSize: "20px",
              fontWeight: "600",
              color: "#1a1a1a",
              overflow: "hidden",
              textOverflow: "ellipsis",
              whiteSpace: "nowrap",
            }}
          >
            {templateName || "Sans titre"}
          </h2>

          {/* Status Badges */}
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: "8px",
              flexShrink: 0,
            }}
          >
            {deferredIsModified && (
              <span
                style={{
                  fontSize: "12px",
                  padding: "4px 10px",
                  backgroundColor: "#fff3cd",
                  color: "#856404",
                  borderRadius: "4px",
                  fontWeight: "500",
                  border: "1px solid #ffeaa7",
                  display: "flex",
                  alignItems: "center",
                  gap: "4px",
                }}
              >
                <span style={{ fontSize: "16px" }}>●</span>
                {" "}Modifié
              </span>
            )}
            {isNewTemplate && (
              <span
                style={{
                  fontSize: "12px",
                  padding: "4px 10px",
                  backgroundColor: "#d1ecf1",
                  color: "#0c5460",
                  borderRadius: "4px",
                  fontWeight: "500",
                  border: "1px solid #bee5eb",
                }}
              >
                Nouveau
              </span>
            )}
          </div>
        </div>
      </div>

      {/* Right Section - Action Buttons */}
      <div
        style={{
          display: "flex",
          gap: "10px",
          flexShrink: 0,
          alignItems: "center",
        }}
      >
        {canCreateNewTemplate && (
          <button
            onClick={handleNewTemplate}
            onMouseEnter={() => setHoveredButton("new")}
            onMouseLeave={() => setHoveredButton(null)}
            style={{
              ...secondaryButtonStyles,
              opacity: isSaving ? 0.6 : 1,
              pointerEvents: isSaving ? "none" : "auto",
            }}
            title="Créer un nouveau template"
          >
            <span>➕</span>
            <span>Nouveau</span>
          </button>
        )}

        {canUsePredefinedTemplates && (
          <div style={{ position: "relative" }} data-predefined-dropdown>
            <button
              onClick={() => setShowPredefinedTemplates(!showPredefinedTemplates)}
              onMouseEnter={() => setHoveredButton("predefined")}
              onMouseLeave={() => setHoveredButton(null)}
              style={{
                ...secondaryButtonStyles,
                opacity: isSaving ? 0.6 : 1,
                pointerEvents: isSaving ? "none" : "auto",
              }}
              title="Modèles prédéfinis"
            >
              <span>🎨</span>
              <span>Modèles Prédéfinis</span>
              <span style={{ marginLeft: "4px", fontSize: "12px" }}>▼</span>
            </button>

            {showPredefinedTemplates && (
              <div
                style={{
                  position: "absolute",
                  top: "100%",
                  right: 0,
                  background: "white",
                  border: "1px solid #e0e0e0",
                  borderRadius: "8px",
                  boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
                  zIndex: 1001,
                  minWidth: "280px",
                  maxHeight: "400px",
                  overflowY: "auto",
                }}
              >
                <div
                  style={{
                    padding: "12px 16px",
                    borderBottom: "1px solid #e0e0e0",
                    background: "#f8f9fa",
                    fontWeight: "600",
                    fontSize: "14px",
                    color: "#23282d",
                  }}
                >
                  🎨 Modèles Prédéfinis
                </div>

              {/* Liste des modèles prédéfinis */}
              <div style={{ padding: "8px 0" }}>
                <button
                  type="button"
                  style={{
                    padding: "12px 16px",
                    cursor: "pointer",
                    borderBottom: "1px solid #f0f0f0",
                    display: "flex",
                    alignItems: "center",
                    gap: "12px",
                    width: "100%",
                    background: "none",
                    border: "none",
                    textAlign: "left",
                  }}
                  onClick={() => {
                    // Ouvrir la page des templates prédéfinis
                    globalThis.open("/wp-admin/admin.php?page=pdf-builder-templates", "_blank");
                    setShowPredefinedTemplates(false);
                  }}
                  onMouseEnter={(e) =>
                    (e.currentTarget.style.backgroundColor = "#f8f9fa")
                  }
                  onMouseLeave={(e) =>
                    (e.currentTarget.style.backgroundColor = "transparent")
                  }
                >
                  <span style={{ fontSize: "20px" }}>🧾</span>
                  <div>
                    <div style={{ fontWeight: "500", color: "#23282d" }}>
                      Facture Professionnelle
                    </div>
                    <div style={{ fontSize: "12px", color: "#666" }}>
                      Template professionnel pour factures
                    </div>
                  </div>
                </button>

                <button
                  type="button"
                  style={{
                    padding: "12px 16px",
                    cursor: "pointer",
                    borderBottom: "1px solid #f0f0f0",
                    display: "flex",
                    alignItems: "center",
                    gap: "12px",
                    width: "100%",
                    background: "none",
                    border: "none",
                    textAlign: "left",
                  }}
                  onClick={() => {
                    // Ouvrir la page des templates prédéfinis
                    globalThis.open("/wp-admin/admin.php?page=pdf-builder-templates", "_blank");
                    setShowPredefinedTemplates(false);
                  }}
                  onMouseEnter={(e) =>
                    (e.currentTarget.style.backgroundColor = "#f8f9fa")
                  }
                  onMouseLeave={(e) =>
                    (e.currentTarget.style.backgroundColor = "transparent")
                  }
                >
                  <span style={{ fontSize: "20px" }}>📋</span>
                  <div>
                    <div style={{ fontWeight: "500", color: "#23282d" }}>
                      Devis Commercial
                    </div>
                    <div style={{ fontSize: "12px", color: "#666" }}>
                      Template professionnel pour devis
                    </div>
                  </div>
                </button>

                <button
                  type="button"
                  style={{
                    padding: "12px 16px",
                    cursor: "pointer",
                    borderBottom: "1px solid #f0f0f0",
                    display: "flex",
                    alignItems: "center",
                    gap: "12px",
                    width: "100%",
                    background: "none",
                    border: "none",
                    textAlign: "left",
                  }}
                  onClick={() => {
                    // Ouvrir la page des templates prédéfinis
                    globalThis.open("/wp-admin/admin.php?page=pdf-builder-templates", "_blank");
                    setShowPredefinedTemplates(false);
                  }}
                  onMouseEnter={(e) =>
                    (e.currentTarget.style.backgroundColor = "#f8f9fa")
                  }
                  onMouseLeave={(e) =>
                    (e.currentTarget.style.backgroundColor = "transparent")
                  }
                >
                  <span style={{ fontSize: "20px" }}>📦</span>
                  <div>
                    <div style={{ fontWeight: "500", color: "#23282d" }}>
                      Bon de Commande
                    </div>
                    <div style={{ fontSize: "12px", color: "#666" }}>
                      Template professionnel pour commandes
                    </div>
                  </div>
                </button>

                <button
                  type="button"
                  style={{
                    padding: "12px 16px",
                    cursor: "pointer",
                    display: "flex",
                    alignItems: "center",
                    gap: "12px",
                    color: "#007cba",
                    fontWeight: "500",
                    width: "100%",
                    background: "none",
                    border: "none",
                    textAlign: "left",
                  }}
                  onClick={() => {
                    // Ouvrir la page des templates prédéfinis
                    globalThis.open("/wp-admin/admin.php?page=pdf-builder-templates", "_blank");
                    setShowPredefinedTemplates(false);
                  }}
                  onMouseEnter={(e) =>
                    (e.currentTarget.style.backgroundColor = "#f8f9fa")
                  }
                  onMouseLeave={(e) =>
                    (e.currentTarget.style.backgroundColor = "transparent")
                  }
                >
                  <span style={{ fontSize: "16px" }}>📚</span>
                  <span>Voir tous les modèles...</span>
                </button>
              </div>
            </div>
          )}
          </div>
        )}

        <button
          onClick={handlePreview}
          onMouseEnter={() => setHoveredButton("preview")}
          onMouseLeave={() => setHoveredButton(null)}
          style={{
            ...secondaryButtonStyles,
            opacity: isSaving ? 0.6 : 1,
            pointerEvents: isSaving ? "none" : "auto",
          }}
          title="Générer un aperçu PDF/PNG/JPG avec une commande réelle"
        >
          <span>👁️</span>
          <span>Aperçu</span>
        </button>

        <button
          onClick={() => setShowSettingsModal(true)}
          onMouseEnter={() => setHoveredButton("settings")}
          onMouseLeave={() => setHoveredButton(null)}
          style={{
            ...secondaryButtonStyles,
            opacity: isSaving ? 0.6 : 1,
            pointerEvents: isSaving ? "none" : "auto",
          }}
          title="Paramètres du template"
        >
          <span>⚙️</span>
          <span>Paramètres</span>
        </button>

        <button
          onClick={handleSave}
          disabled={isSaveDisabled}
          onMouseEnter={() => setHoveredButton("save")}
          onMouseLeave={() => setHoveredButton(null)}
          style={{
            ...primaryButtonStyles,
            opacity: isSaveDisabled ? 0.6 : 1,
            pointerEvents: isSaveDisabled ? "none" : "auto",
          }}
          title={saveButtonTitle}
        >
          <span>{saveButtonIcon}</span>
          <span>{saveButtonLabel}</span>
        </button>
      </div>

      <SettingsModal
        show={showSettingsModal}
        onClose={() => setShowSettingsModal(false)}
        originalTemplateName={templateName}
        editedTemplateName={editedTemplateName}
        setEditedTemplateName={setEditedTemplateName}
        editedTemplateDescription={editedTemplateDescription}
        setEditedTemplateDescription={setEditedTemplateDescription}
        editedCanvasWidth={editedCanvasWidth}
        editedCanvasHeight={editedCanvasHeight}
        isNewTemplate={isNewTemplate}
        deferredIsModified={deferredIsModified}
        isEditingExistingTemplate={isEditingExistingTemplate}
        templateStatusText={templateStatusText}
        canvasSettings={canvasSettings}
        performanceMetrics={performanceMetrics}
        showGuides={showGuides}
        snapToGrid={snapToGrid}
        onSaveSettings={(settings) => {
          onUpdateTemplateSettings(settings);
          setShowSettingsModal(false);
        }}
      />

      {/* Modale d'apercu avec selection de format */}
      <PreviewModal
        show={showPreviewModal}
        onClose={handleClosePreviewModal}
        previewOrderId={previewOrderId}
        setPreviewOrderId={setPreviewOrderId}
        isGeneratingPreview={isGeneratingPreview}
        availableOrders={availableOrders}
        isLoadingOrders={isLoadingOrders}
        activeEngine={activeEngine}
        generatePDF={generatePDF}
        openDebugHTML={openDebugHTML}
        isPremium={isPremium}
        hasTemplateId={!!state.template?.id}
        countdown={countdown}
      />

      <QueueModal
        show={isInQueuePhase}
        queuePosition={queuePosition}
        queueSize={queueSize}
        onCancel={cancelQueuedPreview}
      />

      {/* Modale JSON brut du template */}
      <JsonModal
        show={showJsonModal}
        onClose={() => setShowJsonModal(false)}
        jsonModalMode={jsonModalMode}
        setJsonModalMode={setJsonModalMode}
        modalPosition={modalPosition}
        isDraggingModal={isDraggingModal}
        setIsDraggingModal={setIsDraggingModal}
        setDragStart={setDragStart}
        state={state}
        copySuccess={copySuccess}
        setCopySuccess={setCopySuccess}
        isGeneratingHtml={isGeneratingHtml}
        generatedHtml={generatedHtml}
        handleShowHtmlPreview={handleShowHtmlPreview}
        templateName={templateName}
      />

    </div>
  );
}
export const Header = memo(HeaderFn);