/* Shared UI primitives + app chrome. Exported to window. */

const fmtEur = (n, dec = 0) => "€" + n.toLocaleString("nl-NL", { minimumFractionDigits: dec, maximumFractionDigits: dec });
const fmtNum = (n) => n.toLocaleString("nl-NL");
const fmtDate = (s) => { if (!s) return "—"; const d = new Date(s); return isNaN(d) ? s : d.toLocaleDateString("nl-NL", { day: "numeric", month: "short" }); };

const STATUS_LABEL = { ok: "Voldoende", warn: "Raakt op", danger: "Direct bestellen" };

function Stars({ value, size = 14 }) {
  const full = Math.round(value);
  return (
    <span className="stars" title={value.toFixed(1)}>
      {[1, 2, 3, 4, 5].map(i => (
        <Icon key={i} name="star" size={size} className={i <= full ? "" : "empty"}
          style={{ fill: i <= full ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 1.4 }} />
      ))}
    </span>
  );
}

function Delta({ value, suffix = "%", invert = false, showZero = true }) {
  const up = value > 0, down = value < 0;
  const good = invert ? down : up;
  const cls = value === 0 ? "flat" : good ? "up" : "down";
  if (value === 0 && !showZero) return null;
  return (
    <span className={"delta " + cls}>
      <Icon name={value === 0 ? "minus" : up ? "arrowUp" : "arrowDown"} size={13} sw={2.4} />
      {value > 0 ? "+" : ""}{value}{suffix}
    </span>
  );
}

function StatusPill({ status, label }) {
  return <span className={"pill " + status}><span className="pdot" />{label || STATUS_LABEL[status]}</span>;
}

function ProductThumb({ p, size = 38 }) {
  const g = p.group2 || { color: "#6a655e", icon: "package" };
  return (
    <span className="thumb" style={{ width: size, height: size, background: g.color }}>
      {p && p.image
        ? <img src={p.image} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} onError={e => { e.target.style.display = "none"; }} />
        : <Icon name={g.icon} size={size * 0.5} />}
    </span>
  );
}

function Card({ children, className = "", style, onClick }) {
  return <div className={"card " + className} style={style} onClick={onClick}>{children}</div>;
}
function CardHead({ title, sub, icon, right }) {
  return (
    <div className="card-head">
      {icon && <span style={{ color: "var(--text-3)" }}><Icon name={icon} size={17} /></span>}
      <div>
        <h3>{title}</h3>
        {sub && <div className="ch-sub">{sub}</div>}
      </div>
      {right && <div className="ch-right">{right}</div>}
    </div>
  );
}

function KPI({ icon, iconBg, iconColor, label, value, foot, delta, onClick, valColor }) {
  return (
    <Card className={"kpi" + (onClick ? " kpi-click" : "")} onClick={onClick}>
      <div className="k-top">
        <span className="k-ico" style={{ background: iconBg, color: iconColor }}><Icon name={icon} size={18} /></span>
        <span className="k-label">{label}</span>
      </div>
      <div className="k-val" style={valColor ? { color: valColor } : undefined}>{value}</div>
      <div className="k-foot">{delta}{foot}</div>
    </Card>
  );
}

/* ---------- Sidebar ---------- */
const NAV = [
  { id: "dashboard", label: "Dashboard", icon: "dashboard" },
  { id: "voorraad", label: "Voorraad", icon: "boxes" },
  { id: "producten", label: "Producten", icon: "tag" },
  { id: "inkoop", label: "Inkoop", icon: "truck" },
  { id: "winst", label: "Winst", icon: "euro" },
  { id: "retouren", label: "Retouren", icon: "truck" },
  { id: "advertenties", label: "Advertenties", icon: "chart" },
  { id: "reviews", label: "Reviews", icon: "star" },
  { id: "rankings", label: "Rankings", icon: "trending" },
  { id: "seo", label: "SEO", icon: "search2" },
  { id: "meldingen", label: "Meldingen", icon: "bell" },
  { id: "instellingen", label: "Instellingen", icon: "settings" },
];

