// SEO GUY Web V2 — composants partagés
const { useState, useEffect, useRef } = React;

function Icon({ name, size = 18 }) {
  const paths = {
    home: "M3 10.5 12 3l9 7.5M5 9.5V21h5v-6h4v6h5V9.5",
    docs: "M7 3h7l5 5v13H7zM14 3v5h5M9.5 13h6M9.5 16.5h6",
    chart: "M4 20V4M4 20h16M8 16v-5M12 16V7M16 16v-8",
    gear: "M12 9.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M12 3v2.5M12 18.5V21M5.6 5.6l1.8 1.8M16.6 16.6l1.8 1.8M3 12h2.5M18.5 12H21M5.6 18.4l1.8-1.8M16.6 7.4l1.8-1.8",
    check: "M5 12.5l4.5 4.5L19 7.5",
    bolt: "M13 3 5 13h6l-1 8 8-10h-6z",
    spark: "M12 3v6M12 15v6M3 12h6M15 12h6",
    arrow: "M5 12h14M13 6l6 6-6 6",
    calendar: "M4 6h16v15H4zM4 10h16M8 3v4M16 3v4",
    eye: "M2 12s3.5-6.5 10-6.5S22 12 22 12s-3.5 6.5-10 6.5S2 12 2 12M12 9.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5",
    target: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8M12 11.5a.5.5 0 1 0 0 1 .5.5 0 0 0 0-1",
    mic: "M12 3a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3M5 11v1a7 7 0 0 0 14 0v-1M12 19v3M8.5 22h7",
    users: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75",
    trending: "M3 17l4-8 4 4 4-6 4 4",
    plus: "M12 5v14M5 12h14",
    globe: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18M3 12h18",
    star: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z",
    wand: "M15 4V2M15 16v-2M8 9h2M20 9h2M17.8 11.8 19 13M17.8 6.2 19 5M3 21l9-9M12.2 6.2 11 5",
    card: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 0 0 3-3V8a3 3 0 0 0-3-3H6a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3",
    user: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2M12 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8",
    send: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z",
    menu: "M4 7h16M4 12h16M4 17h16",
    close: "M6 6l12 12M18 6 6 18",
    image: "M4 5h16v14H4zM4 15l4.2-4.2 3 3L16 9.5 20 14.5M9 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3",
  };
  const p = paths[name];
  if (!p) return null;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none"
      stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d={p} />
    </svg>
  );
}

function StatusPill({ children, tone = "live" }) {
  return <span className={`sg-statuspill is-${tone}`}>{tone === "live" && <span className="sg-dot" />}{children}</span>;
}

function Pill({ children, tone }) {
  return <span className={`sg-pill is-${tone}`}>{children}</span>;
}

/** Anneau score SEO : jusqu'à 85 % en bleu, 15 % bonus humanisation en or. */
const SEO_SCORE_HUMAN_NOTE = "Contenu suffisamment humanisé pour performer";
const SEO_SCORE_CAP = 85;
const SEO_SCORE_BONUS = 15;
const SEO_RING_BLUE = "#2563eb";
const SEO_RING_GOLD = "#f5c518";
let __sgRingUid = 0;

function ScoreRing({ value, size = 44 }) {
  const v = Math.min(100, Math.max(0, Number(value) || 0));
  const r = size / 2 - 4;
  const c = 2 * Math.PI * r;
  const cx = size / 2;
  const cy = size / 2;
  const seoPct = Math.min(v, SEO_SCORE_CAP);
  const blueLen = (seoPct / 100) * c;
  const goldLen = (SEO_SCORE_BONUS / 100) * c;
  const goldRotate = -90 + (SEO_SCORE_CAP / 100) * 360;
  const uidRef = React.useRef(null);
  if (!uidRef.current) uidRef.current = `sg-ring-gold-${++__sgRingUid}`;
  const uid = uidRef.current;

  return (
    <div
      className="sg-ring"
      style={{ width: size, height: size }}
      title={SEO_SCORE_HUMAN_NOTE}
    >
      <svg width={size} height={size} aria-hidden="true">
        <defs>
          <linearGradient id={uid} x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" stopColor="#ffe566" />
            <stop offset="45%" stopColor={SEO_RING_GOLD} />
            <stop offset="100%" stopColor="#c9970a" />
          </linearGradient>
        </defs>
        <circle cx={cx} cy={cy} r={r} stroke="#ECECF3" strokeWidth="4" fill="none" />
        {/* Bonus humanisation : derniers 15 % (or brillant) */}
        <circle
          cx={cx}
          cy={cy}
          r={r}
          stroke={`url(#${uid})`}
          strokeWidth="4.5"
          fill="none"
          strokeDasharray={`${goldLen} ${Math.max(c - goldLen, 0)}`}
          strokeDashoffset={0}
          strokeLinecap="round"
          transform={`rotate(${goldRotate} ${cx} ${cy})`}
        />
        {/* Optimisation SEO : jusqu'à 85 % (bleu) */}
        <circle
          cx={cx}
          cy={cy}
          r={r}
          stroke={SEO_RING_BLUE}
          strokeWidth="4"
          fill="none"
          strokeDasharray={`${blueLen} ${Math.max(c - blueLen, 0)}`}
          strokeDashoffset={0}
          strokeLinecap="round"
          transform={`rotate(-90 ${cx} ${cy})`}
        />
      </svg>
      <span className="sg-ring-num">{Math.round(v)}</span>
    </div>
  );
}

