/* ============================================================
   Shared UI — Sidebar, TopBar, charts, primitives
   ============================================================ */
const { useState, useEffect, useRef, useMemo } = React;

/* ---------- Sidebar ---------- */
const NAV_GROUPS = [
  { label: "Bảng điều khiển", items: [
    { id: "overview", label: "Tổng quan", icon: "grid" },
    { id: "coverage", label: "Độ phủ", icon: "coverage", badge: "92%" },
  ]},
  { label: "Tài liệu", items: [
    { id: "docs",         label: "Tài liệu", icon: "doc" },
    { id: "rfi",          label: "Phê duyệt · RFI", icon: "flow" },
    { id: "transmittals", label: "Transmittals", icon: "send" },
  ]},
  { label: "Phối hợp", items: [
    { id: "viewer",   label: "BIM Viewer", icon: "cube" },
    { id: "issues",   label: "Issues · BCF", icon: "flag", badge: "5" },
    { id: "clash",    label: "Va chạm", icon: "burst", badge: "2", warn: true },
    { id: "alerts",   label: "Cảnh báo", icon: "alert", badge: "37", warn: true },
    { id: "schedule", label: "Tiến độ", icon: "calendar" },
  ]},
  { label: "Quản trị", items: [
    { id: "users",       label: "Người dùng", icon: "users" },
    { id: "permissions", label: "Phân quyền", icon: "shield" },
    { id: "audit",       label: "Nhật ký", icon: "clock" },
    { id: "reports",     label: "Báo cáo", icon: "chart" },
  ]},
];

function NavRow({ item, active, onClick }) {
  const Ico = Icon[item.icon];
  return (
    <div className={`nav-item ${active ? "active" : ""}`} onClick={onClick}>
      <Ico size={18} />
      <span className="label">{item.label}</span>
      {item.badge && <span className={`nav-badge ${item.warn ? "warn" : ""}`}>{item.badge}</span>}
    </div>
  );
}

const ROLE_VI = { viewer: "Xem", uploader: "Nạp", editor: "Biên tập", admin: "Quản trị" };
function initialsOf(name) {
  const p = (name || "").trim().split(/\s+/);
  return ((p[p.length - 1]?.[0] || "") + (p.length > 1 ? p[0][0] : "")).toUpperCase() || "?";
}

function Sidebar({ route, setRoute, auth, onLogin, onLogout }) {
  const loggedIn = !!(auth && auth.user);
  const prof = auth && auth.profile;
  const name = loggedIn ? (prof?.full_name || auth.user.email) : "Khách";
  const sub = loggedIn
    ? (prof ? (ROLE_VI[prof.role] || prof.role) + (prof.discipline ? " · " + prof.discipline : "") : "Đang tải hồ sơ…")
    : (auth && auth.ready ? "Bấm để đăng nhập" : "Chế độ mock");
  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark"><Icon.sync size={21} sw={2.1} /></div>
        <div>
          <div className="brand-name">BIMUP</div>
          <div className="brand-sub">CDE · cde.bimupstudio.com</div>
        </div>
      </div>

      <nav className="nav">
        {NAV_GROUPS.map((group) => (
          <React.Fragment key={group.label}>
            <div className="nav-label">{group.label}</div>
            {group.items.map((it) => (
              <NavRow key={it.id} item={it} active={route === it.id} onClick={() => setRoute(it.id)} />
            ))}
          </React.Fragment>
        ))}
      </nav>

      <div className="side-foot">
        <NavRow item={{ label: "Cài đặt", icon: "gear" }} active={route === "settings"} onClick={() => setRoute("settings")} />
        <div className="user-chip" style={{ cursor: "pointer" }}
          title={loggedIn ? "Đăng xuất" : "Đăng nhập"}
          onClick={() => (loggedIn ? onLogout && onLogout() : onLogin && onLogin())}>
          <div className="avatar">{initialsOf(name)}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13.5, fontWeight: 800, lineHeight: 1.2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{name}</div>
            <div style={{ fontSize: 11.5, color: "var(--ink-3)", fontWeight: 600, display: "flex", alignItems: "center", gap: 5 }}>
              {loggedIn && <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--ok)", flex: "none" }} />}
              {sub}
            </div>
          </div>
          <Icon.chevUD size={15} color="var(--ink-4)" />
        </div>
      </div>
    </aside>
  );
}

/* ---------- TopBar ---------- */
function TopBar({ crumb, title, theme, setTheme, actions }) {
  return (
    <header className="topbar">
      <div>
        <div className="crumb">{crumb}</div>
        <div className="page-title">{title}</div>
      </div>
      <div className="search">
        <Icon.search size={17} />
        <span style={{ flex: 1 }}>Tìm mô hình, tệp, người dùng…</span>
        <span className="kbd">⌘K</span>
      </div>
      {actions}
      <button className="pill"><span className="dot live" /> Đồng bộ 2 phút trước</button>
      <button className="icon-btn" onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
        title="Đổi giao diện sáng/tối">
        {theme === "dark" ? <Icon.sun size={18} /> : <Icon.moon size={18} />}
      </button>
      <button className="icon-btn"><Icon.bell size={18} /><span className="ping" /></button>
    </header>
  );
}