function Sidebar({ view, onNav, alertCount }) {
  return (
    <aside className="sidebar">
      <div className="sb-brand">
        <img src="assets/stocers-logo-white.png" alt="STOCERS" />
        {(() => {
          const period = (window.STORE && window.STORE.period && window.STORE.period()) || "d30";
          const PD = { today: 1, yesterday: 1, d7: 7, d30: 30, d90: 90, d180: 180, d365: 365 };
          const LBL = { today: "Vandaag", yesterday: "Gisteren", d7: "7 dagen", d30: "30 dagen", d90: "3 maanden", d180: "6 maanden", d365: "1 jaar" };
          const t = new Date();
          const at = (back) => new Date(t.getFullYear(), t.getMonth(), t.getDate() - back);
          const f = (d, withYear) => { const s = d.toLocaleDateString("nl-NL", withYear ? { day: "numeric", month: "short", year: "2-digit" } : { day: "numeric", month: "short" }); return s; };
          const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
          let dateStr;
          if (period === "today") dateStr = cap(t.toLocaleDateString("nl-NL", { weekday: "short", day: "numeric", month: "short" }));
          else if (period === "yesterday") dateStr = cap(at(1).toLocaleDateString("nl-NL", { weekday: "short", day: "numeric", month: "short" }));
          else { const n = PD[period] || 30; const longRange = n > 31; dateStr = f(at(n - 1), longRange) + " – " + f(at(0), longRange); }
          return (
            <span className="sb-date">
              <span className="sb-date-lbl">{LBL[period] || period}</span>
              <span className="sb-date-val">{dateStr}</span>
            </span>
          );
        })()}
      </div>
      <div className="sb-brand" style={{ padding: "0 22px 14px", marginTop: -10 }}>
        <span className="sub">Command Center</span>
      </div>
      <div className="sb-divider" />
      <nav className="sb-nav">
        {NAV.map(n => (
          <button key={n.id} className={"nav-item" + (view === n.id ? " active" : "") + (n.id === "winst" ? " nav-key" : "")} onClick={() => onNav(n.id)}>
            <Icon name={n.icon} size={18} className="nav-ico" />
            {n.label}
            {n.id === "meldingen" && alertCount > 0 && <span className="nav-badge">{alertCount}</span>}
          </button>
        ))}
      </nav>
      <div className="sb-foot">
        <div className="sb-user">
          <div className="sb-avatar">ST</div>
          <div style={{ minWidth: 0 }}>
            <div className="nm">STOCERS</div>
            <div className="em">doosjehout.nl</div>
          </div>
        </div>
      </div>
    </aside>
  );
}