function SeoScoreHumanNote({ className = "" }) {
  return (
    <p className={`sg-seo-human-note${className ? ` ${className}` : ""}`}>
      {SEO_SCORE_HUMAN_NOTE}
    </p>
  );
}

const NAV_MAIN = [
  { id: "home", label: "Accueil", icon: "home" },
  { id: "assistants", label: "Assistants Premium", icon: "wand" },
  { id: "performance", label: "Performance", icon: "chart" },
  { id: "articles", label: "Articles", icon: "docs" },
];

const NAV_ADVANCED = [
  { id: "settings", label: "Réglages", icon: "gear" },
  { id: "gsc", label: "Search Console", icon: "globe" },
  { id: "config", label: "Ciblage marketing", icon: "target" },
  { id: "billing", label: "Abonnements", icon: "card" },
];

function Sidebar({ active, onNav, showMascot, onAccount, siteLabel, planLabel, mobileOpen, onClose }) {
  function navigate(id) {
    onNav(id);
    onClose?.();
  }
  return (
    <>
      <div
        className={`sg-side-backdrop${mobileOpen ? " is-open" : ""}`}
        onClick={onClose}
        aria-hidden={!mobileOpen}
      />
      <aside className={`sg-side${mobileOpen ? " is-open" : ""}`} aria-label="Navigation">
        <div className="sg-brand">
          <span className="sg-brand-mark">S</span>
          <span className="sg-brand-type">SEO<b>GUY</b></span>
          <button type="button" className="sg-side-close" onClick={onClose} aria-label="Fermer le menu">
            <Icon name="close" size={20} />
          </button>
        </div>
        <nav className="sg-nav">
          {NAV_MAIN.map((n) => (
            <button key={n.id} type="button" className={`sg-nav-item${active === n.id ? " is-active" : ""}`} onClick={() => navigate(n.id)}>
              <Icon name={n.icon} /><span>{n.label}</span>
            </button>
          ))}
          <p className="sg-nav-section">Réglages avancés</p>
          {NAV_ADVANCED.map((n) => (
            <button key={n.id} type="button" className={`sg-nav-item sg-nav-item--sub${active === n.id ? " is-active" : ""}`} onClick={() => navigate(n.id)}>
              <Icon name={n.icon} size={16} /><span>{n.label}</span>
            </button>
          ))}
          <button type="button" className={`sg-nav-item sg-nav-item--sub${active === "account" ? " is-active" : ""}`} onClick={() => navigate("account")}>
            <Icon name="user" size={16} /><span>Mon compte</span>
          </button>
        </nav>
        {showMascot && (
          <div className="sg-side-coach">
            <img src={POSE.avatar} alt="SEO GUY" />
            <p><b>SEO GUY veille pour vous.</b> Pilotez votre SEO sans la complexité technique.</p>
          </div>
        )}
        <div className="sg-side-shop">
          <button type="button" className="sg-side-shop-row sg-side-shop-btn" onClick={() => { onAccount(); onClose?.(); }}>
            <span className="sg-shop-logo">G</span>
            <div>
              <div className="sg-shop-name">{siteLabel || "Ma boutique"}</div>
              <span className="sg-plan">{planLabel ? `Plan ${planLabel}` : "SEO GUY"}</span>
            </div>
          </button>
        </div>
      </aside>
    </>
  );
}

function MobileTopBar({ onMenu, title }) {
  return (
    <header className="sg-mobile-bar">
      <button type="button" className="sg-mobile-menu-btn" onClick={onMenu} aria-label="Ouvrir le menu">
        <Icon name="menu" size={22} />
      </button>
      <div className="sg-mobile-brand">
        <span className="sg-brand-mark sm">S</span>
        <span className="sg-brand-type">SEO<b>GUY</b></span>
      </div>
      {title ? <span className="sg-mobile-title">{title}</span> : <span className="sg-mobile-title" />}
    </header>
  );
}

function PageHeader({ greeting, title, sub, status, actions }) {
  return (
    <header className="sg-pagehead">
      <div>
        {greeting && <p className="sg-greeting">{greeting}</p>}
        <h1 className="sg-h1">{title}</h1>
        {sub && <p className="sg-sub">{sub}</p>}
      </div>
      <div className="sg-pagehead-aside">
        {status && <StatusPill>{status}</StatusPill>}
        {actions}
      </div>
    </header>
  );
}

