// SEO GUY Web V2 — écrans étendus (couverture inventaire complet)
const { useState: useS, useEffect: useE, useRef: useR } = React;

function Sparkline({ data, w = 720, h = 220 }) {
  const series = Array.isArray(data) ? data.filter((v) => Number.isFinite(v)) : [];
  if (series.length === 0) return null;
  const max = Math.max(...series, 1);
  const pts = series.map((v, i) => {
    const x = series.length === 1 ? w / 2 : (i / (series.length - 1)) * w;
    const y = h - (v / max) * (h - 24) - 12;
    return `${x},${y}`;
  }).join(" ");
  return (
    <svg className="sg-spark" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      <polyline points={pts} fill="none" stroke="var(--accent)" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function PerformanceScreen({ publishedThisMonth, performance, kpis, traffic }) {
  const [days, setDays] = useS("30");
  const [perfLoading, setPerfLoading] = useS(false);
  const [perfOverride, setPerfOverride] = useS(null);

  useE(() => {
    let cancelled = false;
    setPerfLoading(true);
    GuyAPI.performanceOverall(days)
      .then((body) => {
        if (!cancelled && body?.performance) setPerfOverride(body.performance);
      })
      .catch(() => {
        if (!cancelled) setPerfOverride(null);
      })
      .finally(() => {
        if (!cancelled) setPerfLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [days]);

  const perf = perfOverride || performance?.data || performance;
  const kpiData = kpis && !perfOverride ? kpis : mapKpisFromPerformance(perf);
  const trafficData = traffic && !perfOverride ? traffic : mapTrafficSeries(perf);
  const top = perf?.topArticles ?? [];
  const baseline = perf?.baseline;
  const weekCount = perf?.trafficSeries?.length ?? 0;
  const weeksLabel =
    weekCount === 0
      ? (perf?.gscConnected ? "Aucune donnée" : "GSC non connectée")
      : weekCount === 1
        ? "1 semaine"
        : `${weekCount} semaines`;

  return (
    <div className="sg-screen">
      <div className="sg-toolbar-inline">
        <div className="sg-seg">
          {["7", "30", "90"].map((d) => (
            <button key={d} type="button" className={days === d ? "is-active" : ""} onClick={() => setDays(d)}>{d} jours</button>
          ))}
        </div>
        {perfLoading ? <span className="sg-block-note">Actualisation…</span> : null}
      </div>
      <section className="sg-kpis">
        {kpiData.map((k) => <KpiCard key={k.label} {...k} />)}
      </section>
      <section className="sg-panel">
        <div className="sg-panel-head">
          <h3 className="sg-block-title"><span className="sg-legend-dot" />Évolution du trafic SEO</h3>
          <span className="sg-legend">{weeksLabel}</span>
        </div>
        {trafficData.length > 0 ? (
          <Sparkline data={trafficData} />
        ) : (
          <p className="sg-block-note">
            {perf?.gscConnected
              ? "Pas encore de données sur cette période."
              : "Connectez Google Search Console pour afficher le trafic."}
          </p>
        )}
      </section>
      <section className="sg-compare">
        <div className="sg-compare-head">
          <h3 className="sg-block-title">Impact AVANT / APRÈS SEO GUY</h3>
          <span className="sg-block-note">{publishedThisMonth} articles validés ce mois-ci</span>
        </div>
        <div className="sg-compare-grid">
          <div className="sg-compare-card">
            <p className="sg-compare-lab">Avant install</p>
            <p className="sg-compare-val">
              {baseline?.visitsBefore != null
                ? `${baseline.visitsBefore.toLocaleString("fr-FR")}`
                : "—"}
              <span> visites/mois</span>
            </p>
            <p className="sg-compare-meta">
              {baseline?.visitsBefore != null
                ? "Baseline figée à la connexion GSC"
                : "Baseline en cours de collecte"}
            </p>
          </div>
          <div className="sg-compare-arrow"><Icon name="arrow" size={22} /></div>
          <div className="sg-compare-card is-after">
            <p className="sg-compare-lab">Aujourd'hui</p>
            <p className="sg-compare-val">{baseline?.visitsAfter ?? "—"}<span> visites</span></p>
            <p className="sg-compare-meta">Valeur trafic {perf?.trafficValueEur ? `${perf.trafficValueEur} €` : "estimée"}</p>
          </div>
        </div>
      </section>
      <section className="sg-panel">
        <h3 className="sg-block-title">Top publications performantes</h3>
        {top.length === 0 ? (
          <p className="sg-block-note">
            Publiez des articles et connectez la GSC pour voir les performances.
          </p>
        ) : (
          <div className="sg-top">
            {top.map((a, i) => (
              <div key={a.title || a.articleId} className="sg-top-row">
                <span className="sg-top-rank">{i + 1}</span>
                <div className="sg-top-main">
                  <p className="sg-top-title">{a.title}</p>
                  <p className="sg-top-kw">{a.revenue ? `CA ${a.revenue} €` : ""}</p>
                </div>
                <div className="sg-top-pos"><b>#{a.position ?? a.pos ?? "—"}</b><span>position</span></div>
                <div className="sg-top-vis"><b>{a.visits}</b><span>visites</span></div>
              </div>
            ))}
          </div>
        )}
      </section>
    </div>
  );
}

function AssistantHubCard({ icon, title, pill, description, bullets, ctaLabel, ctaPrimary = true, onClick }) {
  return (
    <article className="sg-assistant-card is-rich">
      <div className="sg-assistant-head">
        <span className="sg-assistant-ic"><Icon name={icon} size={22} /></span>
        {pill ? <span className={`sg-pill is-${pill.tone}`}>{pill.label}</span> : null}
      </div>
      <h3>{title}</h3>
      <p className="sg-assistant-desc">{description}</p>
      <ul className="sg-assistant-bullets">
        {bullets.map((b) => (
          <li key={b}><Icon name="check" size={14} /> <span>{b}</span></li>
        ))}
      </ul>
      <button
        type="button"
        className={`${ctaPrimary ? "sg-btn-primary" : "sg-btn-ghost"} sg-assistant-cta`}
        onClick={onClick}
      >
        {ctaLabel}
      </button>
    </article>
  );
}

function AssistantsHubScreen({
  onOpen,
  onStart,
  segmentsCount = 0,
  articlesCount = 0,
  onboardingCompleted = false,
  interviewCredits = 0,
  editorialPlanAllowed = false,
  publicationScheduleAllowed = false,
  planCode = "",
}) {
  const stats = [
    {
      label: "Segments éditoriaux",
      value: String(segmentsCount),
      hint: "Audiences et angles de contenu",
      icon: "users",
    },
    {
      label: "Articles dans Guy",
      value: String(articlesCount),
      hint: "Titres, brouillons et publiés",
      icon: "docs",
    },
    {
      label: "Site configuré",
      value: onboardingCompleted ? "Oui" : "—",
      hint: onboardingCompleted ? "Assistant démarrage terminé" : "À lancer en premier",
      icon: "check",
    },
  ];

  return (
    <div className="sg-screen sg-screen-assistants">
      <PageHeader
        title={<>Assistant de <span>démarrage</span></>}
        sub="Lancez le parcours guidé pour configurer votre site, vos cibles et votre premier article SEO."
      />

      <div className="sg-assistant-stats">
        {stats.map((s) => (
          <div key={s.label} className="sg-assistant-stat">
            <span className="sg-assistant-stat-ic"><Icon name={s.icon} size={18} /></span>
            <div>
              <p className="sg-assistant-stat-val">{s.value}</p>
              <p className="sg-assistant-stat-lab">{s.label}</p>
              <p className="sg-assistant-stat-hint">{s.hint}</p>
            </div>
          </div>
        ))}
      </div>

      <div className="sg-assistant-grid is-2">
        <AssistantHubCard
          icon="bolt"
          title="Assistant de démarrage"
          pill={
            onboardingCompleted
              ? { label: "Déjà lancé", tone: "published" }
              : { label: "Recommandé en premier", tone: "draft" }
          }
          description={
            <>
              Le grand tour : décrivez votre activité, choisissez vos pages ou
              produits prioritaires, vos cibles et vos mots-clés. Guy crée votre premier{" "}
              <strong>segment éditorial</strong> et un article modèle.
            </>
          }
          bullets={[
            "Analyse du site + suggestions IA",
            "Persona, ton, précautions de rédaction",
            "Génération + relecture du 1er article",
          ]}
          ctaLabel={onboardingCompleted ? "Relancer" : "Commencer"}
          onClick={onStart}
        />
      </div>

      <p className="sg-assistant-footnote">
        Astuce : vous pouvez relancer l&apos;assistant à tout moment depuis cette page.
      </p>
    </div>
  );
}

function SegmentPersonaCard({ persona, index, onEdit }) {
  const enriched =
    (persona.sellingPoints || []).length >= 1 && !!(persona.differentiation || "").trim();
  const bullets = (persona.sellingPoints || []).filter(Boolean).slice(0, 3);
  const fallbackBullets = bullets.length
    ? bullets
    : (persona.interests || []).filter(Boolean).slice(0, 3).length
      ? persona.interests.slice(0, 3)
      : [
          persona.tone ? `Ton : ${persona.tone}` : "Ton éditorial à définir",
          (persona.preferredProducts || []).length
            ? `${persona.preferredProducts.length} produit(s) associé(s)`
            : "Produits à associer au segment",
          "Parcours guidé en 4 étapes + synthèse IA",
        ];

  return (
    <article className="sg-assistant-card is-rich">
      <div className="sg-assistant-head">
        <span className={`sg-assistant-ic${persona.avatarUrl ? " has-photo" : ""}`}>
          {persona.avatarUrl ? (
            <img src={persona.avatarUrl} alt="" />
          ) : (
            <Icon name="users" size={22} />
          )}
        </span>
        <span className={`sg-pill is-${enriched ? "published" : "draft"}`}>
          {enriched ? (persona.tone || "Enrichi") : "À compléter"}
        </span>
      </div>
      <h3>{persona.name}</h3>
      <p className="sg-assistant-desc">{persona.desc}</p>
      <ul className="sg-assistant-bullets">
        {fallbackBullets.map((b) => (
          <li key={b}><Icon name="check" size={14} /> <span>{b}</span></li>
        ))}
      </ul>
      <button
        type="button"
        className="sg-btn-primary sg-assistant-cta"
        onClick={() => onEdit?.(index, persona)}
      >
        {enriched ? "Modifier le segment" : "Enrichir le segment"}
      </button>
    </article>
  );
}

function SegmentAddCard({ atLimit, slotsLeft, onAdd }) {
  return (
    <article className={`sg-assistant-card is-rich sg-seg-add-card${atLimit ? " is-disabled" : ""}`}>
      <div className="sg-assistant-head">
        <span className="sg-assistant-ic"><Icon name="plus" size={22} /></span>
        <span className={`sg-pill is-${atLimit ? "draft" : "scheduled"}`}>
          {atLimit ? "Limite atteinte" : `${slotsLeft} slot${slotsLeft > 1 ? "s" : ""} restant${slotsLeft > 1 ? "s" : ""}`}
        </span>
      </div>
      <h3>Créer un segment de plus</h3>
      <p className="sg-assistant-desc">
        Ajoutez une <strong>nouvelle cible</strong> (autre persona, autre univers produit)
        à votre stratégie. Idéal pour adresser plusieurs audiences sans diluer le ton.
      </p>
      <ul className="sg-assistant-bullets">
        <li><Icon name="check" size={14} /> <span>Reprend votre charte éditoriale</span></li>
        <li><Icon name="check" size={14} /> <span>Ajoute une cible + produits dédiés</span></li>
        <li><Icon name="check" size={14} /> <span>Arguments vendeurs + différenciation</span></li>
      </ul>
      <button
        type="button"
        className={`${atLimit ? "sg-btn-ghost" : "sg-btn-primary"} sg-assistant-cta`}
        disabled={atLimit}
        onClick={() => !atLimit && onAdd?.()}
      >
        {atLimit ? "Passez à un plan supérieur" : "Ajouter un segment"}
      </button>
    </article>
  );
}

function SegFunnelStepIntro({ icon, title, sub }) {
  return (
    <div className="sg-seg-funnel-intro">
      <span className="sg-assistant-ic"><Icon name={icon} size={22} /></span>
      <div>
        <p className="sg-seg-funnel-step-title">{title}</p>
        <p className="sg-assistant-desc">{sub}</p>
      </div>
    </div>
  );
}

function AssistantSegmentScreen({
  onBack,
  personas,
  targets = [],
  segmentsLimit = 3,
  onEditSegment,
  onAddSegment,
}) {
  const list = personas || PERSONAS;
  const count = targets?.length ?? list.length;
  const atLimit = count >= segmentsLimit;
  const enrichedCount = list.filter(
    (p) => (p.sellingPoints || []).length >= 1 && (p.differentiation || "").trim(),
  ).length;
  const slotsLeft = Math.max(0, segmentsLimit - count);

  const stats = [
    {
      label: "Segments éditoriaux",
      value: String(count),
      hint: "Audiences et angles de contenu",
      icon: "users",
    },
    {
      label: "Segments enrichis",
      value: String(enrichedCount),
      hint: "Arguments + différenciation renseignés",
      icon: "star",
    },
    {
      label: "Limite du plan",
      value: `${count}/${segmentsLimit}`,
      hint: atLimit ? "Passez à un plan supérieur" : `${slotsLeft} slot${slotsLeft > 1 ? "s" : ""} disponible${slotsLeft > 1 ? "s" : ""}`,
      icon: "target",
    },
  ];

  return (
    <div className="sg-screen sg-screen-assistants">
      <PageHeader
        title={<>Segments & <span>personas</span></>}
        sub="Enrichissez chaque cible en 4 étapes : profil, produits, arguments et différenciation — Guy synthétise une fiche persona prête pour vos articles."
      />

      <div className="sg-assistant-stats">
        {stats.map((s) => (
          <div key={s.label} className="sg-assistant-stat">
            <span className="sg-assistant-stat-ic"><Icon name={s.icon} size={18} /></span>
            <div>
              <p className="sg-assistant-stat-val">{s.value}</p>
              <p className="sg-assistant-stat-lab">{s.label}</p>
              <p className="sg-assistant-stat-hint">{s.hint}</p>
            </div>
          </div>
        ))}
      </div>

      <div className="sg-assistant-grid is-2">
        {list.map((p, i) => (
          <SegmentPersonaCard
            key={p.id || `pe${i}`}
            persona={p}
            index={i}
            onEdit={onEditSegment}
          />
        ))}
        <SegmentAddCard atLimit={atLimit} slotsLeft={slotsLeft} onAdd={onAddSegment} />
      </div>

      <button type="button" className="sg-seg-back" onClick={onBack}>
        ← Retour aux assistants
      </button>
      <p className="sg-assistant-footnote">
        Astuce : les arguments vendeurs et la différenciation de chaque segment alimentent automatiquement vos pré-prompts de rédaction.
      </p>
    </div>
  );
}

const SEG_FUNNEL_STEP_META = [
  { icon: "user", title: "Client idéal", sub: "Profil, contexte de vie et motivations d'achat pour ce segment." },
  { icon: "card", title: "Produits préférés", sub: "Sélectionnez dans votre catalogue ou décrivez des familles produits." },
  { icon: "star", title: "Arguments vendeurs", sub: "Pourquoi ce segment devrait acheter — réutilisés dans vos pré-prompts articles." },
  { icon: "trending", title: "Vs concurrent", sub: "Votre différenciation concrète pour ce segment (service, expertise, promesse…)." },
  { icon: "spark", title: "Synthèse IA", sub: "Guy génère une fiche persona enrichie — relisez et ajustez avant enregistrement." },
];
const SEG_FUNNEL_STEPS = SEG_FUNNEL_STEP_META.map((m) => m.title);

const SEG_ANALYSIS_MSGS = [
  "Guy croise profil et catalogue…",
  "Affinage des arguments vendeurs…",
  "Rédaction de la fiche persona…",
];

function normalizeSegmentDraft(d) {
  return {
    name: (d.name || "").trim(),
    profile: (d.profile || "").trim(),
    motivations: (d.motivations || "").trim(),
    selectedProducts: [...(d.selectedProducts || [])].map((s) => s.trim()).filter(Boolean).sort(),
    productFamilies: (d.productFamilies || "").trim(),
    sellingPoints: (d.sellingPoints || ["", "", ""]).map((s) => (s || "").trim()),
    differentiation: (d.differentiation || "").trim(),
  };
}

function segmentDraftHasChanges(current, initial) {
  return JSON.stringify(normalizeSegmentDraft(current)) !== JSON.stringify(normalizeSegmentDraft(initial));
}

function segmentDraftHasMinimalContent(d) {
  const n = normalizeSegmentDraft(d);
  return !!(
    n.name ||
    n.profile ||
    n.motivations ||
    n.selectedProducts.length ||
    n.productFamilies ||
    n.sellingPoints.some((s) => s.length > 0) ||
    n.differentiation
  );
}

function buildTargetFromDraft(draft, existingTarget, existingPersona) {
  const parsed = existingTarget?.audience
    ? cfgParseAudience(existingTarget.audience)
    : { name: "", description: "", interests: [] };
  const name = draft.name.trim() || parsed.name || existingPersona?.name || "";
  const description = draft.profile.trim() || parsed.description || existingPersona?.desc || "";
  const interests = (existingPersona?.interests || parsed.interests || []).filter(Boolean);
  const tone = existingTarget?.tone || existingPersona?.tone || "";
  const sellingPoints = draft.sellingPoints.map((s) => s.trim()).filter(Boolean).slice(0, 3);
  const differentiation = draft.differentiation.trim() || existingTarget?.differentiation || "";
  const preferredProducts = draft.selectedProducts.length
    ? draft.selectedProducts
    : (existingTarget?.preferredProducts || existingPersona?.preferredProducts || []);
  const productFamilies = draft.productFamilies.trim() || existingTarget?.productFamilies || "";

  let audience = description;
  if (name && description) audience = `${name} — ${description}`;
  else if (name) audience = name;
  else if (existingTarget?.audience) audience = existingTarget.audience.split(" · Recherche :")[0].trim();

  if (interests.length && audience) {
    audience = `${audience}${CFG_INTEREST_MARKER}${interests.join(", ")}`;
  }

  const target = {
    audience: audience || existingTarget?.audience || "",
    tone,
    avatarUrl: existingTarget?.avatarUrl ?? null,
  };
  const sp = sellingPoints.length ? sellingPoints : (existingTarget?.sellingPoints || []);
  if (sp.length) target.sellingPoints = sp;
  if (differentiation) target.differentiation = differentiation;
  if (preferredProducts.length) target.preferredProducts = preferredProducts;
  if (productFamilies) target.productFamilies = productFamilies;
  return target;
}

function funnelDraftFromTarget(target, persona) {
  const t = target || persona?.raw;
  const parsed = t?.audience
    ? cfgParseAudience(t.audience)
    : { name: persona?.name || "", description: persona?.desc || "", interests: [] };
  const selling = t?.sellingPoints || persona?.sellingPoints || [];
  return {
    name: parsed.name || persona?.name || "",
    profile: parsed.description || persona?.desc || "",
    motivations: "",
    selectedProducts: [...(t?.preferredProducts || persona?.preferredProducts || [])],
    productFamilies: t?.productFamilies || persona?.productFamilies || "",
    sellingPoints: [selling[0] || "", selling[1] || "", selling[2] || ""],
    differentiation: t?.differentiation || persona?.differentiation || "",
  };
}

function SegmentFunnelModal({
  mode = "create",
  editIndex = 0,
  targets = [],
  personas = [],
  featuredProducts = [],
  onClose,
  onSaved,
}) {
  const existingTarget = mode === "enrich" ? targets[editIndex] : null;
  const existingPersona = personas[editIndex];
  const initialDraft = funnelDraftFromTarget(existingTarget, existingPersona);
  const initialDraftRef = useR(initialDraft);

  const [step, setStep] = useS(0);
  const [draft, setDraft] = useS(initialDraft);
  const [productQuery, setProductQuery] = useS("");
  const [catalogHits, setCatalogHits] = useS([]);
  const [catalogLoading, setCatalogLoading] = useS(false);
  const [synthesizing, setSynthesizing] = useS(false);
  const [msgIdx, setMsgIdx] = useS(0);
  const [result, setResult] = useS(null);
  const [review, setReview] = useS(null);
  const [error, setError] = useS("");
  const [saving, setSaving] = useS(false);

  useE(() => {
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = ""; };
  }, []);

  useE(() => {
    let interval;
    if (synthesizing) {
      interval = window.setInterval(
        () => setMsgIdx((i) => (i + 1) % SEG_ANALYSIS_MSGS.length),
        2600,
      );
    }
    return () => { if (interval) window.clearInterval(interval); };
  }, [synthesizing]);

  const featuredNames = (featuredProducts || []).map((p) => p.name).filter(Boolean);
  const productOptions = [...new Set([...featuredNames, ...catalogHits.map((p) => p.title)])];

  async function searchCatalog(q) {
    const needle = (q || "").trim();
    if (needle.length < 2) {
      setCatalogHits([]);
      return;
    }
    setCatalogLoading(true);
    try {
      const data = await GuyAPI.shopifyProducts(needle);
      setCatalogHits(data.products || []);
    } catch {
      setCatalogHits([]);
    } finally {
      setCatalogLoading(false);
    }
  }

  function patchDraft(patch) {
    setDraft((d) => ({ ...d, ...patch }));
  }

  function toggleProduct(name) {
    const label = (name || "").trim();
    if (!label) return;
    setDraft((d) => {
      const has = d.selectedProducts.includes(label);
      return {
        ...d,
        selectedProducts: has
          ? d.selectedProducts.filter((x) => x !== label)
          : [...d.selectedProducts, label].slice(0, 25),
      };
    });
  }

  function stepValid(idx) {
    if (idx < 4) return true;
    return Boolean((review?.target?.audience || "").trim());
  }

  function applyReviewWithoutAi() {
    const built = existingTarget?.audience && !segmentDraftHasChanges(draft, initialDraftRef.current)
      ? { ...existingTarget }
      : buildTargetFromDraft(draft, existingTarget, existingPersona);
    const parsed = cfgParseAudience(built.audience || "");
    setReview({
      target: built,
      name: parsed.name || draft.name.trim(),
      description: parsed.description || draft.profile.trim(),
      tone: built.tone || "",
      interests: parsed.interests || existingPersona?.interests || [],
      sellingPoints: built.sellingPoints || [],
      differentiation: built.differentiation || "",
      summary:
        mode === "enrich" && existingTarget?.audience
          ? "Aucune modification détectée — la fiche existante est conservée."
          : "Aucune information saisie. Revenez en arrière pour compléter le segment.",
      skippedAi: true,
    });
  }

  async function runSynthesis() {
    setSynthesizing(true);
    setError("");
    try {
      const data = await GuyAPI.enrichSegment({
        mode,
        editIndex,
        idealClient: {
          name: draft.name.trim(),
          profile: draft.profile.trim(),
          motivations: draft.motivations.trim(),
        },
        products: {
          selected: draft.selectedProducts,
          familiesFreeText: draft.productFamilies.trim(),
        },
        sellingPoints: draft.sellingPoints.map((s) => s.trim()).filter(Boolean),
        differentiation: draft.differentiation.trim(),
        interestOptions: PERSONA_INTERESTS,
        toneOptions: PERSONA_TONES.map((t) => t.label),
      });
      setResult(data);
      const parsed = cfgParseAudience(data.target?.audience || "");
      setReview({
        target: data.target,
        name: parsed.name || data.persona?.name || draft.name,
        description: parsed.description || data.persona?.description || "",
        tone: data.target?.tone || data.persona?.tone || "",
        interests: data.persona?.interests || parsed.interests || [],
        sellingPoints: data.target?.sellingPoints || [],
        differentiation: data.target?.differentiation || "",
        summary: data.summary || "",
      });
    } catch (e) {
      setError(e.message || "Synthèse impossible.");
      setStep(3);
    } finally {
      setSynthesizing(false);
    }
  }

  async function goNext() {
    if (step < 3) {
      setStep((s) => s + 1);
      return;
    }
    if (step === 3) {
      setError("");
      const hasChanges = segmentDraftHasChanges(draft, initialDraftRef.current);
      if (!hasChanges) {
        applyReviewWithoutAi();
        setStep(4);
        return;
      }
      if (mode === "create" && !segmentDraftHasMinimalContent(draft)) {
        applyReviewWithoutAi();
        setStep(4);
        return;
      }
      setStep(4);
      await runSynthesis();
    }
  }

  function goBack() {
    if (step === 0) {
      onClose?.();
      return;
    }
    if (step === 4 && synthesizing) return;
    setStep((s) => Math.max(0, s - 1));
  }

  async function saveSegment() {
    if (!review?.target?.audience) return;
    setSaving(true);
    setError("");
    try {
      const parsed = cfgParseAudience(review.target.audience);
      let audience = review.description.trim();
      const name = review.name.trim();
      if (name && audience) audience = `${name} — ${audience}`;
      else if (name) audience = name;
      const interests = (review.interests || []).filter(Boolean);
      if (interests.length) {
        audience = `${audience}${CFG_INTEREST_MARKER}${interests.join(", ")}`;
      }
      const target = {
        ...review.target,
        audience,
        tone: review.tone || review.target.tone || "",
        sellingPoints: (review.sellingPoints || []).map((s) => s.trim()).filter(Boolean).slice(0, 3),
        differentiation: (review.differentiation || "").trim(),
        preferredProducts: draft.selectedProducts,
        productFamilies: draft.productFamilies.trim() || undefined,
        avatarUrl: existingTarget?.avatarUrl ?? review.target.avatarUrl ?? null,
      };
      const next = [...targets];
      if (mode === "enrich" && editIndex < next.length) {
        next[editIndex] = target;
      } else {
        next.push(target);
      }
      await GuyAPI.saveConfig({ targetAudiences: next });
      onSaved?.();
    } catch (e) {
      setError(e.message || "Enregistrement impossible.");
    } finally {
      setSaving(false);
    }
  }

  const progressPct = Math.round(((step + 1) / SEG_FUNNEL_STEPS.length) * 100);

  return (
    <div className="sg-overlay" onClick={onClose}>
      <div className="sg-iv-room sg-seg-funnel" onClick={(e) => e.stopPropagation()}>
        <header className="sg-iv-room-head">
          <div>
            <span className="sg-next-eyebrow"><Icon name="users" size={14} /> SEO GUY · Segments</span>
            <h2 className="sg-iv-room-title">
              {mode === "enrich" ? "Enrichir un segment" : "Nouveau segment"}
            </h2>
            <p className="sg-set-sub" style={{ marginTop: 6 }}>
              Étape {step + 1} sur {SEG_FUNNEL_STEPS.length} — {SEG_FUNNEL_STEPS[step]}
            </p>
          </div>
          <button type="button" className="sg-review-close" onClick={onClose} aria-label="Fermer">✕</button>
        </header>
        <div className="sg-iv-progress">
          <div className="sg-iv-progress-bar"><span style={{ width: `${progressPct}%` }} /></div>
          <span className="sg-iv-progress-lab">{progressPct}%</span>
        </div>
        <div className="sg-iv-wizard-steps" style={{ padding: "12px 30px 0" }}>
          {SEG_FUNNEL_STEPS.map((label, i) => (
            <span
              key={label}
              className={`sg-iv-wizard-step${i <= step ? " is-done" : ""}${i === step ? " is-current" : ""}`}
            >
              {i + 1}. {label}
            </span>
          ))}
        </div>
        <div className="sg-iv-wizard-body">
          {error ? <p className="sg-field-error">{error}</p> : null}

          {step === 0 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Décrivez votre client idéal</p>
              <p className="sg-set-sub">Profil, contexte de vie et motivations d'achat pour ce segment. <em className="sg-optional-tag">Facultatif</em></p>
              <label className="sg-field-label">Prénom ou libellé</label>
              <input
                className="sg-cfg-input"
                placeholder="Ex. Rebecca, Parent actif…"
                value={draft.name}
                onChange={(e) => patchDraft({ name: e.target.value })}
              />
              <label className="sg-field-label">Profil & contexte</label>
              <textarea
                className="sg-textarea"
                rows={3}
                placeholder="Âge, style de vie, contraintes, ce qui compte pour lui/elle…"
                value={draft.profile}
                onChange={(e) => patchDraft({ profile: e.target.value })}
              />
              <label className="sg-field-label">Motivations & attentes</label>
              <textarea
                className="sg-textarea"
                rows={3}
                placeholder="Pourquoi achète-t-il/elle ? Quels problèmes veut-il/elle résoudre ?"
                value={draft.motivations}
                onChange={(e) => patchDraft({ motivations: e.target.value })}
              />
            </section>
          )}

          {step === 1 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Quels produits lui plaisent ?</p>
              <p className="sg-set-sub">Sélectionnez dans votre catalogue ou décrivez des familles produits. <em className="sg-optional-tag">Facultatif</em></p>
              {featuredNames.length > 0 && (
                <>
                  <p className="sg-field-hint sg-cfg-sub-label">Produits mis en avant</p>
                  <div className="sg-seg-product-picks">
                    {featuredNames.map((name) => (
                      <button
                        key={name}
                        type="button"
                        className={`sg-seg-product-pick${draft.selectedProducts.includes(name) ? " is-on" : ""}`}
                        onClick={() => toggleProduct(name)}
                      >
                        {name}
                      </button>
                    ))}
                  </div>
                </>
              )}
              <label className="sg-field-label">Rechercher dans le catalogue</label>
              <div className="sg-seg-product-search">
                <input
                  className="sg-cfg-input"
                  placeholder="Nom du produit…"
                  value={productQuery}
                  onChange={(e) => {
                    setProductQuery(e.target.value);
                    void searchCatalog(e.target.value);
                  }}
                />
                {catalogLoading ? <span className="sg-spinner sm" aria-hidden="true" /> : null}
              </div>
              {productOptions.length > featuredNames.length && (
                <div className="sg-seg-product-picks">
                  {catalogHits.map((p) => (
                    <button
                      key={p.id || p.title}
                      type="button"
                      className={`sg-seg-product-pick${draft.selectedProducts.includes(p.title) ? " is-on" : ""}`}
                      onClick={() => toggleProduct(p.title)}
                    >
                      {p.title}
                    </button>
                  ))}
                </div>
              )}
              <label className="sg-field-label">Familles / gammes (texte libre)</label>
              <textarea
                className="sg-textarea"
                rows={2}
                placeholder="Ex. gourdes isothermes, accessoires randonnée…"
                value={draft.productFamilies}
                onChange={(e) => patchDraft({ productFamilies: e.target.value })}
              />
            </section>
          )}

          {step === 2 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">3 arguments vendeurs</p>
              <p className="sg-set-sub">Pourquoi ce segment devrait acheter — réutilisés dans vos pré-prompts articles. <em className="sg-optional-tag">Facultatif</em></p>
              {[0, 1, 2].map((i) => (
                <div key={i}>
                  <label className="sg-field-label">Argument {i + 1}</label>
                  <input
                    className="sg-cfg-input"
                    placeholder={i === 0 ? "Ex. Autonomie 24 h sans recharge" : i === 1 ? "Ex. Matériaux recyclés certifiés" : "Ex. Garantie satisfait ou remboursé 60 jours"}
                    value={draft.sellingPoints[i] || ""}
                    onChange={(e) => {
                      const next = [...draft.sellingPoints];
                      next[i] = e.target.value;
                      patchDraft({ sellingPoints: next });
                    }}
                  />
                </div>
              ))}
            </section>
          )}

          {step === 3 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Pourquoi chez vous plutôt que chez un concurrent ?</p>
              <p className="sg-set-sub">Votre différenciation concrète pour ce segment (service, expertise, promesse…). <em className="sg-optional-tag">Facultatif</em></p>
              <textarea
                className="sg-textarea"
                rows={5}
                placeholder="Ex. Fabrication française, SAV réactif, expertise produit depuis 15 ans…"
                value={draft.differentiation}
                onChange={(e) => patchDraft({ differentiation: e.target.value })}
              />
            </section>
          )}

          {step === 4 && (
            <section className="sg-iv-wizard-panel">
              {synthesizing ? (
                <div className="sg-iv-thinking">
                  <img src={POSE.analyse} alt="" className="sg-iv-thinking-img" />
                  <div className="sg-iv-thinking-body">
                    <span className="sg-spinner lg" aria-hidden="true" />
                    <p className="sg-iv-thinking-title">{SEG_ANALYSIS_MSGS[msgIdx]}</p>
                    <p className="sg-iv-thinking-sub">Synthèse persona en cours…</p>
                  </div>
                </div>
              ) : review ? (
                <>
                  <p className="sg-set-title">
                    {review.skippedAi ? "Fiche persona — relecture" : "Fiche persona — synthèse IA"}
                  </p>
                  <p className={`sg-set-sub${review.skippedAi ? " is-muted-note" : ""}`}>{review.summary}</p>
                  <label className="sg-field-label">Nom</label>
                  <input className="sg-cfg-input" value={review.name} onChange={(e) => setReview({ ...review, name: e.target.value })} />
                  <label className="sg-field-label">Description</label>
                  <textarea className="sg-textarea" rows={3} value={review.description} onChange={(e) => setReview({ ...review, description: e.target.value })} />
                  <p className="sg-field-hint sg-cfg-sub-label">Intentions éditoriales</p>
                  <div className="sg-cfg-interests">
                    {(PERSONA_INTERESTS || []).map((label) => (
                      <button
                        key={label}
                        type="button"
                        className={`sg-cfg-interest${(review.interests || []).includes(label) ? " is-on" : ""}`}
                        onClick={() => {
                          const list = review.interests || [];
                          const has = list.includes(label);
                          setReview({
                            ...review,
                            interests: has ? list.filter((x) => x !== label) : [...list, label],
                          });
                        }}
                      >
                        {label}
                      </button>
                    ))}
                  </div>
                  <p className="sg-field-hint sg-cfg-sub-label">Ton</p>
                  <div className="ob-tone-seg sg-cfg-tone-seg">
                    {(PERSONA_TONES || []).map((t) => (
                      <button
                        key={t.id}
                        type="button"
                        className={`ob-tone-seg-btn${review.tone === t.label ? " is-on" : ""}`}
                        onClick={() => setReview({ ...review, tone: t.label })}
                      >
                        {t.label}
                      </button>
                    ))}
                  </div>
                  <p className="sg-field-hint sg-cfg-sub-label">Arguments vendeurs</p>
                  {(review.sellingPoints || []).map((pt, i) => (
                    <input
                      key={i}
                      className="sg-cfg-input"
                      value={pt}
                      onChange={(e) => {
                        const next = [...(review.sellingPoints || [])];
                        next[i] = e.target.value;
                        setReview({ ...review, sellingPoints: next });
                      }}
                    />
                  ))}
                  <label className="sg-field-label">Différenciation</label>
                  <textarea
                    className="sg-textarea"
                    rows={2}
                    value={review.differentiation || ""}
                    onChange={(e) => setReview({ ...review, differentiation: e.target.value })}
                  />
                </>
              ) : null}
            </section>
          )}
        </div>
        <footer className="sg-iv-room-foot">
          <button type="button" className="sg-btn-ghost sm" onClick={goBack} disabled={synthesizing}>
            {step === 0 ? "Annuler" : "← Retour"}
          </button>
          {step < 4 ? (
            <button
              type="button"
              className="sg-btn-primary sm"
              onClick={() => void goNext()}
            >
              {step === 3 ? "Terminer" : "Continuer"}
            </button>
          ) : (
            <button
              type="button"
              className="sg-btn-primary sm"
              disabled={synthesizing || saving || !stepValid(4)}
              onClick={() => void saveSegment()}
            >
              {saving ? "Enregistrement…" : "Enregistrer le segment"}
            </button>
          )}
        </footer>
      </div>
    </div>
  );
}

