// analytics-2026.jsx — Section Analytics du dashboard RAYCAST
//
// Agrège en direct les données des Workers Cloudflare maison (lecture seule) :
//   GA4 + Search Console + Google Ads + GMB (raycom-google-worker)
//   PageSpeed/SEO (raycom-seo-worker) · Meta/Instagram (raycom-meta-worker)
//   Pipeline CRM (raycom-ghl-worker)
//
// Config (sous-domaine workers.dev + token partagé) saisie une fois, gardée dans
// localStorage. Aucune clé en dur. Tout échec d'un endpoint est « gracieux »
// (la carte affiche — au lieu de planter).
//
// Exposé : window.Analytics2026

(function () {
  const { useState, useEffect, useCallback } = React;
  const LS_KEY = "raycast_analytics_cfg";
  // Seule campagne active (« Pub Powerwall avec Isa ») — les autres sont archivées.
  // On filtre les chiffres Meta sur ELLE pour ne pas polluer avec l'historique.
  const ISA_CAMPAIGN = "120247308809130472";

  function loadCfg() {
    try { return JSON.parse(localStorage.getItem(LS_KEY)) || {}; } catch { return {}; }
  }
  function saveCfg(cfg) { localStorage.setItem(LS_KEY, JSON.stringify(cfg)); }

  // Premier nombre trouvé parmi une liste de chemins possibles (robuste aux schémas).
  function pick(obj, paths) {
    for (const p of paths) {
      const v = p.split(".").reduce((o, k) => (o == null ? o : o[k]), obj);
      if (v !== undefined && v !== null && v !== "") return v;
    }
    return null;
  }
  function fmt(v, kind) {
    if (v === null || v === undefined || Number.isNaN(Number(v))) return "—";
    const n = Number(v);
    if (kind === "money") return n.toLocaleString("fr-CA", { style: "currency", currency: "CAD", maximumFractionDigits: 0 });
    if (kind === "pct") return (n <= 1 ? n * 100 : n).toFixed(1) + " %";
    if (kind === "int") return Math.round(n).toLocaleString("fr-CA");
    return String(v);
  }
  // Traduit une erreur worker brute en message clair + actionnable
  function friendlyErr(e) {
    const s = String(e || "");
    if (/invalid_grant|OAuth|refresh failed|unauthorized|401|403/i.test(s)) return "🔌 Reconnexion Google requise";
    if (/429|quota/i.test(s)) return "⏳ Quota atteint — réessayer demain";
    if (/META|access token|fb/i.test(s) && /token|expir|invalid/i.test(s)) return "🔌 Reconnexion Meta requise";
    if (/5\d\d|timeout|network/i.test(s)) return "⚠️ Service momentanément indisponible";
    return s.slice(0, 60);
  }

  // KPI ORDONNÉS PAR IMPORTANCE (100% ventes/marketing — aucune finance) :
  //   leads → pipeline → dépense pub → web → SEO → local → Google Ads → vitesse.
  const METRICS = [
    { key: "mpower_leads", worker: "ghl", path: "/contacts?source=Mpower", label: "Leads MPOWER (distributeur)", icon: "users",
      pick: (d) => (d && typeof d.count === "number") ? d.count : null, kind: "int" },
    { key: "pipe_value", worker: "ghl", path: "/audit/pipeline_health", label: "Pipeline ouvert", icon: "folder",
      pick: (d) => pick(d, ["summary.total_value", "openValue", "pipelineValue", "totalValue", "summary.openValue"]), kind: "money" },
    { key: "pipe_count", worker: "ghl", path: "/audit/pipeline_health", label: "Opportunités ouvertes", icon: "layers",
      pick: (d) => pick(d, ["summary.total_open", "openCount", "openOpportunities", "count", "summary.openCount"]), kind: "int" },
    { key: "ga_conv", worker: "google", path: "/ga4/summary", label: "Conversions (GA4)", icon: "check",
      pick: (d) => pick(d, ["metrics.conversions", "conversions", "summary.conversions", "data.conversions"]), kind: "int" },
    { key: "gsc_clicks", worker: "google", path: "/search-console/summary", label: "Clics Google (SEO)", icon: "search",
      pick: (d) => pick(d, ["metrics.clicks", "clicks", "summary.clicks", "data.clicks", "totals.clicks"]), kind: "int" },
    { key: "ga_sessions", worker: "google", path: "/ga4/summary", label: "Sessions (GA4)", icon: "trending-up",
      pick: (d) => pick(d, ["metrics.sessions", "sessions", "summary.sessions", "data.sessions", "totals.sessions"]), kind: "int" },
    { key: "gsc_pos", worker: "google", path: "/search-console/summary", label: "Position moy.", icon: "bar-chart",
      pick: (d) => pick(d, ["metrics.avg_position", "metrics.position", "position", "summary.position", "avgPosition"]), kind: "num" },
    { key: "gmb_calls", worker: "google", path: "/gmb/performance", label: "Appels fiche GMB", icon: "phone",
      pick: (d) => pick(d, ["metrics.calls", "metrics.call_clicks", "calls", "callClicks", "summary.calls", "data.calls"]), kind: "int" },
    { key: "ads_conv", worker: "google", path: "/google-ads/summary", label: "Conv. Google Ads", icon: "target",
      pick: (d) => pick(d, ["metrics.conversions", "conversions", "summary.conversions", "data.conversions"]), kind: "int" },
    { key: "ads_cost", worker: "google", path: "/google-ads/summary", label: "Coût Google Ads", icon: "dollar",
      pick: (d) => pick(d, ["metrics.cost", "metrics.cost_micros", "cost", "costMicros", "summary.cost", "data.cost"]), kind: "money" },
    { key: "psi", worker: "seo", path: "/pagespeed", label: "PageSpeed", icon: "zap",
      pick: (d) => pick(d, ["metrics.score", "score", "performance", "lighthouse.categories.performance.score", "lighthouse.performance", "data.score"]), kind: "int" },
  ];

  // 1er tableau exploitable d'une réponse (défensif vs schémas variés).
  function firstArray(obj) {
    if (Array.isArray(obj)) return obj;
    if (obj && typeof obj === "object") {
      for (const k of ["rows", "data", "items", "sources", "queries", "campaigns", "results", "list"]) {
        if (Array.isArray(obj[k])) return obj[k];
      }
      for (const v of Object.values(obj)) if (Array.isArray(v)) return v;
    }
    return [];
  }
  function rowVal(row, keys) {
    if (!row || typeof row !== "object") return null;
    for (const k of keys) if (row[k] !== undefined && row[k] !== null) return row[k];
    return null;
  }

  // Graphiques (endpoints « liste ») — extraction label/valeur défensive.
  const CHARTS = [
    { worker: "google", path: "/ga4/sources", title: "Trafic par source (GA4)", color: "#2563eb",
      labelKeys: ["source", "channel", "sessionSource", "name", "dimension"], valueKeys: ["sessions", "users", "value", "count"], kind: "int" },
    { worker: "google", path: "/search-console/queries", title: "Top requêtes Google (SEO)", color: "#10b981",
      labelKeys: ["query", "keyword", "term", "name"], valueKeys: ["clicks", "impressions", "value"], kind: "int" },
    { worker: "google", path: "/google-ads/campaigns", title: "Campagnes Google Ads (coût)", color: "#f59e0b",
      labelKeys: ["name", "campaign", "campaignName"], valueKeys: ["cost", "costMicros", "spend", "clicks"], kind: "money" },
    // (Ventilations Meta âge/genre · régions · placements · appareils → composant MetaDetail dédié, plus haut)
  ];

  function BarChart({ rows, color, kind }) {
    if (!rows || rows.length === 0) return <div style={styles.chartEmpty}>aucune donnée</div>;
    const max = Math.max(...rows.map((r) => Number(r.value) || 0), 1);
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
        {rows.slice(0, 8).map((r, i) => (
          <div key={i} style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ width: 130, fontSize: 12, color: "#475569", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={r.label}>{r.label || "—"}</div>
            <div style={{ flex: 1, background: "#f1f5f9", borderRadius: 6, height: 22 }}>
              <div style={{ width: ((Number(r.value) || 0) / max * 100) + "%", background: color, height: "100%", borderRadius: 6, minWidth: 2 }} />
            </div>
            <div style={{ width: 84, textAlign: "right", fontSize: 12, fontWeight: 700, color: "#0f172a" }}>{fmt(r.value, kind)}</div>
          </div>
        ))}
      </div>
    );
  }

  function workerUrl(cfg, worker, path) {
    const sub = (cfg.subdomain || "proud-leaf-b313").trim();
    const name = { google: "raycom-google-worker", seo: "raycom-seo-worker", meta: "raycom-meta-worker", ghl: "raycom-ghl-worker" }[worker];
    const u = new URL(`https://${name}.${sub}.workers.dev${path}`);
    if (cfg.token) u.searchParams.set("token", cfg.token);
    if (worker === "seo" && path === "/pagespeed") u.searchParams.set("url", cfg.site || "https://raycomelectrique.com");
    return u.toString();
  }

  // ── Meta — détail COMPLET de la campagne active (Isa) : KPIs ordonnés + 4 ventilations ──
  function MetaDetail() {
    const ISA = "120247308809130472";
    const [d, setD] = useState(null);
    const [err, setErr] = useState(null);
    useEffect(() => {
      let on = true;
      (async () => {
        try {
          const cfg = (window.RaycastDB && window.RaycastDB.getAppSetting) ? await window.RaycastDB.getAppSetting("analytics") : null;
          const sub = (cfg && cfg.subdomain) || "proud-leaf-b313";
          const token = cfg && cfg.token;
          if (!token) { if (on) setErr("Configure les Analytics (token)."); return; }
          const base = `https://raycom-meta-worker.${sub}.workers.dev`;
          const q = `token=${encodeURIComponent(token)}`;
          const bd = (b) => fetch(`${base}/ads/breakdown?${q}&campaign_id=${ISA}&breakdown=${b}`).then(r => r.json()).then(j => j.segments || []).catch(() => []);
          const [camps, ag, reg, plc, dev] = await Promise.all([
            fetch(`${base}/ads/campaigns?${q}&days=30`).then(r => r.json()).catch(() => ({})),
            bd("age_gender"), bd("region"), bd("placement"), bd("device")
          ]);
          const isa = ((((camps || {}).campaigns) || []).find((c) => String(c.id) === ISA)) || {};
          if (on) setD({ isa, ag, reg, plc, dev });
        } catch (e) { if (on) setErr("Worker Meta injoignable."); }
      })();
      return () => { on = false; };
    }, []);
    const I = (d && d.isa) || {};
    const n = (v) => Number(v || 0);
    const impr = n(I.impressions), clk = n(I.clicks), sp = n(I.spend), rch = n(I.reach), lds = n(I.leads);
    const fmtK = (v, k) => {
      if (v === null || v === undefined || Number.isNaN(Number(v))) return "n/d";
      const x = Number(v);
      if (k === "money") return x.toLocaleString("fr-CA", { style: "currency", currency: "CAD", maximumFractionDigits: 0 });
      if (k === "money2") return x.toLocaleString("fr-CA", { style: "currency", currency: "CAD", minimumFractionDigits: 2, maximumFractionDigits: 2 });
      if (k === "pct") return x.toFixed(1).replace(".", ",") + " %";
      if (k === "freq") return x.toFixed(2).replace(".", ",") + "×";
      return Math.round(x).toLocaleString("fr-CA");
    };
    const kpis = [
      { label: "Leads", val: d ? lds : null, kind: "int", hi: true },
      { label: "Coût / lead", val: lds > 0 ? sp / lds : null, kind: "money2" },
      { label: "Dépense", val: d ? sp : null, kind: "money" },
      { label: "Clics", val: d ? clk : null, kind: "int" },
      { label: "CTR", val: impr > 0 ? (clk / impr) * 100 : null, kind: "pct" },
      { label: "CPC", val: clk > 0 ? sp / clk : null, kind: "money2" },
      { label: "Impressions", val: d ? impr : null, kind: "int" },
      { label: "Portée", val: d ? rch : null, kind: "int" },
      { label: "Fréquence", val: rch > 0 ? impr / rch : null, kind: "freq" }
    ];
    const BD = ({ title, rows, color }) => (
      <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 14, padding: 16 }}>
        <div style={{ fontSize: 13, fontWeight: 700, color: "#0f172a", marginBottom: 12 }}>{title}</div>
        {err ? <div style={{ fontSize: 12, color: "#94a3b8" }}>{err}</div>
          : !d ? <div style={{ fontSize: 12, color: "#94a3b8" }}>chargement…</div>
          : <BarChart rows={(rows || []).map((s) => ({ label: String(s.segment), value: s.clicks }))} color={color} kind="int" />}
      </div>
    );
    return (
      <div style={{ marginBottom: 24 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
          <span style={{ width: 9, height: 9, borderRadius: 5, background: "linear-gradient(135deg,#5cb3f5,#0c4686)" }} />
          <h2 style={{ fontSize: 18, fontWeight: 800, margin: 0, color: "#0a1b3d", letterSpacing: "-0.01em" }}>Meta — Pub Isa · détail complet</h2>
          <span style={{ fontSize: 12, color: "#94a3b8" }}>{err ? "" : !d ? "chargement…" : "30 derniers jours · qui clique"}</span>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(140px, 1fr))", gap: 12, marginBottom: 16 }}>
          {kpis.map((k, i) => (
            <div key={i} style={{ background: k.hi ? "linear-gradient(180deg,#eaf3fc,#fff)" : "#fff", border: `1px solid ${k.hi ? "#bfdbfe" : "#e2e8f0"}`, borderRadius: 12, padding: "12px 14px" }}>
              <div style={{ fontSize: 11.5, color: "#64748b", fontWeight: 600 }}>{k.label}</div>
              <div style={{ fontSize: 22, fontWeight: 800, color: k.hi ? "#1e7fd6" : "#0f172a", marginTop: 4, fontFamily: "'JetBrains Mono',ui-monospace,monospace" }}>{!d ? "…" : fmtK(k.val, k.kind)}</div>
            </div>
          ))}
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: 14 }}>
          <BD title="Qui clique — âge · genre" rows={d && d.ag} color="#1e7fd6" />
          <BD title="Régions" rows={d && d.reg} color="#0d9488" />
          <BD title="Placements" rows={d && d.plc} color="#7c3aed" />
          <BD title="Appareils" rows={d && d.dev} color="#d97706" />
        </div>
      </div>
    );
  }

  function Analytics2026({ profile }) {
    const [cfg, setCfg] = useState(loadCfg());
    const [results, setResults] = useState({});   // path -> {data|error}
    const [loading, setLoading] = useState(false);
    const [showCfg, setShowCfg] = useState(!loadCfg().token);
    const [form, setForm] = useState({ subdomain: cfg.subdomain || "proud-leaf-b313", token: cfg.token || "", site: cfg.site || "https://raycomelectrique.com" });

    const load = useCallback(async (c) => {
      if (!c.token) { setShowCfg(true); return; }
      setLoading(true);
      const paths = [...new Set([...METRICS, ...CHARTS].map((m) => m.worker + "|" + m.path))];
      const out = {};
      await Promise.all(paths.map(async (key) => {
        const [worker, path] = key.split("|");
        try {
          const r = await fetch(workerUrl(c, worker, path), { headers: { "X-Worker-Token": c.token } });
          out[key] = r.ok ? { data: await r.json() } : { error: `HTTP ${r.status}` };
        } catch (e) { out[key] = { error: String(e).slice(0, 80) }; }
      }));
      setResults(out);
      setLoading(false);
    }, []);

    // Charge la config depuis Supabase (partagée, persistée, derrière login) ; repli localStorage.
    useEffect(() => {
      (async () => {
        try {
          if (window.RaycastDB && window.RaycastDB.getAppSetting) {
            const remote = await window.RaycastDB.getAppSetting("analytics");
            if (remote && remote.token) {
              saveCfg(remote); setCfg(remote);
              setForm({ subdomain: remote.subdomain || "proud-leaf-b313", token: remote.token || "", site: remote.site || "https://raycomelectrique.com" });
              setShowCfg(false); load(remote); return;
            }
          }
        } catch (e) { /* repli localStorage */ }
        if (cfg.token) load(cfg);
      })();
    }, []); // eslint-disable-line

    const S = styles;
    return (
      <div style={S.wrap}>
        <div style={S.header}>
          <div>
            <h1 style={S.h1}>Analytics</h1>
            <p style={S.sub}>Marketing &amp; ventes en direct — agrégé par tes Workers Cloudflare</p>
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            <button style={S.btnGhost} onClick={() => load(cfg)} disabled={loading || !cfg.token}>
              {loading ? "Chargement…" : "↻ Rafraîchir"}
            </button>
            <button style={S.btnGhost} onClick={() => setShowCfg((v) => !v)}>⚙︎ Config</button>
          </div>
        </div>

        {showCfg && (
          <div style={S.cfgCard}>
            <div style={S.cfgRow}>
              <label style={S.lbl}>Sous-domaine workers.dev
                <input style={S.input} value={form.subdomain} onChange={(e) => setForm({ ...form, subdomain: e.target.value })} placeholder="proud-leaf-b313" />
              </label>
              <label style={S.lbl}>Token (WORKER_AUTH_TOKEN)
                <input style={S.input} type="password" value={form.token} onChange={(e) => setForm({ ...form, token: e.target.value })} placeholder="colle ton token" />
              </label>
              <label style={S.lbl}>Site (PageSpeed)
                <input style={S.input} value={form.site} onChange={(e) => setForm({ ...form, site: e.target.value })} />
              </label>
            </div>
            <button style={S.btn} onClick={() => { saveCfg(form); setCfg(form); setShowCfg(false); load(form); if (window.RaycastDB && window.RaycastDB.saveAppSetting) window.RaycastDB.saveAppSetting("analytics", form).catch(() => {}); }}>Enregistrer &amp; charger</button>
            <p style={S.hint}>Enregistré dans RAYCAST (Supabase) — saisi <b>une seule fois</b>, retrouvé sur tous tes appareils. Un seul token de lecture, partagé par tous les workers.</p>
          </div>
        )}

        {!cfg.token ? (
          <div style={S.empty}>Configure tes Workers (bouton ⚙︎) pour afficher les données.</div>
        ) : (
          <>
            <MetaDetail />
            <div style={S.grid}>
              {METRICS.map((m) => {
                const res = results[m.worker + "|" + m.path];
                const val = res && res.data ? m.pick(res.data) : null;
                const err = res && res.error;
                return (
                  <div key={m.key} style={S.card}>
                    <div style={S.cardLabel}>{m.label}</div>
                    <div style={S.cardVal}>{loading && !res ? "…" : fmt(val, m.kind)}</div>
                    <div style={S.cardFoot}>{err ? <span style={{ color: "#b45309" }}>{friendlyErr(err)}</span> : (m.worker + m.path)}</div>
                  </div>
                );
              })}
            </div>
            <div style={S.chartGrid}>
              {CHARTS.map((c) => {
                const res = results[c.worker + "|" + c.path];
                const rows = res && res.data
                  ? firstArray(res.data)
                      .map((row) => ({ label: String(rowVal(row, c.labelKeys) ?? ""), value: rowVal(row, c.valueKeys) }))
                      .filter((r) => r.value != null)
                  : [];
                return (
                  <div key={c.title} style={S.chartCard}>
                    <div style={S.chartTitle}>{c.title}</div>
                    {res && res.error
                      ? <div style={S.chartEmpty}>{friendlyErr(res.error)}</div>
                      : (loading && !res ? <div style={S.chartEmpty}>chargement…</div> : <BarChart rows={rows} color={c.color} kind={c.kind} />)}
                  </div>
                );
              })}
            </div>
          </>
        )}
      </div>
    );
  }

  const styles = {
    wrap: { padding: "32px 40px", maxWidth: 1200, margin: "0 auto" },
    header: { display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24, flexWrap: "wrap", gap: 12 },
    h1: { fontSize: 28, fontWeight: 800, margin: 0, letterSpacing: "-0.02em" },
    sub: { color: "#64748b", margin: "4px 0 0", fontSize: 14 },
    btn: { background: "#2563eb", color: "#fff", border: 0, borderRadius: 10, padding: "10px 16px", fontWeight: 600, cursor: "pointer" },
    btnGhost: { background: "#fff", color: "#0f172a", border: "1px solid #e2e8f0", borderRadius: 10, padding: "9px 14px", fontWeight: 600, cursor: "pointer" },
    cfgCard: { background: "#f8fafc", border: "1px solid #e2e8f0", borderRadius: 14, padding: 20, marginBottom: 24 },
    cfgRow: { display: "flex", gap: 16, flexWrap: "wrap", marginBottom: 12 },
    lbl: { display: "flex", flexDirection: "column", gap: 6, fontSize: 12, fontWeight: 600, color: "#475569", flex: "1 1 240px" },
    input: { padding: "9px 12px", border: "1px solid #cbd5e1", borderRadius: 8, fontSize: 14, fontFamily: "inherit" },
    hint: { fontSize: 12, color: "#94a3b8", marginTop: 10 },
    empty: { padding: 48, textAlign: "center", color: "#94a3b8", background: "#f8fafc", borderRadius: 14, border: "1px dashed #cbd5e1" },
    grid: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", gap: 16 },
    card: { background: "#fff", border: "1px solid #e2e8f0", borderRadius: 14, padding: 18, boxShadow: "0 1px 2px rgba(0,0,0,0.04)" },
    cardLabel: { fontSize: 13, color: "#64748b", fontWeight: 600 },
    cardVal: { fontSize: 30, fontWeight: 800, margin: "6px 0 8px", letterSpacing: "-0.02em", color: "#0f172a" },
    cardFoot: { fontSize: 11, color: "#cbd5e1", fontFamily: "monospace" },
    chartGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(420px, 1fr))", gap: 16, marginTop: 20 },
    chartCard: { background: "#fff", border: "1px solid #e2e8f0", borderRadius: 14, padding: 18, boxShadow: "0 1px 2px rgba(0,0,0,0.04)" },
    chartTitle: { fontSize: 14, fontWeight: 700, color: "#0f172a", marginBottom: 14 },
    chartEmpty: { fontSize: 13, color: "#94a3b8", padding: "16px 0" },
  };

  window.Analytics2026 = Analytics2026;
})();