function HeroBand({ guyImage, eyebrow, title, tip, pills, actions, showMascot }) {
  if (!showMascot) return null;
  return (
    <section className="sg-hero-band">
      <div className="sg-hero-copy">
        {eyebrow && <p className="sg-hero-eyebrow">{eyebrow}</p>}
        {title && <h2 className="sg-hero-title">{title}</h2>}
        {tip && <p className="sg-hero-tip">{tip}</p>}
        {pills?.length > 0 && (
          <div className="sg-hero-pills">
            {pills.map((p) => <span key={p} className="sg-hero-pill">{p}</span>)}
          </div>
        )}
        {actions && <div className="sg-hero-actions">{actions}</div>}
      </div>
      <div className="sg-hero-guy">
        <img src={guyImage || POSE.working} alt="SEO GUY" className="sg-hero-guy-img" />
      </div>
    </section>
  );
}

function AlertList({ alerts, onNav }) {
  if (!alerts?.length) return null;
  return (
    <div className="sg-alerts">
      {alerts.map((a) => (
        <button key={a.title} type="button" className={`sg-alert is-${a.tone}`} onClick={() => onNav(a.to)}>
          <strong>{a.title}</strong>
          <Icon name="arrow" size={14} />
        </button>
      ))}
    </div>
  );
}

function KpiCard({ icon, label, value, delta, up }) {
  const isEmoji = typeof icon === "string" && icon.length <= 4;
  return (
    <div className="sg-kpi">
      <div className="sg-kpi-top">
        <span className="sg-kpi-icon">
          {isEmoji ? <span className="sg-kpi-emoji">{icon}</span> : <img src={icon} alt="" />}
        </span>
        <span className={`sg-kpi-delta${up ? "" : " is-down"}`}>{delta}</span>
      </div>
      <p className="sg-kpi-label">{label}</p>
      <p className="sg-kpi-value">{value}</p>
    </div>
  );
}

/** Éditeur HTML léger (contentEditable) — conserve le balisage. */
function HtmlEditor({ value, onChange, disabled }) {
  const ref = useRef(null);
  const skipSync = useRef(false);
  const ready = useRef(false);

  useEffect(() => {
    if (!ref.current) return;
    if (!ready.current) {
      ref.current.innerHTML = value || "";
      ready.current = true;
      return;
    }
    if (skipSync.current) {
      skipSync.current = false;
      return;
    }
    if (document.activeElement === ref.current) return;
    const next = value || "";
    if (ref.current.innerHTML !== next) ref.current.innerHTML = next;
  }, [value]);

  function emit() {
    if (!ref.current) return;
    skipSync.current = true;
    onChange?.(ref.current.innerHTML);
  }

  function run(cmd, arg) {
    if (disabled) return;
    ref.current?.focus();
    try {
      document.execCommand(cmd, false, arg);
    } catch {
      /* ignore */
    }
    emit();
  }

  function setBlock(tag) {
    // execCommand attend souvent la forme <h2>, etc.
    run("formatBlock", `<${tag}>`);
  }

  function addLink() {
    const url = window.prompt("URL du lien :", "https://");
    if (!url) return;
    run("createLink", url);
  }

  // Titre 1 = H2, Titre 2 = H3, Titre 3 = H4 (H1 réservé au titre de l'article)
  const tools = [
    { label: "Titre 1", title: "Titre 1 (H2)", onClick: () => setBlock("h2") },
    { label: "Titre 2", title: "Titre 2 (H3)", onClick: () => setBlock("h3") },
    { label: "Titre 3", title: "Titre 3 (H4)", onClick: () => setBlock("h4") },
    { label: "¶", title: "Paragraphe", onClick: () => setBlock("p") },
    { label: "« »", title: "Citation", onClick: () => setBlock("blockquote") },
    { sep: true },
    { label: "B", title: "Gras", className: "is-bold", onClick: () => run("bold") },
    { label: "I", title: "Italique", className: "is-italic", onClick: () => run("italic") },
    { label: "S", title: "Souligné", className: "is-underline", onClick: () => run("underline") },
    { sep: true },
    { label: "A−", title: "Réduire", onClick: () => run("fontSize", "2") },
    { label: "A+", title: "Agrandir", onClick: () => run("fontSize", "5") },
    { label: "🔗", title: "Lien", onClick: addLink },
    { label: "• Liste", title: "Liste à puces", onClick: () => run("insertUnorderedList") },
  ];

  return (
    <div className={`sg-html-editor${disabled ? " is-disabled" : ""}`}>
      <div className="sg-html-toolbar" role="toolbar" aria-label="Formatage">
        {tools.map((t, i) =>
          t.sep ? (
            <span key={`sep-${i}`} className="sg-html-toolbar-sep" aria-hidden="true" />
          ) : (
            <button
              key={t.title}
              type="button"
              className={`sg-html-tool${t.className ? ` ${t.className}` : ""}`}
              title={t.title}
              disabled={disabled}
              onMouseDown={(e) => e.preventDefault()}
              onClick={t.onClick}
            >
              {t.label}
            </button>
          ),
        )}
      </div>
      <div
        ref={ref}
        className="sg-html-surface"
        contentEditable={!disabled}
        suppressContentEditableWarning
        role="textbox"
        aria-multiline="true"
        onInput={emit}
        onBlur={emit}
      />
    </div>
  );
}