const PLAN_FUNNEL_STEPS = ["Périodes clés", "Événements", "Publication", "Calendrier 12 sem."];

const PLAN_ANALYSIS_MSGS = [
  "Guy croise personas et saisonnalité…",
  "Alignement sur la Search Console…",
  "Construction du calendrier 12 semaines…",
];

function formatSlotsLabel(slots) {
  const days = ["", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
  if (!slots?.length) return "Non configuré";
  return slots
    .map((s) => {
      const m = s.minute ? `:${String(s.minute).padStart(2, "0")}` : "";
      return `${days[s.weekday] || "?"} ${String(s.hour).padStart(2, "0")}h${m}`;
    })
    .join(" · ");
}

function PublicationSchedulePanel({
  schedule,
  publicationScheduleAllowed = false,
  editorialPlanAllowed = false,
  editorialQuota,
  onSaveSchedule,
  onSaved,
  busy = false,
}) {
  const scheduleAllowed = publicationScheduleAllowed || editorialPlanAllowed;
  const sched = schedule || {};
  const [saving, setSaving] = useS(false);
  const [error, setError] = useS("");
  const [liabilityOpen, setLiabilityOpen] = useS(false);

  const reviewMode = !!sched.enabled && !sched.publishWithoutReview;
  const fullAuto = !!sched.enabled && !!sched.publishWithoutReview;
  const articlesPerWeek = editorialQuota?.articlesPerWeek ?? 2;
  const slotLabel = formatSlotsLabel(sched.slots);

  function buildPayload(overrides) {
    return {
      enabled: sched.enabled ?? false,
      timezone: sched.timezone || "Europe/Paris",
      cadence: sched.cadence || "weekly",
      biweeklyOnEvenIsoWeeks: sched.biweeklyOnEvenIsoWeeks !== false,
      slots: sched.slots?.length
        ? sched.slots
        : [{ weekday: 2, hour: 9, minute: 0 }],
      requireReviewBeforePublish: true,
      publishWithoutReview: false,
      liabilityAcceptedAt: null,
      lastProcessedSlotKey: sched.lastProcessedSlotKey ?? null,
      ...overrides,
    };
  }

  async function persist(payload) {
    if (!onSaveSchedule) return;
    setSaving(true);
    setError("");
    try {
      await onSaveSchedule(payload);
      onSaved?.();
    } catch (e) {
      setError(e.message || "Enregistrement impossible.");
    } finally {
      setSaving(false);
    }
  }

  function slotsForPlan() {
    const suggested = editorialQuota?.suggestedPublicationSlots;
    if (suggested?.length) return suggested;
    if (sched.slots?.length >= articlesPerWeek) return sched.slots;
    return sched.slots?.length ? sched.slots : [{ weekday: 2, hour: 9, minute: 0 }];
  }

  function enableReviewMode() {
    void persist(
      buildPayload({
        enabled: true,
        publishWithoutReview: false,
        requireReviewBeforePublish: true,
        liabilityAcceptedAt: null,
        slots: slotsForPlan(),
      }),
    );
  }

  function disableReviewMode() {
    if (fullAuto) return;
    void persist(
      buildPayload({
        enabled: false,
        publishWithoutReview: false,
        requireReviewBeforePublish: true,
        liabilityAcceptedAt: null,
      }),
    );
  }

  function confirmFullAuto() {
    setLiabilityOpen(false);
    void persist(
      buildPayload({
        enabled: true,
        publishWithoutReview: true,
        requireReviewBeforePublish: false,
        liabilityAcceptedAt: new Date().toISOString(),
        slots: slotsForPlan(),
      }),
    );
  }

  function disableFullAuto() {
    void persist(
      buildPayload({
        enabled: false,
        publishWithoutReview: false,
        requireReviewBeforePublish: true,
        liabilityAcceptedAt: null,
      }),
    );
  }

  return (
    <>
      <div className="sg-set-row">
        <div className="sg-set-txt">
          <p className="sg-set-title">Créneaux automatiques</p>
          <p className="sg-set-sub">
            {slotLabel} — mode relecture avant publication.
            {articlesPerWeek > 2 ? ` Aligné sur ${articlesPerWeek} art./sem.` : ""}
          </p>
        </div>
        <button
          type="button"
          className={`sg-switch${reviewMode ? " is-on" : ""}`}
          disabled={!scheduleAllowed || saving || busy}
          aria-pressed={reviewMode}
          onClick={() => (reviewMode ? disableReviewMode() : enableReviewMode())}
        >
          <span />
        </button>
      </div>
      <div className="sg-set-sep" />
      <div className="sg-set-row">
        <div className="sg-set-txt">
          <p className="sg-set-title">Mode 100 % automatique</p>
          <p className="sg-set-sub">
            Publication sans relecture — clause de responsabilité requise.
          </p>
        </div>
        <button
          type="button"
          className={`sg-switch${fullAuto ? " is-on" : ""}`}
          disabled={!scheduleAllowed || saving || busy}
          aria-pressed={fullAuto}
          onClick={() => (fullAuto ? disableFullAuto() : setLiabilityOpen(true))}
        >
          <span />
        </button>
      </div>
      {error ? <p className="sg-field-error">{error}</p> : null}
      {saving ? <p className="sg-field-hint">Enregistrement…</p> : null}
      {liabilityOpen ? (
        <div className="sg-overlay" onClick={() => setLiabilityOpen(false)}>
          <div
            className="sg-panel sg-liability-modal"
            onClick={(e) => e.stopPropagation()}
            role="dialog"
            aria-labelledby="sg-liability-title"
          >
            <h3 id="sg-liability-title" className="sg-block-title">Clause de responsabilité</h3>
            <p className="sg-set-sub">
              En activant le mode 100 % automatique, SEO Guy enchaîne titres, articles, visuels et
              programmation sans validation humaine. Vous acceptez la responsabilité du contenu publié.
            </p>
            <div className="sg-liability-actions">
              <button type="button" className="sg-btn-ghost sm" onClick={() => setLiabilityOpen(false)}>
                Annuler
              </button>
              <button type="button" className="sg-btn-primary sm" onClick={confirmFullAuto}>
                J&apos;accepte et j&apos;active
              </button>
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}

function ManualEditorialPlanPanel({
  markdown = "",
  onSave,
  onSaved,
  busy = false,
}) {
  const [text, setText] = useS(markdown || "");
  const [saving, setSaving] = useS(false);
  const [error, setError] = useS("");
  const [saved, setSaved] = useS(false);

  useE(() => {
    setText(markdown || "");
  }, [markdown]);

  async function savePlan() {
    if (!onSave) return;
    setSaving(true);
    setError("");
    setSaved(false);
    try {
      await onSave({ editorialPlanMarkdown: text.trim() });
      setSaved(true);
      onSaved?.();
    } catch (e) {
      setError(e.message || "Enregistrement impossible.");
      throw e;
    } finally {
      setSaving(false);
    }
  }

  const isDirty = (text || "").trim() !== (markdown || "").trim();
  useUnsavedChangesGuard({
    isDirty,
    onSave: savePlan,
    onDiscard: () => setText(markdown || ""),
  });

  return (
    <>
      <p className="sg-assistant-desc">
        Renseignez votre calendrier éditorial sous forme de <strong>tableau markdown</strong> :
        semaine, date, thème, mot-clé, persona, angle… Guy s&apos;en sert pour orienter les suggestions de titres.
      </p>
      <label className="sg-field-label">Plan éditorial (markdown)</label>
      <textarea
        className="sg-textarea"
        rows={14}
        placeholder={"| Semaine | Date | Thème | Format | Mot-clé | Persona | Intentions | Événement | Intention | Angle | Priorité |\n|---|---|---|---|---|---|---|---|---|---|---|"}
        value={text}
        onChange={(e) => {
          setText(e.target.value);
          setSaved(false);
        }}
      />
      {error ? <p className="sg-field-error">{error}</p> : null}
      {saved ? <p className="sg-field-hint sg-sync-ok">Plan enregistré.</p> : null}
      <button
        type="button"
        className="sg-btn-primary sg-assistant-cta"
        disabled={busy || saving}
        onClick={() => void savePlan()}
      >
        {saving ? "Enregistrement…" : "Enregistrer le plan"}
      </button>
    </>
  );
}

function defaultPlanPublicationPrefs(schedule, editorialQuota) {
  const suggested = editorialQuota?.suggestedPublicationSlots;
  const slots = schedule?.slots?.length ? schedule.slots : (suggested?.length ? suggested : [{ weekday: 2, hour: 9 }]);
  return {
    weekdays: [...new Set(slots.map((s) => s.weekday))],
    hours: [...new Set(slots.map((s) => s.hour))],
    timezone: schedule?.timezone || "Europe/Paris",
    notes: "",
  };
}

function EditorialPlanFunnelModal({
  personas = [],
  schedule,
  editorialQuota,
  gscConnected = false,
  onClose,
  onSaved,
}) {
  const pubDefaults = defaultPlanPublicationPrefs(schedule, editorialQuota);
  const [step, setStep] = useS(0);
  const [periods, setPeriods] = useS([]);
  const [periodsText, setPeriodsText] = useS("");
  const [retailEvents, setRetailEvents] = useS([]);
  const [customEvents, setCustomEvents] = useS("");
  const [weekdays, setWeekdays] = useS(pubDefaults.weekdays);
  const [hours, setHours] = useS(pubDefaults.hours);
  const [pubNotes, setPubNotes] = useS("");
  const [generating, setGenerating] = useS(false);
  const [msgIdx, setMsgIdx] = useS(0);
  const [result, setResult] = useS(null);
  const [error, setError] = useS("");
  const [saving, setSaving] = useS(false);

  useE(() => {
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = ""; };
  }, []);

  useE(() => {
    let interval;
    if (generating) {
      interval = window.setInterval(
        () => setMsgIdx((i) => (i + 1) % PLAN_ANALYSIS_MSGS.length),
        2600,
      );
    }
    return () => { if (interval) window.clearInterval(interval); };
  }, [generating]);

  function togglePeriod(id) {
    setPeriods((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
  }
  function toggleRetail(id) {
    setRetailEvents((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
  }
  function toggleWeekday(v) {
    setWeekdays((prev) => (prev.includes(v) ? prev.filter((x) => x !== v) : [...prev, v].sort()));
  }
  function toggleHour(h) {
    setHours((prev) => (prev.includes(h) ? prev.filter((x) => x !== h) : [...prev, h].sort()));
  }

  async function runGeneration() {
    setGenerating(true);
    setError("");
    try {
      const data = await GuyAPI.editorialPlanGenerateCalendar({
        importantPeriods: periods,
        periodsFreeText: periodsText.trim(),
        selectedRetailEvents: retailEvents,
        customEvents: customEvents.trim(),
        publicationPreferences: {
          weekdays: weekdays.length ? weekdays : [2, 4],
          hours: hours.length ? hours : [9],
          timezone: pubDefaults.timezone,
          notes: pubNotes.trim(),
        },
      });
      setResult(data);
    } catch (e) {
      setError(e.message || "Génération impossible.");
      setStep(2);
    } finally {
      setGenerating(false);
    }
  }

  async function goNext() {
    if (step < 2) {
      setStep((s) => s + 1);
      return;
    }
    if (step === 2) {
      setStep(3);
      await runGeneration();
    }
  }

  function goBack() {
    if (step === 0) {
      onClose?.();
      return;
    }
    if (step === 3 && generating) return;
    setStep((s) => Math.max(0, s - 1));
  }

  async function savePlan() {
    if (!result?.editorialPlanMarkdown) return;
    setSaving(true);
    setError("");
    try {
      await GuyAPI.editorialPlanApply({ editorialPlanMarkdown: result.editorialPlanMarkdown });
      onSaved?.();
    } catch (e) {
      setError(e.message || "Enregistrement impossible.");
    } finally {
      setSaving(false);
    }
  }

  const progressPct = Math.round(((step + 1) / PLAN_FUNNEL_STEPS.length) * 100);

  return (
    <div className="sg-overlay" onClick={onClose}>
      <div className="sg-iv-room sg-plan-funnel" onClick={(e) => e.stopPropagation()}>
        <header className="sg-iv-room-head">
          <div>
            <span className="sg-next-eyebrow"><Icon name="calendar" size={14} /> SEO GUY · Plan éditorial</span>
            <h2 className="sg-iv-room-title">Calendrier éditorial 12 semaines</h2>
            <p className="sg-set-sub" style={{ marginTop: 6 }}>
              Étape {step + 1} sur {PLAN_FUNNEL_STEPS.length} — {PLAN_FUNNEL_STEPS[step]}
            </p>
          </div>
          <button type="button" className="sg-review-close" onClick={onClose} aria-label="Fermer">✕</button>
        </header>
        <div className="sg-iv-progress">
          <div className="sg-iv-progress-bar"><span style={{ width: `${progressPct}%` }} /></div>
          <span className="sg-iv-progress-lab">{progressPct}%</span>
        </div>
        <div className="sg-iv-wizard-steps" style={{ padding: "12px 30px 0" }}>
          {PLAN_FUNNEL_STEPS.map((label, i) => (
            <span
              key={label}
              className={`sg-iv-wizard-step${i <= step ? " is-done" : ""}${i === step ? " is-current" : ""}`}
            >
              {i + 1}. {label}
            </span>
          ))}
        </div>
        <div className="sg-iv-wizard-body">
          {error ? <p className="sg-field-error">{error}</p> : null}

          {personas.length > 0 && step < 3 && (
            <div className="sg-plan-funnel-context">
              <p className="sg-cfg-sub-label">Personas & intentions pris en compte</p>
              <div className="sg-plan-funnel-personas">
                {personas.slice(0, 3).map((p) => (
                  <span key={p.id} className="sg-plan-funnel-persona-chip">
                    <b>{p.name}</b>
                    {(p.interests || []).length ? ` · ${p.interests.slice(0, 2).join(", ")}` : ""}
                  </span>
                ))}
              </div>
            </div>
          )}

          {step === 0 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Quelles périodes de l&apos;année comptent pour vous ?</p>
              <p className="sg-set-sub">Saisons commerciales et moments forts de votre activité. <em className="sg-optional-tag">Facultatif</em></p>
              <div className="sg-seg-product-picks">
                {(EDITORIAL_SEASON_PERIODS || []).map((p) => (
                  <button
                    key={p.id}
                    type="button"
                    className={`sg-seg-product-pick${periods.includes(p.id) ? " is-on" : ""}`}
                    onClick={() => togglePeriod(p.id)}
                  >
                    {p.label}
                  </button>
                ))}
              </div>
              <label className="sg-field-label">Autres périodes importantes</label>
              <textarea
                className="sg-textarea"
                rows={3}
                placeholder="Ex. soldes privées en septembre, lancement collection automne…"
                value={periodsText}
                onChange={(e) => setPeriodsText(e.target.value)}
              />
            </section>
          )}

          {step === 1 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Événements, salons et temps forts retail</p>
              <p className="sg-set-sub">Calendrier national + vos événements propre à votre boutique. <em className="sg-optional-tag">Facultatif</em></p>
              <p className="sg-field-hint sg-cfg-sub-label">Événements du calendrier</p>
              <div className="sg-seg-product-picks">
                {(EDITORIAL_RETAIL_EVENTS || []).map((ev) => (
                  <button
                    key={ev.id}
                    type="button"
                    className={`sg-seg-product-pick${retailEvents.includes(ev.id) ? " is-on" : ""}`}
                    onClick={() => toggleRetail(ev.id)}
                  >
                    {ev.label}
                  </button>
                ))}
              </div>
              <label className="sg-field-label">Salons, soldes, opérations spéciales</label>
              <textarea
                className="sg-textarea"
                rows={4}
                placeholder="Ex. salon du surf Paris en janvier, soldes flash été, collab influenceur en octobre…"
                value={customEvents}
                onChange={(e) => setCustomEvents(e.target.value)}
              />
            </section>
          )}

          {step === 2 && (
            <section className="sg-iv-wizard-panel">
              <p className="sg-set-title">Jours et heures de publication</p>
              {editorialQuota ? (
                <div className="sg-plan-funnel-context">
                  <p className="sg-cfg-sub-label">Quota de votre plan</p>
                  <p className="sg-set-sub" style={{ marginTop: 4 }}>
                    <strong>{editorialQuota.articlesPerWeek} article(s)/semaine</strong>
                    {" · "}
                    {editorialQuota.totalBlogEntries12Weeks} entrées blog sur 12 sem.
                    {editorialQuota.interviewsIn12Weeks > 0 ? (
                      <>
                        {" · "}
                        <strong>{editorialQuota.interviewRhythmLabel}</strong>
                      </>
                    ) : null}
                  </p>
                  <button
                    type="button"
                    className="sg-btn-ghost sm"
                    style={{ marginTop: 8 }}
                    onClick={() => {
                      const suggested = editorialQuota.suggestedPublicationSlots || [];
                      if (!suggested.length) return;
                      setWeekdays([...new Set(suggested.map((s) => s.weekday))].sort());
                      setHours([...new Set(suggested.map((s) => s.hour))].sort());
                    }}
                  >
                    Aligner les créneaux sur le plan ({editorialQuota.articlesPerWeek}/sem.)
                  </button>
                </div>
              ) : null}
              <p className="sg-set-sub">
                Guy s&apos;appuie aussi sur la Search Console{gscConnected ? " (connectée)" : ""} et vos performances Shopify pour affiner les créneaux.
                <em className="sg-optional-tag">Facultatif</em>
              </p>
              <p className="sg-field-hint sg-cfg-sub-label">Jours préférés</p>
              <div className="sg-seg-product-picks">
                {(EDITORIAL_WEEKDAYS || []).map((d) => (
                  <button
                    key={d.v}
                    type="button"
                    className={`sg-seg-product-pick${weekdays.includes(d.v) ? " is-on" : ""}`}
                    onClick={() => toggleWeekday(d.v)}
                  >
                    {d.label}
                  </button>
                ))}
              </div>
              <p className="sg-field-hint sg-cfg-sub-label">Heures préférées</p>
              <div className="sg-seg-product-picks">
                {(EDITORIAL_HOUR_OPTIONS || []).map((h) => (
                  <button
                    key={h}
                    type="button"
                    className={`sg-seg-product-pick${hours.includes(h) ? " is-on" : ""}`}
                    onClick={() => toggleHour(h)}
                  >
                    {String(h).padStart(2, "0")} h
                  </button>
                ))}
              </div>
              <p className="sg-field-hint">Fuseau : {pubDefaults.timezone}</p>
              <label className="sg-field-label">Notes de rythme</label>
              <textarea
                className="sg-textarea"
                rows={2}
                placeholder="Ex. pas de publication le week-end, priorité mardi matin…"
                value={pubNotes}
                onChange={(e) => setPubNotes(e.target.value)}
              />
            </section>
          )}

          {step === 3 && (
            <section className="sg-iv-wizard-panel">
              {generating ? (
                <div className="sg-iv-thinking">
                  <img src={POSE.analyse} alt="" className="sg-iv-thinking-img" />
                  <div className="sg-iv-thinking-body">
                    <span className="sg-spinner lg" aria-hidden="true" />
                    <p className="sg-iv-thinking-title">{PLAN_ANALYSIS_MSGS[msgIdx]}</p>
                    <p className="sg-iv-thinking-sub">Génération du calendrier…</p>
                  </div>
                </div>
              ) : result ? (
                <>
                  <p className="sg-set-title">Proposition — 12 semaines</p>
                  <p className="sg-set-sub">{result.summary}</p>
                  {result.publicationInsights ? (
                    <p className="sg-set-sub is-muted-note">{result.publicationInsights}</p>
                  ) : null}
                  {(result.sourcesUsed || []).length > 0 && (
                    <p className="sg-field-hint">Sources : {(result.sourcesUsed || []).join(" · ")}</p>
                  )}
                  {(result.planQuota || editorialQuota) && (
                    <p className="sg-field-hint">
                      Quota appliqué : {(result.planQuota || editorialQuota).articlesPerWeek} art./sem.
                      {(result.planQuota || editorialQuota).interviewsIn12Weeks > 0
                        ? ` · ${(result.planQuota || editorialQuota).interviewsIn12Weeks} interview(s) planifiée(s)`
                        : ""}
                    </p>
                  )}
                  <div className="sg-editorial-timeline sg-editorial-timeline--funnel">
                    {(result.entries || []).map((row, i) => (
                      <EditorialPlanEntry key={`${row.weekLabel}-${i}`} row={row} />
                    ))}
                  </div>
                </>
              ) : null}
            </section>
          )}
        </div>
        <footer className="sg-iv-room-foot">
          <button type="button" className="sg-btn-ghost sm" onClick={goBack} disabled={generating}>
            {step === 0 ? "Annuler" : "← Retour"}
          </button>
          {step < 3 ? (
            <button type="button" className="sg-btn-primary sm" onClick={() => void goNext()}>
              {step === 2 ? "Générer le calendrier" : "Continuer"}
            </button>
          ) : (
            <button
              type="button"
              className="sg-btn-primary sm"
              disabled={generating || saving || !result?.editorialPlanMarkdown}
              onClick={() => void savePlan()}
            >
              {saving ? "Enregistrement…" : "Enregistrer le plan"}
            </button>
          )}
        </footer>
      </div>
    </div>
  );
}

function EditorialPlanEntry({ row, className = "" }) {
  const isInterview = String(row.format || "").toLowerCase() === "interview";
  const week = row.week || row.weekLabel || "—";
  const date =
    row.date ||
    [row.publishDate, row.publishTime].filter(Boolean).join(" · ") ||
    "";
  const intentions =
    row.intentions ||
    (Array.isArray(row.personaIntentions) ? row.personaIntentions.join(", ") : "");
  const event = row.event || row.linkedEvent;
  const priority = row.priority || "P2";
  const intent = row.intent || "Informative";

  return (
    <article
      className={`sg-editorial-entry${isInterview ? " is-interview" : ""}${className ? ` ${className}` : ""}`}
    >
      <aside className="sg-editorial-entry-aside">
        <span className="sg-editorial-week">{week}</span>
        {date ? <span className="sg-editorial-date">{date}</span> : null}
        <span className={`sg-badge plan-p${String(priority).slice(1)}`}>{priority}</span>
      </aside>
      <div className="sg-editorial-entry-body">
        <h4 className="sg-editorial-title">{row.theme || "—"}</h4>
        <div className="sg-editorial-tags">
          {row.format ? (
            <span className={`sg-editorial-format${isInterview ? " is-itw" : ""}`}>{row.format}</span>
          ) : null}
          {row.keyword ? <span className="sg-editorial-kw">{row.keyword}</span> : null}
        </div>
        {row.persona || intentions ? (
          <p className="sg-editorial-persona">
            {row.persona ? <b>{row.persona}</b> : null}
            {row.persona && intentions ? " · " : null}
            {intentions || null}
          </p>
        ) : null}
        {event ? <span className="sg-editorial-event">{event}</span> : null}
        {row.angle ? <p className="sg-editorial-angle">{row.angle}</p> : null}
        <div className="sg-editorial-footer">
          <span className={`sg-badge ${intent === "Commercial" ? "intent-com" : "intent-info"}`}>
            {intent}
          </span>
        </div>
      </div>
    </article>
  );
}

function AssistantPlanScreen({
  onBack,
  plan,
  schedule,
  editorialPlanAllowed = false,
  publicationScheduleAllowed = false,
  planCode = "",
  editorialPlanMarkdown = "",
  editorialQuota,
  personas = [],
  gscConnected = false,
  planLabel = "",
  onOpenFunnel,
  onSavePlan,
  onPlanSaved,
  onSaveSchedule,
  onScheduleSaved,
  busy = false,
}) {
  const isStarterManual = planCode === "starter" || (publicationScheduleAllowed && !editorialPlanAllowed);
  const timeline = plan || EDITORIAL_PLAN;
  const weeksCount = timeline.length;
  const sched = schedule || {};

  const articlesPerWeek = editorialQuota?.articlesPerWeek;
  const stats = [
    {
      label: "Articles / semaine",
      value: articlesPerWeek != null ? String(articlesPerWeek) : "—",
      hint: isStarterManual
        ? "4 articles · lun.–jeu. à 9 h par défaut"
        : editorialQuota
          ? `${editorialQuota.totalBlogEntries12Weeks} entrées blog sur 12 sem.`
          : "Selon votre abonnement",
      icon: "spark",
    },
    {
      label: "Rythme interviews",
      value: editorialQuota?.interviewsIn12Weeks
        ? `${editorialQuota.interviewsIn12Weeks} / 12 sem.`
        : "—",
      hint: editorialQuota?.interviewRhythmLabel || "Non inclus dans le plan",
      icon: "mic",
    },
    {
      label: "Semaines planifiées",
      value: String(weeksCount),
      hint: "Horizon calendrier éditorial",
      icon: "calendar",
    },
    {
      label: "Search Console",
      value: gscConnected ? "Connectée" : "—",
      hint: gscConnected ? "Requêtes utilisées pour les suggestions" : "Connectez la GSC pour affiner",
      icon: "chart",
    },
  ];

  return (
    <div className="sg-screen sg-screen-assistants">
      <PageHeader
        title={<>Plan <span>éditorial</span></>}
        sub={
          isStarterManual
            ? "Plan Starter : calendrier à saisir manuellement et créneaux lun.–jeu. à 9 h par défaut (1 article/jour)."
            : "Calendrier 12 semaines : thématiques, formats, dates, personas, intentions et événements — enrichi par la GSC et vos performances."
        }
      />

      {isStarterManual && (
        <div className="sg-cfg-note">
          <Icon name="calendar" size={16} />
          <span>
            L&apos;assistant IA calendrier est réservé aux plans Pro et Business. Sur Starter, complétez le tableau ci-dessous et activez le planning de publication.
          </span>
        </div>
      )}

      {!editorialPlanAllowed && !publicationScheduleAllowed && (
        <div className="sg-cfg-note">
          <Icon name="spark" size={16} />
          <span>Passez à un plan Starter ou supérieur pour configurer votre plan éditorial et vos créneaux de publication.</span>
        </div>
      )}

      <div className="sg-assistant-stats">
        {stats.map((s) => (
          <div key={s.label} className="sg-assistant-stat">
            <span className="sg-assistant-stat-ic"><Icon name={s.icon} size={18} /></span>
            <div>
              <p className="sg-assistant-stat-val">{s.value}</p>
              <p className="sg-assistant-stat-lab">{s.label}</p>
              <p className="sg-assistant-stat-hint">{s.hint}</p>
            </div>
          </div>
        ))}
      </div>

      <div className="sg-assistant-grid is-2" style={{ marginBottom: "var(--gap)" }}>
        <article className="sg-assistant-card is-rich">
          <div className="sg-assistant-head">
            <span className="sg-assistant-ic"><Icon name="calendar" size={22} /></span>
            <span className="sg-pill is-published">{planLabel || (isStarterManual ? "Starter" : "12 semaines")}</span>
          </div>
          {isStarterManual ? (
            <>
              <h3>Plan éditorial manuel</h3>
              <ManualEditorialPlanPanel
                markdown={editorialPlanMarkdown}
                onSave={onSavePlan}
                onSaved={onPlanSaved}
                busy={busy}
              />
            </>
          ) : (
            <>
              <h3>Générer mon calendrier éditorial</h3>
              <p className="sg-assistant-desc">
                Parcours guidé en 3 étapes puis <strong>synthèse IA</strong> : périodes clés, événements retail,
                créneaux de publication et proposition de contenus sur 12 semaines.
              </p>
              <ul className="sg-assistant-bullets">
                <li><Icon name="check" size={14} /> <span>Personas, intentions et quota du plan</span></li>
                <li><Icon name="check" size={14} /> <span>Saint-Valentin, Noël, Black Friday, vacances…</span></li>
                <li><Icon name="check" size={14} /> <span>GSC + analytics Shopify pour les thèmes</span></li>
              </ul>
              <button
                type="button"
                className="sg-btn-primary sg-assistant-cta"
                disabled={!editorialPlanAllowed}
                onClick={() => onOpenFunnel?.()}
              >
                Lancer l&apos;assistant plan
              </button>
            </>
          )}
        </article>

        <article className="sg-assistant-card is-rich">
          <div className="sg-assistant-head">
            <span className="sg-assistant-ic"><Icon name="gear" size={22} /></span>
            <span className={`sg-pill is-${sched.enabled ? "published" : "draft"}`}>
              {sched.enabled ? (sched.publishWithoutReview ? "100 % auto" : "Relecture") : "Inactif"}
            </span>
          </div>
          <h3>Planning de publication</h3>
          <p className="sg-assistant-desc">
            Choisissez un mode : créneaux avec relecture, ou publication entièrement automatique.
            Les deux options sont mutuellement exclusives.
          </p>
          <PublicationSchedulePanel
            schedule={sched}
            publicationScheduleAllowed={publicationScheduleAllowed}
            editorialPlanAllowed={editorialPlanAllowed}
            editorialQuota={editorialQuota}
            onSaveSchedule={onSaveSchedule}
            onSaved={onScheduleSaved}
            busy={busy}
          />
        </article>
      </div>

      <section className="sg-panel">
        <h3 className="sg-block-title">Vue planning ({weeksCount} entrée{weeksCount > 1 ? "s" : ""})</h3>
        <div className="sg-editorial-timeline">
          {timeline.map((row, i) => (
            <EditorialPlanEntry key={row.week || i} row={row} />
          ))}
        </div>
      </section>

      <button type="button" className="sg-seg-back" onClick={onBack}>← Retour aux assistants</button>
    </div>
  );
}

function GscScreen({ live, onRefresh, busy }) {
  const connected = live?.connected ?? false;
  const email = live?.email || null;
  const properties = live?.properties || [];
  const selectedProperty = live?.selectedPropertyUrl || null;
  // `live` absent = mode démo statique ; sinon toujours les données réelles.
  const queries = live ? (live.queries || []) : GSC_QUERIES;

  const [connecting, setConnecting] = useS(false);
  const [error, setError] = useS("");
  const [pendingProperty, setPendingProperty] = useS("");
  const [selectedQueries, setSelectedQueries] = useS({});
  const [importing, setImporting] = useS(false);
  const [importInfo, setImportInfo] = useS("");
  const [disconnecting, setDisconnecting] = useS(false);

  async function connect() {
    setConnecting(true);
    setError("");
    try {
      const body = await GuyAPI.gscConnectInit();
      if (!body.authUrl) {
        setError("Connexion indisponible pour le moment.");
        setConnecting(false);
        return;
      }
      const popup = window.open(body.authUrl, "gsc-oauth", "popup,width=520,height=680,scrollbars=yes");
      if (!popup) {
        setError("Popup bloquée — autorisez les popups pour ce site puis réessayez.");
        setConnecting(false);
        return;
      }
      const onMessage = (e) => {
        if (typeof e.data === "object" && e.data?.type === "gsc:oauth") {
          window.removeEventListener("message", onMessage);
          setConnecting(false);
          if (e.data.payload?.ok) {
            onRefresh?.();
          } else {
            setError(e.data.payload?.error ? `Échec OAuth : ${e.data.payload.error}` : "Échec OAuth Google.");
          }
        }
      };
      window.addEventListener("message", onMessage);
      const watch = window.setInterval(() => {
        if (popup.closed) {
          window.clearInterval(watch);
          window.removeEventListener("message", onMessage);
          setConnecting(false);
        }
      }, 800);
    } catch (err) {
      setConnecting(false);
      setError(err.message || "Connexion impossible.");
    }
  }

  async function chooseProperty(propertyUrl) {
    setPendingProperty(propertyUrl);
    setError("");
    try {
      await GuyAPI.gscSetProperty(propertyUrl);
      await onRefresh?.();
    } catch (err) {
      setError(err.message || "Sélection impossible.");
    } finally {
      setPendingProperty("");
    }
  }

  async function disconnect() {
    setDisconnecting(true);
    setError("");
    try {
      await GuyAPI.gscDisconnect();
      await onRefresh?.();
    } catch (err) {
      setError(err.message || "Déconnexion impossible.");
    } finally {
      setDisconnecting(false);
    }
  }

  function toggleQuery(query) {
    setSelectedQueries((prev) => ({ ...prev, [query]: !prev[query] }));
    setImportInfo("");
  }

  const selectedCount = Object.values(selectedQueries).filter(Boolean).length;

  async function importSelected() {
    const items = queries
      .filter((q) => selectedQueries[q.query])
      .map((q) => ({
        keyword: q.query,
        clicks: q.clicks,
        impressions: q.impressions,
        position: q.position,
      }));
    if (items.length === 0) return;
    setImporting(true);
    setError("");
    try {
      const res = await GuyAPI.gscAddKeywords({ items });
      setImportInfo(`${res.inserted ?? items.length} mot(s)-clé(s) importé(s).`);
      setSelectedQueries({});
    } catch (err) {
      setError(err.message || "Import impossible.");
    } finally {
      setImporting(false);
    }
  }

  const fmtNum = (v) => (typeof v === "number" ? v.toLocaleString("fr-FR") : v ?? "—");
  const fmtPos = (v) => (typeof v === "number" ? v.toFixed(1) : "—");
  const fmtCtr = (v) => (typeof v === "number" ? `${v.toFixed(1).replace(".", ",")} %` : "—");

  return (
    <div className="sg-screen">
      <PageHeader
        title={<>Google <span>Search Console</span></>}
        sub="Connexion OAuth · sélection de propriété · import de mots-clés · sync métriques articles."
        status={connected ? "Connectée" : "À connecter"}
      />
      {error && <div className="ob-error">{error}</div>}
      {!connected ? (
        <section className="sg-panel sg-gsc-connect">
          <div className="ob-gsc-logo">G</div>
          <div>
            <h3 className="sg-block-title">Connecter votre compte Google</h3>
            <p className="sg-set-sub">Active visites SEO, position moyenne, CTR et opportunités de mots-clés.</p>
            <button type="button" className="sg-btn-primary" disabled={busy || connecting} onClick={connect}>
              {connecting ? (<><span className="sg-spinner sm" /> Connexion…</>) : "Connecter la GSC"}
            </button>
          </div>
        </section>
      ) : (
        <>
          <section className="sg-panel">
            <div className="sg-gsc-account-row">
              <div className="sg-gsc-account-id">
                <div className="ob-gsc-logo">G</div>
                <div>
                  <h3 className="sg-block-title" style={{ margin: 0 }}>Compte Google connecté</h3>
                  {email && <span className="sg-gsc-account-mail">{email}</span>}
                </div>
              </div>
              <button type="button" className="sg-btn-ghost sm" disabled={disconnecting} onClick={disconnect}>
                {disconnecting ? "Déconnexion…" : "Déconnecter"}
              </button>
            </div>
            <h3 className="sg-block-title">
              {selectedProperty ? "Propriété GSC utilisée" : "Propriété GSC à utiliser"}
            </h3>
            {selectedProperty ? (
              <>
                <div className="sg-gsc-properties">
                  <div className="sg-gsc-prop is-active is-locked">
                    <span className="sg-gsc-prop-url">{selectedProperty}</span>
                    <span className="sg-gsc-prop-perm">Verrouillée</span>
                  </div>
                </div>
                <p className="sg-set-sub">
                  Pour changer de propriété, déconnectez le compte Google puis reconnectez-vous.
                </p>
              </>
            ) : properties.length === 0 ? (
              <p className="sg-set-sub">Aucune propriété accessible avec ce compte Google.</p>
            ) : (
              <div className="sg-gsc-properties">
                {properties.map((p) => (
                  <label
                    key={p.siteUrl}
                    className={`sg-gsc-prop${pendingProperty === p.siteUrl ? " is-active" : ""}`}
                  >
                    <input
                      type="radio"
                      name="gsc-property"
                      checked={false}
                      disabled={!!pendingProperty}
                      onChange={() => chooseProperty(p.siteUrl)}
                    />
                    <span className="sg-gsc-prop-url">{p.siteUrl}</span>
                    <span className="sg-gsc-prop-perm">
                      {pendingProperty === p.siteUrl ? "Activation…" : p.permissionLevel}
                    </span>
                  </label>
                ))}
              </div>
            )}
          </section>
          {selectedProperty ? (
            <section className="sg-panel">
              <div className="sg-gsc-head-row">
                <h3 className="sg-block-title">Requêtes Search Console (90 derniers jours)</h3>
                <button type="button" className="sg-btn-primary sm" disabled={selectedCount === 0 || importing} onClick={importSelected}>
                  {importing ? "Import…" : `Importer en mots-clés (${selectedCount})`}
                </button>
              </div>
              {importInfo && <p className="sg-set-sub">{importInfo}</p>}
              {queries.length === 0 ? (
                <p className="sg-set-sub">Aucune requête sur la période pour cette propriété.</p>
              ) : (
                <>
                  <div className="sg-gsc-thead">
                    <span className="sg-gsc-col-q">Requête</span><span>Clics</span><span>Impressions</span><span>CTR</span><span>Position</span>
                  </div>
                  <div className="sg-gsc-list">
                    {queries.map((q) => (
                      <div key={q.query} className="sg-gsc-row">
                        <span className="sg-gsc-col-q sg-gsc-query">
                          <label className="sg-gsc-check">
                            <input
                              type="checkbox"
                              checked={!!selectedQueries[q.query]}
                              onChange={() => toggleQuery(q.query)}
                            />
                            <span>{q.query}</span>
                          </label>
                        </span>
                        <span className="sg-gsc-col-n">{fmtNum(q.clicks)}</span>
                        <span className="sg-gsc-col-n">{fmtNum(q.impressions)}</span>
                        <span className="sg-gsc-col-n">{fmtCtr(q.ctr)}</span>
                        <span className="sg-gsc-col-n">{fmtPos(q.position)}</span>
                      </div>
                    ))}
                  </div>
                </>
              )}
            </section>
          ) : (
            <section className="sg-panel">
              <p className="sg-set-sub">Sélectionnez une propriété pour charger les requêtes Search Console.</p>
            </section>
          )}
        </>
      )}
    </div>
  );
}

const CFG_TARGETS_MAX = 3;
const CFG_PRODUCTS_MAX = 200;
const CFG_INTEREST_MARKER = " · Recherche : ";

function cfgParseAudience(audience) {
  const raw = (audience || "").trim();
  const markerIdx = raw.indexOf("Recherche :");
  let base = raw;
  let interests = [];
  if (markerIdx !== -1) {
    base = raw.slice(0, markerIdx).replace(/[·•|\-\s]+$/, "").trim();
    interests = raw
      .slice(markerIdx + "Recherche :".length)
      .split(",")
      .map((s) => s.trim())
      .filter(Boolean);
  }
  const parts = base.split(/\s*—\s*/).map((p) => p.trim()).filter(Boolean);
  let name = "";
  let description = base;
  if (parts.length >= 2) {
    name = parts[0];
    description = parts.slice(1).join(" — ");
  } else if (parts.length === 1) {
    description = parts[0];
  }
  return { name, description, interests };
}

function cfgTargetToRow(t) {
  const { name, description, interests } = cfgParseAudience(t.audience);
  return {
    name,
    description,
    tone: t.tone || "",
    interests,
    avatarUrl: t.avatarUrl || null,
    sellingPoints: t.sellingPoints || [],
    differentiation: t.differentiation || "",
    preferredProducts: t.preferredProducts || [],
    productFamilies: t.productFamilies || "",
  };
}

function cfgRowToTarget(row) {
  const name = (row.name || "").trim();
  const desc = (row.description || "").trim();
  const tone = (row.tone || "").trim();
  const interests = Array.isArray(row.interests) ? row.interests.filter(Boolean) : [];
  let audience = desc;
  if (name && desc) audience = `${name} — ${desc}`;
  else if (name) audience = name;
  if (!audience) return null;
  if (interests.length) audience = `${audience}${CFG_INTEREST_MARKER}${interests.join(", ")}`;
  const sellingPoints = (row.sellingPoints || []).map((s) => (s || "").trim()).filter(Boolean).slice(0, 3);
  const preferredProducts = (row.preferredProducts || []).map((s) => (s || "").trim()).filter(Boolean).slice(0, 25);
  const differentiation = (row.differentiation || "").trim();
  const productFamilies = (row.productFamilies || "").trim();
  const target = {
    audience,
    tone,
    avatarUrl: row.avatarUrl?.trim() || null,
  };
  if (sellingPoints.length) target.sellingPoints = sellingPoints;
  if (differentiation) target.differentiation = differentiation;
  if (preferredProducts.length) target.preferredProducts = preferredProducts;
  if (productFamilies) target.productFamilies = productFamilies;
  return target;
}

function cfgSignature(cfg) {
  return JSON.stringify({
    t: cfg?.targetAudiences ?? [],
    p: cfg?.featuredProducts ?? [],
    c: cfg?.editorialCharter ?? "",
    w: cfg?.writingPrecautions ?? "",
    r: cfg?.regulatoryReferences ?? "",
    f: cfg?.forbiddenKeywords ?? "",
  });
}

function serializeConfigDraft(personaRows, products, charter, precautions) {
  const cleanTargets = personaRows.map((r) => cfgRowToTarget(r)).filter(Boolean);
  const cleanProducts = (products || [])
    .map((p) => {
      const row = { name: (p.name || "").trim(), url: (p.url || "").trim() };
      const img = (p.imageUrl || "").trim();
      if (/^https?:\/\//i.test(img)) row.imageUrl = img;
      const sid = (p.shopifyProductId || "").trim();
      if (sid) row.shopifyProductId = sid;
      return row;
    })
    .filter((p) => p.name && (p.imageUrl || /^https?:\/\//i.test(p.url)));
  return JSON.stringify({
    targetAudiences: cleanTargets,
    featuredProducts: cleanProducts,
    editorialCharter: (charter || "").trim(),
    writingPrecautions: (precautions || "").trim(),
  });
}

function ConfigScreen({ configuration, onSave, busy, shopifyConnected, wordpressConnected }) {
  const cfg = configuration || {};
  const catalogConnected = !!(shopifyConnected || wordpressConnected);
  const [personaRows, setPersonaRows] = useS(() =>
    (cfg.targetAudiences || []).map((t) => cfgTargetToRow(t)),
  );
  const [products, setProducts] = useS(() => (cfg.featuredProducts || []).map((p) => ({ ...p })));
  const [charter, setCharter] = useS(cfg.editorialCharter || "");
  const [precautions, setPrecautions] = useS(cfg.writingPrecautions || "");
  const [saved, setSaved] = useS(false);
  const [productPhotoBusy, setProductPhotoBusy] = useS(null);
  const [productPhotoErr, setProductPhotoErr] = useS("");

  // Resynchronise quand la config change (ex : après l'assistant ou un enregistrement).
  const sig = cfgSignature(cfg);
  React.useEffect(() => {
    setPersonaRows((cfg.targetAudiences || []).map((t) => cfgTargetToRow(t)));
    setProducts((cfg.featuredProducts || []).map((p) => ({ ...p })));
    setCharter(cfg.editorialCharter || "");
    setPrecautions(cfg.writingPrecautions || "");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sig]);

  function updatePersonaRow(i, patch) {
    setPersonaRows((prev) => prev.map((r, idx) => (idx === i ? { ...r, ...patch } : r)));
  }

  function togglePersonaInterest(i, label) {
    setPersonaRows((prev) =>
      prev.map((r, idx) => {
        if (idx !== i) return r;
        const list = Array.isArray(r.interests) ? r.interests : [];
        const has = list.includes(label);
        return { ...r, interests: has ? list.filter((x) => x !== label) : [...list, label] };
      }),
    );
  }

  function addPersonaRow() {
    if (personaRows.length >= CFG_TARGETS_MAX) return;
    setPersonaRows((prev) => [
      ...prev,
      { name: "", description: "", tone: PERSONA_TONES[0]?.label || "", interests: [], avatarUrl: null },
    ]);
  }

  function removePersonaRow(i) {
    setPersonaRows((prev) => prev.filter((_, idx) => idx !== i));
  }

  function updateTarget(i, field, value) {
    updatePersonaRow(i, { [field]: value });
  }
  function addTarget() {
    addPersonaRow();
  }
  function removeTarget(i) {
    removePersonaRow(i);
  }

  function updateProduct(i, field, value) {
    setProducts((prev) => prev.map((p, idx) => (idx === i ? { ...p, [field]: value } : p)));
  }
  function patchProduct(i, patch) {
    setProducts((prev) => prev.map((p, idx) => (idx === i ? { ...p, ...patch } : p)));
  }
  function addProduct() {
    setProducts((prev) => [...prev, { name: "", url: "", imageUrl: "", shopifyProductId: "" }]);
  }
  function removeProduct(i) {
    setProducts((prev) => prev.filter((_, idx) => idx !== i));
  }

  function catalogProductKey(p) {
    const gid = (p.shopifyProductId || p.id || "").trim();
    if (gid) return `id:${gid.toLowerCase()}`;
    const handle = productHandleFromUrl(p.url);
    if (handle) return `h:${handle}`;
    const name = (p.name || p.title || "").trim().toLowerCase();
    return name ? `n:${name}` : "";
  }

  function mergeCatalogRows(existing, catalog) {
    const out = (existing || []).map((p) => ({ ...p }));
    const indexByKey = {};
    out.forEach((p, i) => {
      const k = catalogProductKey(p);
      if (k && indexByKey[k] == null) indexByKey[k] = i;
    });
    for (const c of catalog || []) {
      const row = {
        name: (c.title || c.name || "").trim().slice(0, 200),
        url: c.url || "",
        imageUrl: c.imageUrl || "",
        shopifyProductId: c.id || "",
      };
      if (!row.name) continue;
      const k = catalogProductKey(row);
      if (k && indexByKey[k] != null) {
        const idx = indexByKey[k];
        if (!out[idx].imageUrl && row.imageUrl) {
          out[idx] = {
            ...out[idx],
            imageUrl: row.imageUrl,
            shopifyProductId: out[idx].shopifyProductId || row.shopifyProductId,
          };
        }
        continue;
      }
      if (out.length >= CFG_PRODUCTS_MAX) break;
      if (k) indexByKey[k] = out.length;
      out.push(row);
    }
    return out.slice(0, CFG_PRODUCTS_MAX);
  }

  function productHandleFromUrl(url) {
    const raw = (url || "").trim();
    if (!raw) return "";
    const m = raw.match(/\/products\/([^/?#]+)/i);
    if (!m) return "";
    try {
      return decodeURIComponent(m[1]).replace(/\/+$/, "").toLowerCase();
    } catch {
      return m[1].replace(/\/+$/, "").toLowerCase();
    }
  }

  function matchCatalogProduct(list, p) {
    const handle = productHandleFromUrl(p.url);
    const gid = (p.shopifyProductId || "").trim();
    const url = (p.url || "").trim().replace(/\/+$/, "").toLowerCase();
    const name = (p.name || "").trim().toLowerCase();
    return (list || []).find((c) => {
      if (gid && c.id && gid === c.id) return true;
      const cHandle = (c.handle || productHandleFromUrl(c.url) || "").toLowerCase();
      if (handle && cHandle && handle === cHandle) return true;
      const cUrl = (c.url || "").trim().replace(/\/+$/, "").toLowerCase();
      const cTitle = (c.title || "").trim().toLowerCase();
      if (url && cUrl && (cUrl === url || cUrl.includes(url) || url.includes(cUrl))) return true;
      return !!(name && cTitle && cTitle === name);
    });
  }

  async function applyShopifyPhoto(i) {
    setProductPhotoErr("");
    setProductPhotoBusy(i);
    try {
      const data = await GuyAPI.shopifyProducts();
      const hit = matchCatalogProduct(data.products || [], products[i]);
      if (!hit?.imageUrl) {
        setProductPhotoErr("Aucune photo catalogue pour ce produit. Importez un packshot ou vérifiez le lien.");
        return;
      }
      patchProduct(i, { imageUrl: hit.imageUrl, shopifyProductId: hit.id || products[i]?.shopifyProductId });
    } catch (e) {
      setProductPhotoErr(e.message || "Catalogue Shopify inaccessible.");
    } finally {
      setProductPhotoBusy(null);
    }
  }

  async function fillShopifyPhotos(opts) {
    const silent = !!(opts && opts.silent);
    if (!silent) setProductPhotoErr("");
    setProductPhotoBusy("all");
    try {
      const data = await GuyAPI.shopifyProducts();
      const list = data.products || [];
      const next = mergeCatalogRows(products, list);
      const changed = JSON.stringify(next) !== JSON.stringify(products);
      setProducts(next);
      if (changed) {
        persistFilledPhotos(next);
        if (!silent) {
          setSaved(true);
          setTimeout(() => setSaved(false), 2500);
        }
      } else if (!silent) {
        setProductPhotoErr(
          list.length
            ? "Le catalogue est déjà à jour."
            : "Aucun produit actif trouvé dans Shopify / WooCommerce.",
        );
      }
    } catch (e) {
      if (!silent) setProductPhotoErr(e.message || "Catalogue inaccessible.");
    } finally {
      setProductPhotoBusy(null);
    }
  }

  const autoPhotoTried = React.useRef(false);
  React.useEffect(() => {
    if (autoPhotoTried.current) return;
    if (!catalogConnected) return;
    autoPhotoTried.current = true;
    fillShopifyPhotos({ silent: true });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [catalogConnected, sig]);

  async function onProductPhotoFile(i, file) {
    if (!file) return;
    setProductPhotoErr("");
    setProductPhotoBusy(i);
    try {
      const dataUrl = await resizeProductRefFile(file);
      const res = await GuyAPI.uploadFeaturedProductImage(dataUrl);
      if (!res.url) throw new Error("Hébergement de la photo impossible.");
      patchProduct(i, { imageUrl: res.url });
    } catch (e) {
      setProductPhotoErr(e.message || "Import de la photo impossible.");
    } finally {
      setProductPhotoBusy(null);
    }
  }

  function nameFromVisualFile(file) {
    const raw = (file.name || "Visuel").replace(/\.[^.]+$/, "");
    const cleaned = raw.replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim();
    if (!cleaned) return "Visuel";
    return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
  }

  async function onBulkVisualFiles(fileList) {
    const files = Array.from(fileList || []).filter((f) =>
      /^image\/(jpeg|jpg|png|webp)$/i.test(f.type),
    );
    if (!files.length) {
      setProductPhotoErr("Choisissez des JPEG, PNG ou WebP.");
      return;
    }
    const room = CFG_PRODUCTS_MAX - products.length;
    if (room <= 0) {
      setProductPhotoErr("Limite atteinte (200 visuels).");
      return;
    }
    const take = files.slice(0, Math.min(10, room));
    setProductPhotoErr("");
    setProductPhotoBusy("bulk");
    const added = [];
    try {
      for (let i = 0; i < take.length; i += 1) {
        setProductPhotoErr(`Import ${i + 1} / ${take.length}…`);
        const file = take[i];
        const dataUrl = await resizeProductRefFile(file);
        const res = await GuyAPI.uploadFeaturedProductImage(dataUrl);
        if (!res.url) throw new Error("Hébergement du visuel impossible.");
        added.push({
          name: nameFromVisualFile(file),
          url: "",
          imageUrl: res.url,
          shopifyProductId: "",
        });
      }
      setProducts((prev) => [...prev, ...added]);
      setProductPhotoErr(
        files.length > take.length
          ? `${take.length} visuels importés (10 maximum à la fois). Renommez-les puis Enregistrer.`
          : `${added.length} visuel${added.length > 1 ? "s" : ""} importé${added.length > 1 ? "s" : ""}. Renommez-les si besoin, puis Enregistrer.`,
      );
    } catch (e) {
      if (added.length) setProducts((prev) => [...prev, ...added]);
      setProductPhotoErr(e.message || "Import des visuels impossible.");
    } finally {
      setProductPhotoBusy(null);
    }
  }

  function persistFilledPhotos(productList) {
    const list = productList || products;
    const cleanProducts = list
      .map((p) => {
        const row = { name: (p.name || "").trim(), url: (p.url || "").trim() };
        const img = (p.imageUrl || "").trim();
        if (/^https?:\/\//i.test(img)) row.imageUrl = img;
        const sid = (p.shopifyProductId || "").trim();
        if (sid) row.shopifyProductId = sid;
        return row;
      })
      .filter((p) => p.name && (p.imageUrl || /^https?:\/\//i.test(p.url)));
    onSave?.({ featuredProducts: cleanProducts });
  }

  function saveWithProducts(productList) {
    const list = productList || products;
    const cleanTargets = personaRows.map((r) => cfgRowToTarget(r)).filter(Boolean);
    const cleanProducts = list
      .map((p) => {
        const row = { name: (p.name || "").trim(), url: (p.url || "").trim() };
        const img = (p.imageUrl || "").trim();
        if (/^https?:\/\//i.test(img)) row.imageUrl = img;
        const sid = (p.shopifyProductId || "").trim();
        if (sid) row.shopifyProductId = sid;
        return row;
      })
      .filter((p) => p.name && (p.imageUrl || /^https?:\/\//i.test(p.url)));
    onSave?.({
      targetAudiences: cleanTargets,
      featuredProducts: cleanProducts,
      editorialCharter: charter,
      writingPrecautions: precautions,
    });
    setSaved(true);
    setTimeout(() => setSaved(false), 2500);
  }

  async function saveAsync() {
    const list = products;
    const cleanTargets = personaRows.map((r) => cfgRowToTarget(r)).filter(Boolean);
    const cleanProducts = list
      .map((p) => {
        const row = { name: (p.name || "").trim(), url: (p.url || "").trim() };
        const img = (p.imageUrl || "").trim();
        if (/^https?:\/\//i.test(img)) row.imageUrl = img;
        const sid = (p.shopifyProductId || "").trim();
        if (sid) row.shopifyProductId = sid;
        return row;
      })
      .filter((p) => p.name && (p.imageUrl || /^https?:\/\//i.test(p.url)));
    await onSave?.({
      targetAudiences: cleanTargets,
      featuredProducts: cleanProducts,
      editorialCharter: charter,
      writingPrecautions: precautions,
    });
    setSaved(true);
    setTimeout(() => setSaved(false), 2500);
  }

  const savedDraft = React.useMemo(
    () =>
      serializeConfigDraft(
        (cfg.targetAudiences || []).map((t) => cfgTargetToRow(t)),
        (cfg.featuredProducts || []).map((p) => ({ ...p })),
        cfg.editorialCharter || "",
        cfg.writingPrecautions || "",
      ),
    [sig],
  );
  const currentDraft = React.useMemo(
    () => serializeConfigDraft(personaRows, products, charter, precautions),
    [personaRows, products, charter, precautions],
  );
  const isDirty = savedDraft !== currentDraft;

  useUnsavedChangesGuard({
    isDirty,
    onSave: saveAsync,
    onDiscard: () => {
      setPersonaRows((cfg.targetAudiences || []).map((t) => cfgTargetToRow(t)));
      setProducts((cfg.featuredProducts || []).map((p) => ({ ...p })));
      setCharter(cfg.editorialCharter || "");
      setPrecautions(cfg.writingPrecautions || "");
    },
  });

  function save() {
    saveWithProducts(products);
  }

  return (
    <div className="sg-screen">
      <PageHeader title={<>Ciblage <span>marketing</span></>} sub="Personas, produits mis en avant, charte éditoriale et précautions." />

      <div className="sg-cfg-note">
        <Icon name="spark" size={16} />
        <span>Ces informations sont préremplies par l'Assistant de démarrage. Modifiez-les ici à tout moment.</span>
      </div>

      <div className="sg-toolbar-inline">
        <button type="button" className="sg-btn-primary sm" disabled={busy} onClick={save}>
          {busy ? "Enregistrement…" : saved ? "Enregistré ✓" : "Enregistrer"}
        </button>
      </div>

      <section className="sg-panel">
        <h3 className="sg-block-title">Clients cibles (personas)</h3>
        <p className="sg-field-hint">Qui visez-vous ? SEO GUY adapte le ton, les intentions éditoriales et les angles à ces audiences.</p>
        <div className="sg-cfg-list sg-cfg-personas">
          {personaRows.length === 0 && (
            <p className="sg-field-hint">Aucune cible définie pour le moment.</p>
          )}
          {personaRows.map((row, i) => (
            <div key={i} className="sg-cfg-persona-card">
              <div className="sg-cfg-persona-head">
                {row.avatarUrl ? (
                  <img src={row.avatarUrl} alt="" className="sg-cfg-persona-photo" />
                ) : (
                  <div className="sg-cfg-persona-photo sg-cfg-persona-photo--empty">
                    {(row.name || "?").slice(0, 1).toUpperCase()}
                  </div>
                )}
                <div className="sg-cfg-persona-fields">
                  <input
                    className="sg-cfg-input"
                    placeholder="Nom (ex. Rebecca)"
                    value={row.name || ""}
                    onChange={(e) => updatePersonaRow(i, { name: e.target.value })}
                  />
                  <textarea
                    className="sg-textarea sg-cfg-persona-desc"
                    rows={2}
                    placeholder="Qui est cette personne ? Besoins, contexte…"
                    value={row.description || ""}
                    onChange={(e) => updatePersonaRow(i, { description: e.target.value })}
                  />
                </div>
                <button type="button" className="sg-cfg-remove" onClick={() => removeTarget(i)} aria-label="Retirer">✕</button>
              </div>
              <p className="sg-field-hint sg-cfg-sub-label">Ce qu'il/elle cherche vraiment</p>
              <div className="sg-cfg-interests">
                {(PERSONA_INTERESTS || []).map((label) => (
                  <button
                    key={label}
                    type="button"
                    className={`sg-cfg-interest${(row.interests || []).includes(label) ? " is-on" : ""}`}
                    onClick={() => togglePersonaInterest(i, label)}
                  >
                    {label}
                  </button>
                ))}
              </div>
              <p className="sg-field-hint sg-cfg-sub-label">Ton pour ce persona</p>
              <div className="ob-tone-seg sg-cfg-tone-seg">
                {(PERSONA_TONES || []).map((t) => (
                  <button
                    key={t.id}
                    type="button"
                    className={`ob-tone-seg-btn${row.tone === t.label ? " is-on" : ""}`}
                    onClick={() => updatePersonaRow(i, { tone: t.label })}
                  >
                    {t.label}
                  </button>
                ))}
              </div>
            </div>
          ))}
        </div>
        {personaRows.length < CFG_TARGETS_MAX && (
          <button type="button" className="sg-cfg-add" onClick={addTarget}>
            <Icon name="plus" size={14} /> Ajouter une cible
          </button>
        )}
      </section>

      <section className="sg-panel">
        <h3 className="sg-block-title">Produits, offres et visuels de référence</h3>
        <p className="sg-field-hint">
          Sans boutique e-commerce : importez jusqu’à 10 photos d’un coup (captures d’écran, vues du local, produits).
          Le nom du fichier devient le nom — renommez-le comme dans vos titres. Le lien de page est facultatif.
          Boutique Shopify ou WooCommerce : jusqu’à 200 produits actifs sont chargés automatiquement, avec leur photo.
        </p>
        <div className="sg-toolbar-inline" style={{ marginBottom: 12, flexWrap: "wrap" }}>
          <label className={`sg-btn-primary sm sg-cfg-product-file${productPhotoBusy != null || busy || products.length >= CFG_PRODUCTS_MAX ? " is-disabled" : ""}`}>
            {productPhotoBusy === "bulk" ? "Import…" : "Importer jusqu’à 10 photos"}
            <input
              type="file"
              accept="image/jpeg,image/png,image/webp"
              multiple
              hidden
              disabled={productPhotoBusy != null || busy || products.length >= CFG_PRODUCTS_MAX}
              onChange={(e) => {
                const list = e.target.files;
                e.target.value = "";
                if (list && list.length) onBulkVisualFiles(list);
              }}
            />
          </label>
          {catalogConnected ? (
            <button
              type="button"
              className="sg-btn-ghost sm"
              disabled={productPhotoBusy != null || busy}
              onClick={fillShopifyPhotos}
            >
              {productPhotoBusy === "all" ? "Récupération…" : "Actualiser le catalogue"}
            </button>
          ) : null}
        </div>
        {productPhotoErr && <p className="sg-field-error">{productPhotoErr}</p>}
        <div className="sg-cfg-list">
          {products.length === 0 && (
            <p className="sg-field-hint">Aucune offre ni visuel pour le moment.</p>
          )}
          {products.map((p, i) => (
            <div key={i} className="sg-cfg-product-card">
              <div className="sg-cfg-product-photo-wrap">
                {p.imageUrl ? (
                  <img src={p.imageUrl} alt="" className="sg-cfg-product-photo" />
                ) : (
                  <div className="sg-cfg-product-photo sg-cfg-product-photo--empty">Visuel</div>
                )}
              </div>
              <div className="sg-cfg-product-fields">
                <div className="sg-cfg-row">
                  <input
                    className="sg-cfg-input"
                    placeholder="Nom (ex. Tableau de bord, Sérum X)"
                    value={p.name || ""}
                    onChange={(e) => updateProduct(i, "name", e.target.value)}
                  />
                  <input
                    className="sg-cfg-input"
                    placeholder="https://… (page de l’offre)"
                    value={p.url || ""}
                    onChange={(e) => updateProduct(i, "url", e.target.value)}
                  />
                  <button type="button" className="sg-cfg-remove" onClick={() => removeProduct(i)} aria-label="Retirer">✕</button>
                </div>
                <input
                  className="sg-cfg-input"
                  placeholder="https://… (URL du screenshot ou de la photo, optionnel)"
                  value={p.imageUrl || ""}
                  onChange={(e) => updateProduct(i, "imageUrl", e.target.value)}
                />
                <div className="sg-cfg-product-photo-actions">
                  {catalogConnected ? (
                    <button
                      type="button"
                      className="sg-btn-ghost sm"
                      disabled={productPhotoBusy != null || busy}
                      onClick={() => applyShopifyPhoto(i)}
                    >
                      {productPhotoBusy === i ? "…" : "Photo catalogue"}
                    </button>
                  ) : null}
                  <label className="sg-btn-ghost sm sg-cfg-product-file">
                    {p.imageUrl ? "Remplacer le visuel" : "Importer un screenshot"}
                    <input
                      type="file"
                      accept="image/jpeg,image/png,image/webp"
                      hidden
                      onChange={(e) => {
                        const file = e.target.files?.[0];
                        e.target.value = "";
                        if (file) onProductPhotoFile(i, file);
                      }}
                    />
                  </label>
                  {p.imageUrl ? (
                    <button
                      type="button"
                      className="sg-btn-ghost sm"
                      disabled={productPhotoBusy != null}
                      onClick={() => patchProduct(i, { imageUrl: "" })}
                    >
                      Retirer
                    </button>
                  ) : null}
                </div>
              </div>
            </div>
          ))}
        </div>
        <button type="button" className="sg-cfg-add" onClick={addProduct}>
          <Icon name="plus" size={14} /> Ajouter une offre ou un visuel
        </button>
      </section>

      <section className="sg-panel">
        <h3 className="sg-block-title">Charte éditoriale</h3>
        <p className="sg-field-hint">Résumé de votre activité, ton, promesses — rédigé par l'assistant, ajustable ici.</p>
        <textarea
          className="sg-textarea"
          rows={4}
          placeholder="Ce que vous vendez, à quelle clientèle, comment vous vous différenciez…"
          value={charter}
          onChange={(e) => setCharter(e.target.value)}
        />
      </section>

      <section className="sg-panel">
        <h3 className="sg-block-title">Précautions rédactionnelles</h3>
        <textarea
          className="sg-textarea"
          rows={3}
          placeholder="Ex. Ne pas citer de concurrents. Toujours sourcer les allégations santé."
          value={precautions}
          onChange={(e) => setPrecautions(e.target.value)}
        />
      </section>

      <section className="sg-panel">
        <h3 className="sg-block-title">Interdits rédactionnels</h3>
        <p className="sg-field-hint">
          Mots-clés, expressions, pack métier et référentiels se gèrent dans Réglages → Interdits rédactionnels.
          {cfg.forbiddenKeywords
            ? " Des expressions interdites sont déjà enregistrées pour ce compte."
            : ""}
        </p>
      </section>
    </div>
  );
}

function billingPlanPrice(plan, cycle) {
  const monthly = plan.monthlyPriceEur ?? 0;
  if (!monthly) return { main: "Gratuit", suffix: "" };
  const yearly = plan.yearlyPriceEur ?? 0;
  const display =
    cycle === "yearly" && yearly > 0
      ? Math.round((yearly / 12) * 10) / 10
      : monthly;
  return { main: `${display} €`, suffix: "/mois" };
}

function billingYearlySave(plans) {
  const list = plans || PLANS;
  const hasPaid = list.some((p) => (p.monthlyPriceEur ?? 0) > 0 && (p.yearlyPriceEur ?? 0) > 0);
  return hasPaid ? 17 : 0;
}

function billingPlanCta(plan) {
  if (plan.pending) return "Confirmation en attente…";
  if (plan.current) return "Plan actif";
  if (plan.code === "discovery") return "Commencer gratuitement";
  return `Choisir ${plan.name}`;
}

function BillingScreen({ plans, current, onSelectPlan, busy }) {
  const [cycle, setCycle] = useS("yearly");
  const [couponCode, setCouponCode] = useS("");
  const planList = (plans || PLANS).filter((p) => p.code !== "business");
  const yearlySave = billingYearlySave(planList);

  async function choosePlan(code) {
    try {
      await onSelectPlan?.(code, cycle, couponCode.trim() || undefined);
    } catch (e) {
      alert(e?.message || "Impossible de changer de plan.");
    }
  }

  return (
    <div className="sg-screen sg-billing-screen">
      <header className="sg-billing-head">
        <div className="sg-billing-head-copy">
          <h1 className="sg-billing-title">Abonnements</h1>
          <p className="sg-billing-sub">
            3 formules · la cadence d&apos;articles change selon le plan · résiliable à tout moment.
          </p>
        </div>
        <div className="sg-billing-cycle" role="group" aria-label="Périodicité de facturation">
          <button
            type="button"
            className={cycle === "yearly" ? "is-active" : ""}
            onClick={() => setCycle("yearly")}
          >
            Annuel {yearlySave > 0 ? <span className="sg-billing-save">−{yearlySave} %</span> : null}
          </button>
          <button
            type="button"
            className={cycle === "monthly" ? "is-active" : ""}
            onClick={() => setCycle("monthly")}
          >
            Mensuel
          </button>
        </div>
      </header>

      <div className="sg-billing-coupon">
        <label htmlFor="sg-billing-coupon">Code promo</label>
        <input
          id="sg-billing-coupon"
          className="sg-input"
          placeholder="Saisissez votre code"
          value={couponCode}
          onChange={(e) => setCouponCode(e.target.value)}
          autoComplete="off"
          spellCheck={false}
        />
        <p>Un code 100 % active le pack choisi sans paiement.</p>
      </div>

      <div className="sg-billing-grid">
        {planList.map((plan) => {
          const price = billingPlanPrice(plan, cycle);
          const isBusiness = plan.code === "business";
          return (
            <article
              key={plan.code}
              className={[
                "sg-billing-card",
                plan.highlighted ? "is-featured" : "",
                plan.current ? "is-current" : "",
                isBusiness ? "is-business" : "",
                `is-${plan.code}`,
              ]
                .filter(Boolean)
                .join(" ")}
            >
              {plan.highlighted && !plan.current ? (
                <span className="sg-billing-badge is-rec">Recommandé</span>
              ) : null}
              {plan.pending ? (
                <span className="sg-billing-badge is-pending-plan">En attente</span>
              ) : null}
              {plan.current ? (
                <span className="sg-billing-badge is-active-plan">Votre plan</span>
              ) : null}

              <div className={`sg-billing-icon is-${plan.code}`}>
                <span>{plan.letter || plan.name[0]}</span>
              </div>
              <h3 className="sg-billing-card-name">{plan.name}</h3>
              <p className="sg-billing-card-sub">{plan.subtitle || plan.tagline}</p>
              <p className="sg-billing-price">
                {price.main}
                {price.suffix ? <span>{price.suffix}</span> : null}
              </p>

              <ul className="sg-billing-features">
                {(plan.features || []).map((feat) => (
                  <li key={feat.label} className={feat.ok ? "is-ok" : "is-no"}>
                    <span className="sg-billing-feat-icon" aria-hidden="true">
                      {feat.ok ? "✓" : "✕"}
                    </span>
                    {feat.label}
                  </li>
                ))}
              </ul>

              <button
                type="button"
                className={`sg-billing-cta is-${plan.code}${plan.current ? " is-active" : ""}${plan.pending ? " is-pending" : ""}`}
                disabled={plan.current || plan.pending || busy}
                onClick={() => choosePlan(plan.code)}
              >
                {plan.current ? <Icon name="check" size={15} /> : null}
                {billingPlanCta(plan)}
              </button>
            </article>
          );
        })}
      </div>

    </div>
  );
}

function accountProfileFrom(account) {
  return {
    companyName: account?.companyName || account?.displayName || "",
    siret: account?.siret || "",
    vatNumber: account?.vatNumber || "",
    billingStreet: account?.billingStreet || "",
    billingPostalCode: account?.billingPostalCode || "",
    billingCity: account?.billingCity || "",
    billingCountry: account?.billingCountry || "France",
  };
}

function AccountScreen({ sites, account, onSelectSite, onLogout, onRefresh, busy }) {
  const siteList = sites || SITES;
  const [newShop, setNewShop] = React.useState("");
  const [profile, setProfile] = React.useState(() => accountProfileFrom(account));
  const [profileInfo, setProfileInfo] = React.useState("");
  const [profileError, setProfileError] = React.useState("");
  const [savingProfile, setSavingProfile] = React.useState(false);
  const [newPassword, setNewPassword] = React.useState("");
  const [newPasswordConfirm, setNewPasswordConfirm] = React.useState("");
  const [passwordInfo, setPasswordInfo] = React.useState("");
  const [passwordError, setPasswordError] = React.useState("");
  const [savingPassword, setSavingPassword] = React.useState(false);

  React.useEffect(() => {
    setProfile(accountProfileFrom(account));
  }, [
    account?.companyName,
    account?.displayName,
    account?.siret,
    account?.vatNumber,
    account?.billingStreet,
    account?.billingPostalCode,
    account?.billingCity,
    account?.billingCountry,
  ]);

  function addShop() {
    const raw = newShop.trim().toLowerCase();
    if (!raw) return;
    const shop = raw.includes(".") ? raw : `${raw}.myshopify.com`;
    const apiBase =
      typeof API_BASE !== "undefined" && API_BASE
        ? API_BASE
        : `http://localhost:${window.SEOGUY_API_PORT || 3000}`;
    window.open(`${apiBase}/auth/login?shop=${encodeURIComponent(shop)}`, "_blank");
  }

  function updateProfileField(key, value) {
    setProfile((prev) => ({ ...prev, [key]: value }));
    setProfileInfo("");
    setProfileError("");
  }

  async function saveProfile(e) {
    if (e?.preventDefault) e.preventDefault();
    setSavingProfile(true);
    setProfileError("");
    setProfileInfo("");
    try {
      await GuyAPI.updateAccountProfile(profile);
      setProfileInfo("Informations enregistrées.");
      await onRefresh?.();
    } catch (err) {
      setProfileError(err.message || "Enregistrement impossible.");
      throw err;
    } finally {
      setSavingProfile(false);
    }
  }

  async function savePassword(e) {
    if (e?.preventDefault) e.preventDefault();
    if (newPassword !== newPasswordConfirm) {
      setPasswordError("Les mots de passe ne correspondent pas.");
      throw new Error("Les mots de passe ne correspondent pas.");
    }
    setSavingPassword(true);
    setPasswordError("");
    setPasswordInfo("");
    try {
      await GuyAPI.changeAccountPassword({
        newPassword,
        newPasswordConfirm,
      });
      setPasswordInfo("Mot de passe mis à jour.");
      setNewPassword("");
      setNewPasswordConfirm("");
    } catch (err) {
      setPasswordError(err.message || "Changement impossible.");
      throw err;
    } finally {
      setSavingPassword(false);
    }
  }

  const savedProfileJson = React.useMemo(
    () => JSON.stringify(accountProfileFrom(account)),
    [
      account?.companyName,
      account?.displayName,
      account?.siret,
      account?.vatNumber,
      account?.billingStreet,
      account?.billingPostalCode,
      account?.billingCity,
      account?.billingCountry,
    ],
  );
  const isProfileDirty = JSON.stringify(profile) !== savedProfileJson;
  const isPasswordDirty = !!(newPassword.trim() || newPasswordConfirm.trim());
  const isDirty = isProfileDirty || isPasswordDirty;

  useUnsavedChangesGuard({
    isDirty,
    onSave: async () => {
      if (isProfileDirty) await saveProfile();
      if (isPasswordDirty) await savePassword();
    },
    onDiscard: () => {
      setProfile(accountProfileFrom(account));
      setNewPassword("");
      setNewPasswordConfirm("");
    },
  });

  const webAccount = typeof onLogout === "function";
  const saving = busy || savingProfile || savingPassword;

  return (
    <div className="sg-screen">
      <PageHeader title="Mon compte" sub="Profil, facturation et boutiques rattachées." status={account?.email} />

      {webAccount && (
        <>
          <section className="sg-panel">
            <div className="sg-account-session">
              <div>
                <h3 className="sg-block-title" style={{ margin: 0 }}>Session</h3>
                <p className="sg-set-sub" style={{ margin: "6px 0 0" }}>{account?.email}</p>
              </div>
              <button type="button" className="sg-btn-ghost sm" disabled={saving} onClick={onLogout}>
                Se déconnecter
              </button>
            </div>
          </section>

          <section className="sg-panel">
            <h3 className="sg-block-title">Société et facturation</h3>
            <p className="sg-set-sub">Ces informations s’appliquent à ce compte web, pour toutes les boutiques rattachées.</p>
            {profileError && <p className="sg-field-error">{profileError}</p>}
            {profileInfo && <p className="sg-set-sub">{profileInfo}</p>}
            <form className="sg-account-form" onSubmit={saveProfile}>
              <label className="sg-field-label">
                Nom de la société
                <input
                  type="text"
                  className="sg-input"
                  value={profile.companyName}
                  onChange={(e) => updateProfileField("companyName", e.target.value)}
                  required
                  disabled={saving}
                />
              </label>
              <label className="sg-field-label">
                Adresse de facturation
                <input
                  type="text"
                  className="sg-input"
                  value={profile.billingStreet}
                  onChange={(e) => updateProfileField("billingStreet", e.target.value)}
                  placeholder="Numéro et rue"
                  disabled={saving}
                />
              </label>
              <div className="sg-account-form-row">
                <label className="sg-field-label">
                  Code postal
                  <input
                    type="text"
                    className="sg-input"
                    value={profile.billingPostalCode}
                    onChange={(e) => updateProfileField("billingPostalCode", e.target.value)}
                    disabled={saving}
                  />
                </label>
                <label className="sg-field-label">
                  Ville
                  <input
                    type="text"
                    className="sg-input"
                    value={profile.billingCity}
                    onChange={(e) => updateProfileField("billingCity", e.target.value)}
                    disabled={saving}
                  />
                </label>
              </div>
              <label className="sg-field-label">
                Pays
                <input
                  type="text"
                  className="sg-input"
                  value={profile.billingCountry}
                  onChange={(e) => updateProfileField("billingCountry", e.target.value)}
                  disabled={saving}
                />
              </label>
              <div className="sg-account-form-row">
                <label className="sg-field-label">
                  N° SIRET
                  <input
                    type="text"
                    className="sg-input"
                    value={profile.siret}
                    onChange={(e) => updateProfileField("siret", e.target.value)}
                    placeholder="14 chiffres"
                    disabled={saving}
                  />
                </label>
                <label className="sg-field-label">
                  N° TVA intracommunautaire
                  <input
                    type="text"
                    className="sg-input"
                    value={profile.vatNumber}
                    onChange={(e) => updateProfileField("vatNumber", e.target.value)}
                    placeholder="FR…"
                    disabled={saving}
                  />
                </label>
              </div>
              <div className="sg-account-form-actions">
                <button type="submit" className="sg-btn-primary sm" disabled={saving || !profile.companyName.trim()}>
                  {savingProfile ? "Enregistrement…" : "Enregistrer"}
                </button>
              </div>
            </form>
          </section>

          <section className="sg-panel">
            <h3 className="sg-block-title">Mot de passe</h3>
            <p className="sg-set-sub">Choisissez un nouveau mot de passe (8 caractères minimum).</p>
            {passwordError && <p className="sg-field-error">{passwordError}</p>}
            {passwordInfo && <p className="sg-set-sub">{passwordInfo}</p>}
            <form className="sg-account-form" onSubmit={savePassword}>
              <div className="sg-account-form-row">
                <label className="sg-field-label">
                  Nouveau mot de passe
                  <input
                    type="password"
                    className="sg-input"
                    autoComplete="new-password"
                    value={newPassword}
                    onChange={(e) => { setNewPassword(e.target.value); setPasswordError(""); setPasswordInfo(""); }}
                    required
                    minLength={8}
                    disabled={saving}
                  />
                </label>
                <label className="sg-field-label">
                  Confirmation
                  <input
                    type="password"
                    className="sg-input"
                    autoComplete="new-password"
                    value={newPasswordConfirm}
                    onChange={(e) => { setNewPasswordConfirm(e.target.value); setPasswordError(""); setPasswordInfo(""); }}
                    required
                    minLength={8}
                    disabled={saving}
                  />
                </label>
              </div>
              <div className="sg-account-form-actions">
                <button type="submit" className="sg-btn-primary sm" disabled={saving || !newPassword}>
                  {savingPassword ? "Mise à jour…" : "Changer le mot de passe"}
                </button>
              </div>
            </form>
          </section>
        </>
      )}

      <section className="sg-panel">
        <h3 className="sg-block-title">Boutiques rattachées</h3>
        <div className="sg-account-list">
          {siteList.map((s) => (
            <div
              key={s.id}
              className={`sg-account-row${s.current ? " is-current" : ""}`}
              onClick={() => onSelectSite?.(s.id)}
              style={{ cursor: onSelectSite ? "pointer" : "default" }}
            >
              <div className="sg-account-main">
                <strong>{s.name}</strong>
                <span>{s.domain}</span>
              </div>
              <div className="sg-account-stats">
                <span>{s.published} publiés</span>
                <span>{s.drafts} brouillons</span>
              </div>
              <div className="sg-account-actions">
                {s.current ? (
                  <span className="sg-hero-pill is-active">Active</span>
                ) : (
                  <button
                    type="button"
                    className="sg-btn-primary sm"
                    onClick={(e) => {
                      e.stopPropagation();
                      onSelectSite?.(s.id);
                    }}
                  >
                    Activer
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
      </section>
      <section className="sg-panel">
        <h3 className="sg-block-title">Ajouter une boutique</h3>
        <p className="sg-block-sub">
          Installez SEO GUY sur une autre boutique Shopify : si l&apos;email
          administrateur correspond à celui de ce compte, elle sera rattachée
          automatiquement (abonnement unique, quota partagé).
        </p>
        <div className="sg-account-add">
          <input
            type="text"
            className="sg-input"
            placeholder="ma-boutique.myshopify.com"
            value={newShop}
            onChange={(e) => setNewShop(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") addShop(); }}
          />
          <button type="button" className="sg-btn-primary sm" disabled={!newShop.trim()} onClick={addShop}>
            Ajouter cette boutique
          </button>
        </div>
      </section>
    </div>
  );
}

Object.assign(window, {
  PerformanceScreen, AssistantsHubScreen, AssistantSegmentScreen, SegmentFunnelModal,
  EditorialPlanFunnelModal, AssistantPlanScreen, ManualEditorialPlanPanel, PublicationSchedulePanel, GscScreen, ConfigScreen, BillingScreen, AccountScreen, Sparkline,
});