/* ---------- Stat card ---------- */
function Stat({ icon, tint, label, value, unit, trend, trendDir, foot, spark }) {
  const Ico = Icon[icon];
  return (
    <div className="card stat fade-up">
      <div className="stat-ico" style={{ background: `${tint}1f`, color: tint }}><Ico size={19} /></div>
      <div>
        <div className="stat-label">{label}</div>
        <div className="stat-value tnum" style={{ marginTop: 8 }}>
          {value}{unit && <span className="u">{unit}</span>}
        </div>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        {trend && (
          <span className={`trend ${trendDir}`}>
            {trendDir === "up" ? <Icon.arrowUp size={12} /> : trendDir === "down" ? <Icon.arrowDn size={12} /> : null}
            {trend}
          </span>
        )}
        {foot && <span style={{ fontSize: 12, color: "var(--ink-3)", fontWeight: 600 }}>{foot}</span>}
        {spark && <div style={{ marginLeft: "auto" }}>{spark}</div>}
      </div>
    </div>
  );
}

/* ---------- Spark line ---------- */
function Spark({ data, color = "var(--accent)", w = 92, h = 30 }) {
  const max = Math.max(...data), min = Math.min(...data);
  const pts = data.map((v, i) => [ (i / (data.length - 1)) * w, h - ((v - min) / (max - min || 1)) * (h - 4) - 2 ]);
  const d = pts.map((p, i) => `${i ? "L" : "M"}${p[0].toFixed(1)} ${p[1].toFixed(1)}`).join(" ");
  return (
    <svg width={w} height={h} className="spark">
      <path d={d} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length-1][0]} cy={pts[pts.length-1][1]} r="2.6" fill={color} />
    </svg>
  );
}

/* ---------- Area chart ---------- */
function AreaChart({ data, color = "var(--accent)", height = 230 }) {
  const ref = useRef(null);
  const [w, setW] = useState(640);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const update = () => setW((prev) => {
      const next = Math.floor(el.clientWidth);
      return Math.abs(next - prev) > 2 ? next : prev;
    });
    const ro = new ResizeObserver(update);
    ro.observe(el); update();
    return () => ro.disconnect();
  }, []);
  const h = height, pad = 8;
  const max = Math.max(...data) * 1.05, min = Math.min(...data) * 0.96;
  const X = (i) => (i / (data.length - 1)) * (w - pad * 2) + pad;
  const Y = (v) => h - 16 - ((v - min) / (max - min || 1)) * (h - 40);
  // smooth path
  const pts = data.map((v, i) => [X(i), Y(v)]);
  let line = `M${pts[0][0]} ${pts[0][1]}`;
  for (let i = 1; i < pts.length; i++) {
    const [x0, y0] = pts[i - 1], [x1, y1] = pts[i];
    const cx = (x0 + x1) / 2;
    line += ` C${cx} ${y0} ${cx} ${y1} ${x1} ${y1}`;
  }
  const area = `${line} L${pts[pts.length-1][0]} ${h} L${pts[0][0]} ${h} Z`;
  return (
    <div ref={ref} style={{ width: "100%", overflow: "hidden" }}>
      <svg width={w} height={h} className="spark" style={{ display: "block" }}>
        <defs>
          <linearGradient id="aFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.20" />
            <stop offset="100%" stopColor={color} stopOpacity="0" />
          </linearGradient>
        </defs>
        {[0.25, 0.5, 0.75, 1].map((g, i) => (
          <line key={i} x1={pad} x2={w - pad} y1={16 + g * (h - 40)} y2={16 + g * (h - 40)}
            stroke="var(--line-soft)" strokeWidth="1" />
        ))}
        <path className="area" d={area} fill="url(#aFill)" />
        <path d={line} fill="none" stroke={color} strokeWidth="2.4" strokeLinecap="round" />
        <circle cx={pts[pts.length-1][0]} cy={pts[pts.length-1][1]} r="5" fill="var(--surface)" stroke={color} strokeWidth="2.6" />
      </svg>
    </div>
  );
}

/* ---------- Donut ---------- */
function Donut({ segments, total, label, size = 168 }) {
  const r = size / 2 - 13, c = 2 * Math.PI * r;
  let off = 0;
  return (
    <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
      <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--sunken)" strokeWidth="13" />
      {segments.map((s, i) => {
        const len = (s.v / total) * c;
        const el = (
          <circle key={i} cx={size/2} cy={size/2} r={r} fill="none" stroke={s.color}
            strokeWidth="13" strokeLinecap="round"
            strokeDasharray={`${len - 4} ${c - len + 4}`} strokeDashoffset={-off}
            style={{ transition: "stroke-dasharray .9s cubic-bezier(.2,.8,.2,1)" }} />
        );
        off += len; return el;
      })}
    </svg>
  );
}

Object.assign(window, { Sidebar, TopBar, Stat, Spark, AreaChart, Donut,
  NAV_GROUPS });

window.DISC_COL = { inf: "#14b8a6", str: "#60a5fa", arc: "#a78bfa", mep: "#f59e0b", site: "#5b6b72" };
