// dashboard-2026.jsx — Vue Dashboard admin/vendeur (iter 9B funnel + KPIs)
//
// Source : design-2026-handoff/iteration-09B-dashboard-funnel.html
//
// Affiche :
//   - 4 stat cards (Total soumissions, Pipeline $, Taux conversion, Panier moyen)
//   - Filtre période (semaine/mois/trimestre/année)
//   - Funnel par statut (brouillon → envoye → accepte/refuse/archive)
//   - Activité récente (5 dernières soumissions)
//
// Exposé : window.Dashboard2026

(function () {
  const { useState, useEffect, useMemo } = React;

  // ============================================================================
  // HELPERS
  // ============================================================================
  function getDateFilterFn(period) {
    const now = new Date();
    const start = new Date(now);
    if (period === "week") start.setDate(now.getDate() - 7);
    else if (period === "month") start.setMonth(now.getMonth() - 1);
    else if (period === "quarter") start.setMonth(now.getMonth() - 3);
    else if (period === "year") start.setFullYear(now.getFullYear() - 1);
    else return () => true;
    return (dateStr) => {
      if (!dateStr) return false;
      const d = new Date(dateStr);
      return d >= start && d <= now;
    };
  }

  function computeStats(submissions, period) {
    const filterFn = getDateFilterFn(period);
    const filtered = submissions.filter(s => filterFn(s.created_at));
    const leads = filtered.filter(s => s.status === "lead").length;
    const total = filtered.length - leads;  // « soumissions » exclut les leads bruts
    const accept = filtered.filter(s => s.status === "accepte").length;
    const refuse = filtered.filter(s => s.status === "refuse").length;
    const envoye = filtered.filter(s => s.status === "envoye").length;
    const brouillon = filtered.filter(s => s.status === "brouillon").length;
    const archive = filtered.filter(s => s.status === "archive").length;
    const pipeline = filtered
      .filter(s => s.status === "envoye" || s.status === "brouillon")
      .reduce((acc, s) => acc + (s.price_total || 0), 0);
    const conversion = (envoye + accept + refuse) > 0
      ? (accept / (envoye + accept + refuse)) * 100
      : 0;
    const acceptValue = filtered.filter(s => s.status === "accepte").reduce((acc, s) => acc + (s.price_total || 0), 0);
    const panierMoyen = accept > 0 ? acceptValue / accept : 0;

    return {
      total, leads, accept, refuse, envoye, brouillon, archive,
      pipeline, conversion, panierMoyen, filtered
    };
  }

  // ============================================================================
  // SPARKLINE (décoratif)
  // ============================================================================
  function Sparkline({ color = "#EA580C", up = true }) {
    const pts = up ? "0,22 14,19 28,20 42,14 56,15 70,9 84,4" : "0,6 14,9 28,7 42,12 56,10 70,16 84,20";
    return (
      <svg className="r5-dash-kpi-spark" viewBox="0 0 84 26" fill="none" preserveAspectRatio="none">
        <polyline points={pts} stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    );
  }

  // ============================================================================
  // LIVE BAR — horloge + date + météo (Open-Meteo) + citation du jour
  // ============================================================================
  function LiveBar() {
    const [now, setNow] = useState(new Date());
    const [weather, setWeather] = useState(null);

    useEffect(() => {
      const id = setInterval(() => setNow(new Date()), 1000);
      return () => clearInterval(id);
    }, []);

    useEffect(() => {
      let mounted = true;
      (async () => {
        try {
          const r = await fetch("https://api.open-meteo.com/v1/forecast?latitude=45.75&longitude=-73.60&current=temperature_2m,weather_code&timezone=America%2FToronto");
          const j = await r.json();
          if (mounted && j && j.current) setWeather({ temp: Math.round(j.current.temperature_2m), code: j.current.weather_code });
        } catch (e) { /* météo non bloquante */ }
      })();
      return () => { mounted = false; };
    }, []);

    const wmo = (code) => {
      if (code == null) return { icon: "☁️", label: "—" };
      if (code === 0) return { icon: "☀️", label: "Dégagé" };
      if (code <= 2) return { icon: "🌤️", label: "Éclaircies" };
      if (code === 3) return { icon: "☁️", label: "Nuageux" };
      if (code <= 48) return { icon: "🌫️", label: "Brouillard" };
      if (code <= 67) return { icon: "🌧️", label: "Pluie" };
      if (code <= 77) return { icon: "🌨️", label: "Neige" };
      if (code <= 82) return { icon: "🌧️", label: "Averses" };
      if (code <= 86) return { icon: "🌨️", label: "Averses de neige" };
      return { icon: "⛈️", label: "Orage" };
    };
    const w = wmo(weather && weather.code);
    const heure = now.toLocaleTimeString("fr-CA", { hour: "2-digit", minute: "2-digit" });
    const date = now.toLocaleDateString("fr-CA", { weekday: "long", day: "numeric", month: "long", year: "numeric" });
    const citation = (window.raycastCitationDuJour && window.raycastCitationDuJour()) || "Prenez le contrôle de votre énergie.";

    return (
      <div style={lb.bar}>
        <svg viewBox="0 0 14 20" style={{ position: "absolute", right: 18, top: -18, width: 120, height: 172, opacity: 0.10, pointerEvents: "none" }} aria-hidden="true">
          <path d="M9 0L0 11.5h5.5L4 20l9-12h-5.5L9 0z" fill="#7cc4fb" />
        </svg>
        <div style={lb.left}>
          <div style={lb.clock}>{heure}</div>
          <div style={lb.date}>{date}</div>
        </div>
        <div style={lb.quote}>« {citation} »</div>
        <div style={lb.weather}>
          <span style={lb.wIcon}>{w.icon}</span>
          <div>
            <div style={lb.wTemp}>{weather ? `${weather.temp} °C` : "—"}</div>
            <div style={lb.wLabel}>Mascouche · {w.label}</div>
          </div>
        </div>
      </div>
    );
  }

  const lb = {
    bar: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 20, flexWrap: "wrap",
           background: "linear-gradient(120deg, #0a1b3d 0%, #0d3a6e 52%, #1763ad 132%)", color: "#fff",
           borderRadius: 18, padding: "22px 26px", marginBottom: 20, position: "relative", overflow: "hidden",
           boxShadow: "0 18px 44px -18px rgba(10,27,61,0.55)" },
    left: { display: "flex", flexDirection: "column" },
    clock: { fontSize: 30, fontWeight: 800, letterSpacing: "0.02em", fontFamily: "'JetBrains Mono', ui-monospace, monospace", lineHeight: 1 },
    date: { fontSize: 12.5, color: "rgba(255,255,255,0.65)", marginTop: 4, textTransform: "capitalize" },
    quote: { flex: 1, textAlign: "center", fontSize: 13.5, fontStyle: "italic", color: "rgba(255,255,255,0.85)", minWidth: 200, padding: "0 10px" },
    weather: { display: "flex", alignItems: "center", gap: 12 },
    wIcon: { fontSize: 30, lineHeight: 1 },
    wTemp: { fontSize: 20, fontWeight: 700, lineHeight: 1 },
    wLabel: { fontSize: 11, color: "rgba(255,255,255,0.6)", marginTop: 3 }
  };

  // ============================================================================
  // PIPELINES GHL — Ventes / Opérations / Nurturing (live, différenciés par couleur)
  //   Ventes = acquisition (bleu) · Opérations = installation/livraison (teal) ·
  //   Nurturing = relance long terme (ambre). Données : /pipelines + /audit/pipeline_health.
  // ============================================================================
  const GHL_PIPES = [
    { key: "VENTES",     id: "iXxbCQTd0UOm3AMcRxIQ", label: "Ventes",     desc: "Acquisition",             color: "#2563EB", grad: "linear-gradient(90deg,#2563EB,#60a5fa)" },
    { key: "OPERATIONS", id: "x0nc5YWySy3G9sUnnBQJ", label: "Opérations", desc: "Installation / livraison", color: "#0d9488", grad: "linear-gradient(90deg,#0d9488,#2dd4bf)" },
    { key: "NURTURING",  id: "5M21a3Px0av4ZJCibeG8", label: "Nurturing",  desc: "Relance long terme",       color: "#d97706", grad: "linear-gradient(90deg,#d97706,#fbbf24)" }
  ];
  function PipelinesGHL() {
    const [data, setData] = useState(null);
    const [err, setErr] = useState(null);
    const [tab, setTab] = useState("VENTES");
    const C = window.RAYCAST_CALC_2026;
    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) pour afficher les pipelines GHL."); return; }
          const base = `https://raycom-ghl-worker.${sub}.workers.dev`;
          const q = `?token=${encodeURIComponent(token)}`;
          const [pl, ph] = await Promise.all([
            fetch(`${base}/pipelines${q}`).then(r => r.json()),
            fetch(`${base}/audit/pipeline_health${q}`).then(r => r.json())
          ]);
          const byStage = (ph && ph.by_stage) || {};
          const out = {};
          GHL_PIPES.forEach(P => {
            const pipe = (pl.pipelines || []).find(p => p.id === P.id)
              || (pl.pipelines || []).find(p => (p.name || "").toUpperCase().indexOf(P.key) >= 0);
            const stages = ((pipe && pipe.stages) || []).map(s => ({
              name: s.name,
              count: (byStage[s.id] || {}).count || 0,
              value: (byStage[s.id] || {}).value || 0
            }));
            out[P.key] = { stages, total: stages.reduce((a, s) => a + s.count, 0), totalValue: stages.reduce((a, s) => a + s.value, 0) };
          });
          if (on) setData(out);
        } catch (e) { if (on) setErr("Worker GHL injoignable."); }
      })();
      return () => { on = false; };
    }, []);
    const P = GHL_PIPES.find(x => x.key === tab);
    const cur = data && data[tab];
    const max = cur ? Math.max(1, ...cur.stages.map(s => s.count)) : 1;
    return (
      <div className="r5-dash-card" style={{ borderTop: `3px solid ${P.color}` }}>
        <div className="r5-dash-card-head">
          <h2 className="r5-dash-card-title">Pipelines GHL <span style={{ color: P.color }}>· {P.label}</span></h2>
          <span className="r5-dash-card-meta">{cur ? `${cur.total} opp · ${C ? C.fmtCAD0(cur.totalValue) : cur.totalValue}` : "CRM live"}</span>
        </div>
        <div style={{ display: "flex", gap: 6, padding: "0 4px 12px" }}>
          {GHL_PIPES.map(x => (
            <button key={x.key} onClick={() => setTab(x.key)} title={x.desc}
              style={{ flex: 1, padding: "7px 6px", borderRadius: 8, border: `1px solid ${tab === x.key ? x.color : "#e2e8f0"}`,
                cursor: "pointer", fontSize: 12, fontWeight: 700, transition: "all .12s",
                background: tab === x.key ? x.color : "#fff", color: tab === x.key ? "#fff" : "#64748b" }}>
              {x.label}
            </button>
          ))}
        </div>
        <div style={{ padding: "0 4px 2px" }}>
          {err ? (
            <div style={{ textAlign: "center", padding: "16px 0", color: "var(--r5-ink-4)", fontSize: 13 }}>{err}</div>
          ) : !data ? (
            <div style={{ textAlign: "center", padding: "16px 0", color: "var(--r5-ink-4)", fontSize: 13 }}>Chargement des pipelines…</div>
          ) : cur.stages.length === 0 ? (
            <div style={{ textAlign: "center", padding: "16px 0", color: "var(--r5-ink-4)", fontSize: 13 }}>Aucune étape</div>
          ) : cur.stages.map((s, i) => (
            <div key={i} style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
              <div style={{ width: 150, minWidth: 96, fontSize: 12, color: "#475569", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }} title={s.name}>{s.name}</div>
              <div style={{ flex: 1, background: "#eef2f7", borderRadius: 6, height: 22 }}>
                <div style={{ width: `${Math.max(5, (s.count / max) * 100)}%`, background: P.grad, height: "100%", borderRadius: 6, minWidth: 4 }} />
              </div>
              <div style={{ width: 30, textAlign: "right", fontSize: 13, fontWeight: 700, color: "#0f172a" }}>{s.count}</div>
              <div style={{ width: 86, textAlign: "right", fontSize: 12, color: "#64748b" }}>{C ? C.fmtCAD0(s.value) : s.value}</div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ============================================================================
  // MAIN DASHBOARD COMPONENT — V5
  // ============================================================================
  function Dashboard2026({ onOpen, onNew, profile }) {
    const [period, setPeriod] = useState("month");
    const [submissions, setSubmissions] = useState([]);
    const [loading, setLoading] = useState(true);
    const C = window.RAYCAST_CALC_2026;

    useEffect(() => {
      let mounted = true;
      (async () => {
        setLoading(true);
        try {
          if (window.RaycastDB) {
            const data = await window.RaycastDB.listSubmissions({});
            if (mounted) setSubmissions(data || []);
          }
        } catch (e) {
          console.error("[dashboard-2026]", e);
        } finally {
          if (mounted) setLoading(false);
        }
      })();
      return () => { mounted = false; };
    }, []);

    const stats = useMemo(() => computeStats(submissions, period), [submissions, period]);
    const signedValue = useMemo(
      () => stats.filtered.filter(s => s.status === "accepte").reduce((a, s) => a + (s.price_total || 0), 0),
      [stats]
    );

    const periodLabel = { week: "7 derniers jours", month: "30 derniers jours", quarter: "3 derniers mois", year: "12 derniers mois" }[period];
    const greeting = (() => {
      const h = new Date().getHours();
      return h < 12 ? "Bonjour" : h < 18 ? "Bon après-midi" : "Bonsoir";
    })();
    const sellerName = (profile?.name || "").split(" ")[0] || "vendeur";

    // Funnel : 4 stages décroissants
    const sent = stats.envoye + stats.accept + stats.refuse; // tout ce qui a quitté brouillon
    const decided = stats.accept + stats.refuse;
    const funnelStages = [
      { name: "Créées", count: stats.total, cls: "", conv: 100 },
      { name: "Envoyées", count: sent, cls: "stage-2", conv: stats.total > 0 ? Math.round(sent / stats.total * 100) : 0 },
      { name: "Décidées", count: decided, cls: "stage-3", conv: sent > 0 ? Math.round(decided / sent * 100) : 0 },
      { name: "Acceptées", count: stats.accept, cls: "stage-4", conv: decided > 0 ? Math.round(stats.accept / decided * 100) : 0 }
    ];
    const funnelMax = Math.max(1, stats.total);

    // Soumissions récentes
    const recent = [...stats.filtered]
      .sort((a, b) => new Date(b.updated_at || b.created_at) - new Date(a.updated_at || a.created_at))
      .slice(0, 7);
    const statusMap = {
      brouillon: { cls: "draft", label: "Brouillon" },
      envoye:    { cls: "sent", label: "Envoyée" },
      accepte:   { cls: "accepted", label: "Acceptée" },
      refuse:    { cls: "refused", label: "Refusée" },
      archive:   { cls: "draft", label: "Archivée" }
    };
    const typeLabel = { solaire: "Solaire", solaire_batterie: "Solaire+Batt", batterie: "Tout-en-un", borne: "Borne VÉ" };

    return (
      <div>
        <LiveBar />
        <div className="r5-dash-head">
          <div>
            <div className="r5-dash-eyebrow"><span className="r5-dot" style={{ display: "inline-block", width: 6, height: 6, borderRadius: 3, background: "var(--r5-primary)", marginRight: 6 }}></span>Cockpit · {periodLabel}</div>
            <h1>{greeting}, {sellerName}.</h1>
            <p>{loading ? "Chargement des soumissions…" : `${stats.total} soumission(s) sur la période · pipeline ${C.fmtCAD0(stats.pipeline)}.`}</p>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <div className="r5-dash-filter">
              {["week", "month", "quarter", "year"].map(p => (
                <button key={p} className={period === p ? "selected" : ""} onClick={() => setPeriod(p)}>
                  {{ week: "Semaine", month: "Mois", quarter: "Trimestre", year: "Année" }[p]}
                </button>
              ))}
            </div>
            {onNew && (
              <button className="r5-btn r5-btn-primary" onClick={onNew}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14"/></svg>
                Nouvelle soumission
              </button>
            )}
          </div>
        </div>

        <div className="r5-dash">
          {/* KPI ROW */}
          <div className="r5-dash-kpi-row">
            <div className="r5-dash-kpi hero">
              <div className="r5-dash-kpi-eyebrow">Valeur signée</div>
              <div className="r5-dash-kpi-value">{C.fmtNum(signedValue)}<small>$</small></div>
              <div className="r5-dash-kpi-meta">{stats.accept} contrat(s) accepté(s)</div>
              <Sparkline color="#EA580C" up={true} />
            </div>
            <div className="r5-dash-kpi primary">
              <div className="r5-dash-kpi-eyebrow">Pipeline en cours</div>
              <div className="r5-dash-kpi-value">{C.fmtNum(stats.pipeline)}<small>$</small></div>
              <div className="r5-dash-kpi-meta">{stats.brouillon} brouillon(s) · {stats.envoye} envoyée(s)</div>
              <Sparkline color="#2563EB" up={true} />
            </div>
            <div className="r5-dash-kpi success">
              <div className="r5-dash-kpi-eyebrow">Taux de conversion</div>
              <div className="r5-dash-kpi-value">{stats.conversion.toFixed(1).replace(".", ",")}<small>%</small></div>
              <div className="r5-dash-kpi-meta">{stats.accept} acceptées / {stats.accept + stats.refuse + stats.envoye} décidables</div>
            </div>
            <div className="r5-dash-kpi">
              <div className="r5-dash-kpi-eyebrow">Panier moyen</div>
              <div className="r5-dash-kpi-value">{C.fmtNum(stats.panierMoyen)}<small>$</small></div>
              <div className="r5-dash-kpi-meta">par contrat accepté</div>
            </div>
            <div className="r5-dash-kpi">
              <div className="r5-dash-kpi-eyebrow">Leads à rappeler</div>
              <div className="r5-dash-kpi-value">{C.fmtNum(stats.leads)}</div>
              <div className="r5-dash-kpi-meta">captés via LP / formulaire</div>
            </div>
          </div>

          {/* MAIN GRID */}
          <div className="r5-dash-grid">
            <div>
              {/* FUNNEL */}
              <div className="r5-dash-card">
                <div className="r5-dash-card-head">
                  <h2 className="r5-dash-card-title">Funnel des soumissions</h2>
                  <span className="r5-dash-card-meta">{stats.total} au total</span>
                </div>
                <div className="r5-funnel-body">
                  {stats.total === 0 ? (
                    <div style={{ textAlign: "center", padding: "20px 0", color: "var(--r5-ink-4)", fontSize: 14 }}>
                      Aucune soumission sur la période — <button onClick={onNew} style={{ background: "none", border: 0, color: "var(--r5-primary)", fontWeight: 600, cursor: "pointer" }}>créer la première</button>
                    </div>
                  ) : (
                    <div className="r5-funnel">
                      {funnelStages.map((st, i) => (
                        <div className="r5-funnel-stage" key={i}>
                          <div className="r5-funnel-bar-wrap">
                            <div className={`r5-funnel-bar ${st.cls}`} style={{ width: `${Math.max(12, (st.count / funnelMax) * 100)}%` }}>
                              <span className="r5-funnel-bar-name">{st.name}</span>
                              <span className="r5-funnel-bar-count">{st.count}</span>
                            </div>
                          </div>
                          <div className="r5-funnel-conv"><strong>{st.conv}</strong> %</div>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              </div>

              {/* PIPELINES GHL — Ventes / Opérations / Nurturing (retransmis du CRM, différenciés) */}
              <PipelinesGHL />

              {/* RECENT SUBMISSIONS */}
              <div className="r5-dash-card">
                <div className="r5-dash-card-head">
                  <h2 className="r5-dash-card-title">Soumissions récentes</h2>
                  <span className="r5-dash-card-meta">7 dernières</span>
                </div>
                <div>
                  {recent.length === 0 ? (
                    <div style={{ padding: "28px 22px", textAlign: "center", color: "var(--r5-ink-4)", fontSize: 13 }}>
                      Aucune activité pour la période
                    </div>
                  ) : recent.map(s => {
                    const sm = statusMap[s.status] || statusMap.brouillon;
                    return (
                      <button key={s.id} type="button" className="r5-subm-row" onClick={() => onOpen?.(s.id)}>
                        <span className="r5-subm-num">{s.number || "—"}</span>
                        <span className="r5-subm-client">{s.client_name || "Client"}<small>{(typeLabel[s.project_type] || s.project_type || "—")} · {s.client_city || "—"}</small></span>
                        <span className="r5-subm-amount">{C.fmtCAD0(s.price_total || 0)}</span>
                        <span><span className={`r5-subm-status ${sm.cls}`}>{sm.label}</span></span>
                      </button>
                    );
                  })}
                </div>
              </div>
            </div>

            {/* SIDEBAR */}
            <aside>
              <div className="r5-dash-quick">
                <div className="r5-dash-quick-title">Mode kiosque</div>
                <div className="r5-dash-quick-desc">Lance une nouvelle soumission plein écran pour présenter directement au client.</div>
                <button className="r5-dash-quick-btn" onClick={onNew}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14"/></svg>
                  Nouvelle soumission
                </button>
              </div>

              {/* Recommandations dynamiques */}
              {stats.envoye > 3 && stats.conversion < 50 && (
                <div className="r5-rec-card">
                  <div className="r5-rec-head"><div className="r5-rec-eyebrow">Relance</div><div className="r5-rec-title">Conversion {stats.conversion.toFixed(0)} % — {stats.envoye} en attente</div></div>
                  <div className="r5-rec-body">Plusieurs soumissions envoyées sans réponse. Un suivi téléphonique aux clients les plus anciens peut débloquer des signatures.</div>
                </div>
              )}
              {stats.brouillon > 5 && (
                <div className="r5-rec-card">
                  <div className="r5-rec-head"><div className="r5-rec-eyebrow">Pipeline</div><div className="r5-rec-title">{stats.brouillon} brouillons en attente</div></div>
                  <div className="r5-rec-body">Finalise ou archive les brouillons anciens pour garder le pipeline propre et lisible.</div>
                </div>
              )}
              {stats.accept > 0 && (
                <div className="r5-rec-card">
                  <div className="r5-rec-head"><div className="r5-rec-eyebrow">Performance</div><div className="r5-rec-title">{stats.accept} contrat(s) signé(s)</div></div>
                  <div className="r5-rec-body">Panier moyen {C.fmtCAD0(stats.panierMoyen)} sur la période. Beau travail — continue sur cette lancée.</div>
                </div>
              )}
              {stats.total === 0 && !loading && (
                <div className="r5-rec-card">
                  <div className="r5-rec-head"><div className="r5-rec-eyebrow">Démarrage</div><div className="r5-rec-title">Aucune donnée encore</div></div>
                  <div className="r5-rec-body">Crée une première soumission pour activer les KPI, le funnel et les recommandations.</div>
                </div>
              )}
            </aside>
          </div>
        </div>
      </div>
    );
  }

  window.Dashboard2026 = Dashboard2026;
})();