/* ---------- Topbar ---------- */
function Topbar({ onNav, alertCount, db }) {
  const today = new Date();
  const dateStr = today.toLocaleDateString("nl-NL", { weekday: "long", day: "numeric", month: "long" });
  const cap = dateStr.charAt(0).toUpperCase() + dateStr.slice(1);
  const [q, setQ] = React.useState("");
  const [open, setOpen] = React.useState(false);
  const wrap = React.useRef();
  React.useEffect(() => {
    const h = (e) => { if (wrap.current && !wrap.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  const ql = q.trim().toLowerCase();
  const prods = (db && db.products) || [];
  const results = ql
    ? prods.filter(p => (p.name + " " + p.sku + " " + (p.group || "")).toLowerCase().includes(ql)).slice(0, 8)
    : [];
  const go = (p) => { setQ(""); setOpen(false); onNav("producten", p.id); };
  return (
    <header className="topbar">
      <div className="tb-search-wrap" ref={wrap}>
        <label className="tb-search">
          <Icon name="search2" size={16} />
          <input placeholder="Zoek product of SKU…" value={q}
            onChange={e => { setQ(e.target.value); setOpen(true); }}
            onFocus={() => setOpen(true)}
            onKeyDown={e => { if (e.key === "Enter" && results[0]) go(results[0]); if (e.key === "Escape") setOpen(false); }} />
          {q && <button className="tb-clear" onMouseDown={e => { e.preventDefault(); setQ(""); }}><Icon name="x" size={14} /></button>}
        </label>
        {open && ql && (
          <div className="tb-results">
            {results.length ? results.map(p => (
              <button key={p.id} className="tb-result" onClick={() => go(p)}>
                <ProductThumb p={p} size={30} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 13, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</div>
                  <div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{p.sku}</div>
                </div>
                <span className={"pill " + p.status} style={{ fontSize: 11 }}><span className="pdot" />{p.stock}</span>
              </button>
            )) : <div className="tb-noresult">Geen product gevonden voor "{q}"</div>}
          </div>
        )}
      </div>
      <div className="tb-right">
        <span className="tb-date">{cap}</span>
        <a className="btn btn-brand btn-sm tb-orders" href="https://doosjehout.stockitup.nl/orders2/items/" target="_blank" rel="noreferrer" title="Orders verwerken in Stockitup">
          <Icon name="truck" size={15} /><span className="tb-orders-label">Orders</span>
        </a>
        <button className={"tb-btn" + (window.DB.liveStatus().busy ? " spin" : "")} title="Verversen"
          onClick={() => { const ls = window.DB.liveStatus(); ls.active ? window.DB.liveSync() : location.reload(); }}>
          <Icon name="refresh" size={18} />
        </button>
        <button className="tb-btn" title="Meldingen" onClick={() => onNav("meldingen")}>
          <Icon name="bell" size={18} />{alertCount > 0 && <span className="dot" />}
        </button>
        <button className="tb-btn" title="Account"><Icon name="user" size={18} /></button>
      </div>
    </header>
  );
}

/* ---------- small helpers ---------- */
function SectionTitle({ children, right }) {
  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", margin: "6px 2px 12px" }}>
      <h2 style={{ fontSize: 16, fontWeight: 600, margin: 0, letterSpacing: "-.01em" }}>{children}</h2>
      {right}
    </div>
  );
}

function Placeholder({ label, note, height = 160 }) {
  return (
    <div className="placeholder" style={{ minHeight: height, display: "grid", placeContent: "center", gap: 6 }}>
      <div style={{ fontWeight: 600, color: "var(--text-2)" }}>{label}</div>
      {note && <div className="ph-mono">{note}</div>}
    </div>
  );
}

/* ---------- confetti (kleine positieve burst bij een nieuwe review) ---------- */
const _confettiFired = new Set();
function celebrate(anchorEl, key) {
  try {
    if (key) { if (_confettiFired.has(key)) return; _confettiFired.add(key); }
    if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const r = (anchorEl && anchorEl.getBoundingClientRect) ? anchorEl.getBoundingClientRect()
      : { left: innerWidth / 2, top: innerHeight / 2, width: 0, height: 0 };
    const ox = r.left + r.width / 2, oy = r.top + r.height / 2;
    const cv = document.createElement("canvas");
    cv.width = innerWidth; cv.height = innerHeight;
    cv.style.cssText = "position:fixed;inset:0;pointer-events:none;z-index:9999";
    document.body.appendChild(cv);
    const ctx = cv.getContext("2d");
    const colors = ["#8f0009", "#e0b341", "#1f8a5b", "#2a6fdb", "#d9772f"];
    const parts = Array.from({ length: 40 }, () => {
      const a = Math.random() * Math.PI * 2, sp = 3 + Math.random() * 6;
      return { x: ox, y: oy, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp - 3.5,
        g: 0.14 + Math.random() * 0.08, s: 4 + Math.random() * 5, rot: Math.random() * 6,
        vr: (Math.random() - 0.5) * 0.5, c: colors[(Math.random() * colors.length) | 0], life: 0 };
    });
    let start = null, last = null;
    function frame(t) {
      if (start == null) { start = t; last = t; }
      const dt = Math.min(34, t - last); last = t;
      ctx.clearRect(0, 0, cv.width, cv.height);
      let alive = false;
      for (const p of parts) {
        p.life += dt; p.vy += p.g; p.x += p.vx; p.y += p.vy; p.rot += p.vr;
        const alpha = Math.max(0, 1 - p.life / 1200);
        if (alpha > 0 && p.y < cv.height + 24) {
          alive = true;
          ctx.save(); ctx.globalAlpha = alpha; ctx.translate(p.x, p.y); ctx.rotate(p.rot);
          ctx.fillStyle = p.c; ctx.fillRect(-p.s / 2, -p.s / 2, p.s, p.s * 0.6); ctx.restore();
        }
      }
      if (alive && (t - start) < 1800) requestAnimationFrame(frame); else cv.remove();
    }
    requestAnimationFrame(frame);
  } catch (e) {}
}
// "Nieuw"-badge die bij verschijnen één keer (per sessie/sku) een confetti-burst geeft
function NieuwBadge({ sku, style, children }) {
  const ref = React.useRef();
  React.useEffect(() => { if (ref.current) celebrate(ref.current, "rev:" + (sku || "")); }, [sku]);
  return <span ref={ref} className="pill ok" style={style}>{children || "Nieuw"}</span>;
}

Object.assign(window, {
  fmtEur, fmtNum, STATUS_LABEL, Stars, Delta, StatusPill, ProductThumb,
  Card, CardHead, KPI, Sidebar, Topbar, NAV, SectionTitle, Placeholder,
  celebrate, NieuwBadge,
});