const BLOG_COVER_HINT = "Paysage 16:9, idéalement 1600 × 900 px. JPEG, PNG ou WebP, 8 Mo max. Guy recadre au format blog.";
const BLOG_COVER_W = 1600;
const BLOG_COVER_H = 900;
const BLOG_COVER_FILE_MAX = 8 * 1024 * 1024;

async function resizeBlogCoverFile(file) {
  if (!file || !/^image\/(jpeg|jpg|png|webp)$/i.test(file.type)) {
    throw new Error("Formats acceptés : JPEG, PNG ou WebP.");
  }
  if (file.size > BLOG_COVER_FILE_MAX) {
    throw new Error("Image trop lourde (max 8 Mo). Réduisez-la avant l’envoi.");
  }
  const bitmap = await createImageBitmap(file);
  const canvas = document.createElement("canvas");
  canvas.width = BLOG_COVER_W;
  canvas.height = BLOG_COVER_H;
  const ctx = canvas.getContext("2d");
  if (!ctx) {
    bitmap.close();
    throw new Error("Canvas indisponible.");
  }
  const targetRatio = BLOG_COVER_W / BLOG_COVER_H;
  const srcRatio = bitmap.width / bitmap.height;
  let sx = 0;
  let sy = 0;
  let sw = bitmap.width;
  let sh = bitmap.height;
  if (srcRatio > targetRatio) {
    sw = sh * targetRatio;
    sx = (bitmap.width - sw) / 2;
  } else {
    sh = sw / targetRatio;
    sy = (bitmap.height - sh) / 2;
  }
  ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, BLOG_COVER_W, BLOG_COVER_H);
  bitmap.close();
  let quality = 0.82;
  let dataUrl = canvas.toDataURL("image/jpeg", quality);
  while (dataUrl.length > 5_500_000 && quality > 0.5) {
    quality -= 0.08;
    dataUrl = canvas.toDataURL("image/jpeg", quality);
  }
  if (dataUrl.length > 5_500_000) {
    throw new Error("Image trop détaillée après compression. Choisissez un fichier plus léger.");
  }
  return dataUrl;
}

async function resizeProductRefFile(file) {
  if (!file || !/^image\/(jpeg|jpg|png|webp)$/i.test(file.type)) {
    throw new Error("Formats acceptés : JPEG, PNG ou WebP.");
  }
  if (file.size > BLOG_COVER_FILE_MAX) {
    throw new Error("Image trop lourde (max 8 Mo). Réduisez-la avant l’envoi.");
  }
  const bitmap = await createImageBitmap(file);
  const maxEdge = 1600;
  let w = bitmap.width;
  let h = bitmap.height;
  if (w > maxEdge || h > maxEdge) {
    const scale = maxEdge / Math.max(w, h);
    w = Math.round(w * scale);
    h = Math.round(h * scale);
  }
  const canvas = document.createElement("canvas");
  canvas.width = w;
  canvas.height = h;
  const ctx = canvas.getContext("2d");
  if (!ctx) {
    bitmap.close();
    throw new Error("Canvas indisponible.");
  }
  ctx.drawImage(bitmap, 0, 0, w, h);
  bitmap.close();
  let quality = 0.82;
  let dataUrl = canvas.toDataURL("image/jpeg", quality);
  while (dataUrl.length > 5_500_000 && quality > 0.5) {
    quality -= 0.08;
    dataUrl = canvas.toDataURL("image/jpeg", quality);
  }
  if (dataUrl.length > 5_500_000) {
    throw new Error("Image trop détaillée après compression. Choisissez un fichier plus léger.");
  }
  return dataUrl;
}

Object.assign(window, {
  Icon, StatusPill, Pill, ScoreRing, SeoScoreHumanNote, SEO_SCORE_HUMAN_NOTE, Sidebar, MobileTopBar, PageHeader, HeroBand, AlertList, KpiCard,
  HtmlEditor,
  NAV_MAIN, NAV_ADVANCED,
  resizeBlogCoverFile, BLOG_COVER_HINT,
  resizeProductRefFile,
});
