/* ============================================================
   FileManager — main shell (tree + list + drawer + upload)
   ============================================================ */
const { useState: useStateMain, useRef: useRefMain, useMemo: useMemoMain } = React;

const STATUS_FILTERS = [
  { k: "all", label: "Tất cả" },
  { k: "wip", label: "WIP" },
  { k: "review", label: "Đang duyệt" },
  { k: "shared", label: "Đã chia sẻ" },
  { k: "approved", label: "Đã duyệt" },
  { k: "published", label: "Phát hành" },
  { k: "changes", label: "Cần sửa" },
];

/* ISO 19650 discipline code → internal discipline key */
const DISC_FROM_ISO = { A: "arc", S: "str", I: "inf", M: "mep", C: "inf" };

function UploadModal({ folderName, folderKey, live, onClose, onAdd, onUploaded }) {
  const [vals, setVals] = useStateMain({ project: "PRJ01", originator: "", volume: "", level: "", type: "M3", discipline: "A", number: "" });
  const [type, setType] = useStateMain("DWG");
  const [file, setFile] = useStateMain(null);
  const [busy, setBusy] = useStateMain(false);
  const [err, setErr] = useStateMain("");
  const fileRef = useRefMain(null);
  const setField = (k, v) => setVals(s => ({ ...s, [k]: v }));
  const preview = buildName(vals);
  const { ok, errors } = validateName(vals);
  const errFor = (key) => errors.find(e => e.field === key);
  const fieldStyle = (key) => ({ ...inp, height: 38, borderColor: errFor(key) ? "var(--danger)" : "var(--line)" });
  const canSubmit = ok && !busy && (!live || !!file);
  const submit = async () => {
    if (!ok) return;
    const disc = DISC_FROM_ISO[vals.discipline] || "inf";
    if (live) {
      if (!file) { setErr("Chọn tệp để nạp lên R2"); return; }
      setBusy(true); setErr("");
      try { await cdeUpload(file, { name: preview, type, disc, folderKey }); onUploaded && onUploaded(); onClose(); }
      catch (e) { setErr(e.message || "Upload thất bại"); }
      finally { setBusy(false); }
    } else {
      onAdd({ name: preview, type, disc }); onClose();
    }
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 50, background: "rgba(8,19,23,.5)", backdropFilter: "blur(3px)", display: "grid", placeItems: "center" }}>
      <div onClick={(e)=>e.stopPropagation()} className="card" style={{ width: 500, boxShadow: "var(--shadow-lg)", maxHeight: "92vh", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "18px 22px", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <div><div style={{ fontWeight: 800, fontSize: 16 }}>Nạp tài liệu</div>
            <div style={{ fontSize: 12.5, color: "var(--ink-3)", fontWeight: 500, marginTop: 2 }}>vào · {folderName}</div></div>
          <button className="icon-btn" style={{ width: 30, height: 30, borderRadius: 8 }} onClick={onClose}><span style={{ fontSize: 18, lineHeight: 0 }}>✕</span></button>
        </div>
        <div style={{ padding: 22, overflowY: "auto" }}>
          <div onClick={() => fileRef.current && fileRef.current.click()}
            style={{ border: `1.5px dashed ${file ? "var(--accent)" : "var(--line)"}`, borderRadius: 12, padding: "22px 16px", textAlign: "center", background: "var(--sunken)", marginBottom: 18, cursor: "pointer" }}>
            <input ref={fileRef} type="file" style={{ display: "none" }} onChange={(e) => setFile(e.target.files[0] || null)} />
            <Icon.upload size={26} color="var(--accent)" />
            <div style={{ fontSize: 13.5, fontWeight: 700, marginTop: 8 }}>{file ? file.name : "Bấm để chọn / kéo thả tệp"}</div>
            <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 3, fontWeight: 500 }}>
              {file ? `${(file.size / 1048576).toFixed(2)} MB · sẽ tải lên R2` : "DWG · IFC · RVT · NWC · PDF · DOCX"}</div>
          </div>

          <label style={lbl}>Mã hồ sơ · ISO 19650</label>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
            {ISO_FIELDS.map(f => (
              <div key={f.key}>
                <label style={{ ...lbl, marginBottom: 4, fontSize: 11 }}>{f.label}</label>
                {f.options
                  ? <select value={vals[f.key]} onChange={(e)=>setField(f.key, e.target.value)} style={fieldStyle(f.key)}>
                      {f.options.map(([v,l]) => <option key={v} value={v}>{l}</option>)}
                    </select>
                  : <input value={vals[f.key]} onChange={(e)=>setField(f.key, e.target.value)} placeholder={f.placeholder} style={fieldStyle(f.key)} />}
              </div>
            ))}
          </div>

          {/* live name preview + validation */}
          <div style={{ marginTop: 14, padding: "12px 14px", borderRadius: 10, background: "var(--sunken)",
            border: `1px solid ${ok ? "var(--line)" : "var(--danger)"}` }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
              <span className="mono" style={{ fontSize: 12.5, fontWeight: 700, color: ok ? "var(--ink)" : "var(--ink-3)", wordBreak: "break-all" }}>{preview}</span>
              {ok
                ? <span className="chip ok" style={{ flex: "none" }}><Icon.check size={12} /> Hợp lệ</span>
                : <span className="chip danger" style={{ flex: "none" }}><Icon.alert size={12} /> {errors.length} lỗi</span>}
            </div>
            {!ok && (
              <ul style={{ margin: "8px 0 0", padding: "0 0 0 16px", fontSize: 11.5, color: "var(--danger)", fontWeight: 600 }}>
                {errors.slice(0, 3).map((e, i) => <li key={i}>{e.msg}</li>)}
              </ul>
            )}
          </div>

          <div style={{ marginTop: 14 }}>
            <label style={lbl}>Định dạng tệp (rendition)</label>
            <select value={type} onChange={(e)=>setType(e.target.value)} style={inp}>{["DWG","IFC","RVT","NWC","PDF","DOCX","XLSX"].map(t=><option key={t}>{t}</option>)}</select>
          </div>
          {err && <div style={{ marginTop: 12, fontSize: 12.5, color: "var(--danger)", fontWeight: 600 }}>{err}</div>}
          {!live && <div style={{ marginTop: 12, fontSize: 11.5, color: "var(--ink-4)" }}>Chế độ demo (chưa đăng nhập) — chỉ thêm vào danh sách tạm.</div>}
        </div>
        <div style={{ padding: "16px 22px", borderTop: "1px solid var(--line)", display: "flex", gap: 10, justifyContent: "flex-end" }}>
          <button className="btn" onClick={onClose}>Huỷ</button>
          <button className="btn primary" disabled={!canSubmit} style={!canSubmit ? { opacity: .5, cursor: "not-allowed" } : undefined}
            onClick={submit}><Icon.upload size={14} /> {busy ? "Đang nạp…" : "Nạp lên"}</button>
        </div>
      </div>
    </div>
  );
}
const lbl = { display: "block", fontSize: 11.5, fontWeight: 700, color: "var(--ink-3)", marginBottom: 6, letterSpacing: ".02em" };
const inp = { width: "100%", height: 40, padding: "0 12px", borderRadius: 10, border: "1px solid var(--line)", background: "var(--surface)", color: "var(--ink)", font: "inherit", fontSize: 13.5, fontWeight: 600, outline: "none" };

function CreateFolderModal({ parentName, onClose, onCreate }) {
  const [name, setName] = useStateMain("");
  const [busy, setBusy] = useStateMain(false);
  const submit = async () => { if (!name.trim()) return; setBusy(true); await onCreate(name.trim()); setBusy(false); };
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 50, background: "rgba(8,19,23,.5)", backdropFilter: "blur(3px)", display: "grid", placeItems: "center" }}>
      <div onClick={(e)=>e.stopPropagation()} className="card" style={{ width: 420, padding: 24, boxShadow: "var(--shadow-lg)" }}>
        <div style={{ fontWeight: 800, fontSize: 16 }}>Tạo thư mục</div>
        <div style={{ fontSize: 12.5, color: "var(--ink-3)", fontWeight: 500, marginTop: 2 }}>trong · {parentName}</div>
        <label style={{ ...lbl, marginTop: 16 }}>Tên thư mục</label>
        <input autoFocus value={name} onChange={(e)=>setName(e.target.value)} placeholder="VD: 03 · Bản vẽ thi công"
          onKeyDown={(e)=>e.key==="Enter"&&submit()} style={inp} />
        <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 20 }}>
          <button className="btn" onClick={onClose}>Huỷ</button>
          <button className="btn primary" disabled={!name.trim()||busy} style={(!name.trim()||busy)?{opacity:.5,cursor:"not-allowed"}:undefined} onClick={submit}>
            <Icon.plus size={14} /> {busy?"Đang tạo…":"Tạo"}
          </button>
        </div>
      </div>
    </div>
  );
}

function FileManager() {
  const auth = (typeof useAuthCtx === "function") ? useAuthCtx() : null;
  const live = !!(auth && auth.user && window.CDE_READY);
  const [cur, setCur] = useStateMain("shared");
  const [expanded, setExpanded] = useStateMain(new Set(["root", "shared"]));
  const [files, setFiles] = useStateMain(FILES0);
  const [foldersVersion, setFoldersVersion] = useStateMain(0);
  const [loading, setLoading] = useStateMain(false);
  const [sel, setSel] = useStateMain(null);
  const [checked, setChecked] = useStateMain(new Set());
  const [view, setView] = useStateMain("list");
  const [filter, setFilter] = useStateMain("all");
  const [q, setQ] = useStateMain("");
  const [uploading, setUploading] = useStateMain(false);
  const [sideW, setSideW] = useStateMain(() => {
    const v = Number(localStorage.getItem("cde.folderW"));
    return v >= 200 && v <= 520 ? v : 288;
  });
  const startResize = (e) => {
    e.preventDefault();
    const startX = e.clientX, startW = sideW; let latest = startW;
    const onMove = (ev) => { latest = Math.min(520, Math.max(200, startW + ev.clientX - startX)); setSideW(latest); };
    const onUp = () => {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      document.body.style.userSelect = "";
      localStorage.setItem("cde.folderW", String(latest));
    };
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
    document.body.style.userSelect = "none";
  };

  // load live data when authenticated; fall back to mock otherwise
  const reload = React.useCallback(() => {
    if (live) {
      setLoading(true);
      Promise.all([cdeData.folders(), cdeData.containers()])
        .then(([fl, cs]) => { setActiveFolders(fl); setFiles(cs); setFoldersVersion(v => v + 1); })
        .catch(e => { console.warn("FileManager live load:", e.message); setActiveFolders(FOLDERS); setFiles(FILES0); })
        .finally(() => setLoading(false));
    } else {
      setActiveFolders(FOLDERS); setFiles(FILES0); setFoldersVersion(v => v + 1);
    }
  }, [live]);
  React.useEffect(() => { reload(); }, [reload]);

  // FR-19 — realtime: refresh when containers change
  React.useEffect(() => {
    if (!live || !window.sb) return;
    const ch = window.sb.channel("rt-containers")
      .on("postgres_changes", { event: "*", schema: "public", table: "containers" }, () => reload())
      .subscribe();
    return () => { try { window.sb.removeChannel(ch); } catch {} };
  }, [live, reload]);

  const toggle = (id) => setExpanded(e => { const n = new Set(e); n.has(id) ? n.delete(id) : n.add(id); return n; });

  const subIds = useMemoMain(() => new Set(descendantIds(cur)), [cur, foldersVersion]);
  const subFolders = childFolders(cur);
  const listing = useMemoMain(() => files.filter(f =>
    subIds.has(f.folder)
    && (filter === "all" || f.status === filter)
    && (!q || f.name.toLowerCase().includes(q.toLowerCase()) || (f.desc||"").toLowerCase().includes(q.toLowerCase()))
  ), [files, subIds, filter, q]);

  const crumbs = breadcrumb(cur);
  const curFolder = folderById(cur);

  const navTo = (id) => { setCur(id); setSel(null); setChecked(new Set());
    setExpanded(e => { const n = new Set(e); let c = folderById(id); while (c) { n.add(c.id); c = c.parent ? folderById(c.parent) : null; } return n; }); };

  const toggleCheck = (id) => setChecked(c => { const n = new Set(c); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const allChecked = listing.length > 0 && listing.every(f => checked.has(f.id));

  const bulkSubmit = async () => {
    if (!live) { window.alert("Đăng nhập để gửi duyệt hàng loạt."); return; }
    const ids = files.filter(f => checked.has(f.id) && f.status === "wip").map(f => f.id);
    if (!ids.length) { window.alert("Chỉ hồ sơ WIP mới gửi duyệt được."); return; }
    for (const id of ids) { try { await cdeData.setContainerStatus(id, "review"); } catch (e) { console.warn("bulk:", e.message); } }
    setChecked(new Set()); reload();
  };

  const exportCSV = () => downloadCSV("document-register.csv",
    ["Mã hồ sơ", "Bộ môn", "Định dạng", "Phiên bản", "Trạng thái", "Suitability", "Dung lượng", "Cập nhật", "Người sửa"],
    listing.map(f => [f.name, DISC_NAME[f.disc], f.type, f.rev, STATUS[f.status].label, STATUS[f.status]?.suit || "", f.size, f.date, f.by]));

  const addFile = ({ name, type, disc }) => {
    const nf = { id: Date.now(), folder: subFolders[0]?.id || cur, name, type, disc, status: "wip",
      size: "—", date: "Vừa xong", by: "Trần Đức", rev: "P01", desc: "Tệp vừa nạp",
      versions: [{ rev: "P01", date: "Vừa xong", by: "Trần Đức", status: "wip", note: "Khởi tạo" }] };
    setFiles(f => [nf, ...f]);
  };

  const [menuFor, setMenuFor] = useStateMain(null);
  const [creatingFolder, setCreatingFolder] = useStateMain(false);

  const shareLink = async (key) => {
    if (!key) { window.alert("Phiên bản này chưa có tệp để chia sẻ."); return; }
    const url = location.origin + cdeData.objectUrl(key);
    try { await navigator.clipboard.writeText(url); window.alert("Đã copy link chia sẻ:\n" + url); }
    catch { window.prompt("Copy link chia sẻ:", url); }
  };
  const doDelete = async (f) => {
    if (!live) { window.alert("Đăng nhập để xoá hồ sơ."); return; }
    if (!window.confirm(`Xoá hồ sơ "${f.name}"? Hành động này không thể hoàn tác.`)) return;
    try { await cdeData.deleteContainer(f.id, f.name); if (sel?.id === f.id) setSel(null); reload(); }
    catch (e) { window.alert("Xoá thất bại: " + e.message); }
  };
  const doSubmit = async (f) => {
    if (!live) { window.alert("Đăng nhập để gửi duyệt."); return; }
    try { await cdeData.setContainerStatus(f.id, "review"); reload(); }
    catch (e) { window.alert("Gửi duyệt thất bại: " + e.message); }
  };
  const createFolder = async (name) => {
    if (!live) { window.alert("Đăng nhập để tạo thư mục."); return; }
    try { await cdeData.createFolder({ name, parentKey: cur }); setCreatingFolder(false); reload(); }
    catch (e) { window.alert("Tạo thư mục thất bại: " + e.message); }
  };

  return (
    <div className="content flush" style={{ display: "flex", height: "100%", minHeight: 0, position: "relative" }}>
      {/* ---- folder tree ---- */}
      <div style={{ width: sideW, flex: "none", borderRight: "1px solid var(--line)", background: "var(--surface)", display: "flex", flexDirection: "column", minHeight: 0, position: "relative" }}>
        <div onMouseDown={startResize} title="Kéo để chỉnh độ rộng"
          style={{ position: "absolute", top: 0, right: -3, width: 6, height: "100%", cursor: "col-resize", zIndex: 6 }} />
        <div style={{ padding: "16px 16px 12px", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <div style={{ fontSize: 14.5, fontWeight: 800 }}>Thư mục dự án</div>
          <button className="icon-btn" style={{ width: 30, height: 30, borderRadius: 8 }} title="Tạo thư mục" onClick={()=>setCreatingFolder(true)}><Icon.plus size={16} /></button>
        </div>
        <div style={{ flex: 1, overflowY: "auto", padding: 10 }}>
          {childFolders("root").map(f => (
            <TreeNode key={f.id} id={f.id} cur={cur} setCur={navTo} expanded={expanded} toggle={toggle} depth={0} />
          ))}
        </div>
        <div style={{ padding: 12, borderTop: "1px solid var(--line)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "4px 8px" }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)", fontWeight: 600 }}>Dung lượng đã dùng</div>
              <div style={{ height: 6, borderRadius: 99, background: "var(--sunken)", marginTop: 6, overflow: "hidden" }}>
                <div style={{ width: "64%", height: "100%", background: "var(--accent)", borderRadius: 99 }} />
              </div>
              <div style={{ fontSize: 11, color: "var(--ink-4)", fontWeight: 600, marginTop: 5 }}>3.2 / 5 TB</div>
            </div>
          </div>
        </div>
      </div>

      {/* ---- main column ---- */}
      <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", minHeight: 0, background: "var(--bg)" }}>
        {/* breadcrumb + actions */}
        <div style={{ padding: "16px 22px 14px", borderBottom: "1px solid var(--line)", background: "var(--surface)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", flex: 1, minWidth: 0 }}>
              {crumbs.map((c, i) => (
                <React.Fragment key={c.id}>
                  {i>0 && <Icon.chevR size={13} color="var(--ink-4)" />}
                  <span onClick={()=>navTo(c.id)} style={{ fontSize: i===crumbs.length-1?16:14, fontWeight: i===crumbs.length-1?800:600,
                    color: i===crumbs.length-1?"var(--ink)":"var(--ink-3)", cursor: "pointer", letterSpacing: i===crumbs.length-1?"-.01em":"0" }}>{c.name}</span>
                </React.Fragment>
              ))}
            </div>
            <button className="btn sm" onClick={exportCSV}><Icon.download size={14} /> Xuất CSV</button>
            <button className="btn sm" onClick={()=>setCreatingFolder(true)}><Icon.plus size={14} /> Thư mục</button>
            <button className="btn sm primary" onClick={()=>setUploading(true)}><Icon.upload size={14} /> Nạp tài liệu</button>
          </div>
        </div>

        {/* filter bar */}
        <div style={{ padding: "12px 22px", borderBottom: "1px solid var(--line)", background: "var(--surface)", display: "flex", alignItems: "center", gap: 12 }}>
          <div style={{ display: "flex", gap: 7, flex: 1, flexWrap: "wrap" }}>
            {STATUS_FILTERS.map(sf => (
              <span key={sf.k} onClick={()=>setFilter(sf.k)} style={{ height: 30, padding: "0 12px", borderRadius: 8, display: "inline-flex", alignItems: "center", gap: 6,
                fontSize: 12.5, fontWeight: 700, cursor: "pointer",
                background: filter===sf.k ? "var(--accent)" : "var(--sunken)", color: filter===sf.k ? "#fff" : "var(--ink-3)" }}>
                {sf.label}{sf.k!=="all" && <span style={{ opacity: .75 }}>{files.filter(f=>subIds.has(f.folder)&&f.status===sf.k).length}</span>}
              </span>
            ))}
          </div>
          <div className="search" style={{ width: 230, height: 36, marginLeft: 0 }}>
            <Icon.search size={15} />
            <input value={q} onChange={(e)=>setQ(e.target.value)} placeholder="Tìm hồ sơ…" style={{ flex: 1, border: 0, background: "transparent", outline: "none", font: "inherit", fontSize: 13, color: "var(--ink)", minWidth: 0 }} />
          </div>
          <div className="seg">
            <button className={view==="list"?"on":""} onClick={()=>setView("list")} style={{ padding: "6px 9px" }}><Icon.grid size={14} style={{ display: "block" }} /></button>
            <button className={view==="grid"?"on":""} onClick={()=>setView("grid")} style={{ padding: "6px 9px" }}><Icon.layers size={14} style={{ display: "block" }} /></button>
          </div>
        </div>

        {/* bulk bar */}
        {checked.size > 0 && (
          <div style={{ padding: "10px 22px", background: "var(--accent-soft)", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 14 }}>
            <span style={{ fontSize: 13, fontWeight: 700, color: "var(--accent)" }}>Đã chọn {checked.size} tệp</span>
            <div style={{ display: "flex", gap: 8, marginLeft: "auto" }}>
              <button className="btn sm" onClick={() => downloadCSV("selected.csv", ["Mã hồ sơ","Bộ môn","Phiên bản","Trạng thái"], files.filter(f=>checked.has(f.id)).map(f=>[f.name, DISC_NAME[f.disc], f.rev, STATUS[f.status].label]))}><Icon.download size={13} /> Xuất chọn</button>
              <button className="btn sm"><Icon.link size={13} /> Chia sẻ</button>
              <button className="btn sm" onClick={bulkSubmit}><Icon.checkCircle size={13} /> Gửi duyệt</button>
              <button className="btn sm" onClick={()=>setChecked(new Set())}>Bỏ chọn</button>
            </div>
          </div>
        )}

        {/* listing + detail flyout */}
        <div style={{ flex: 1, minHeight: 0, position: "relative", display: "flex" }}>
        <div style={{ flex: 1, overflowY: "auto", minHeight: 0 }}>
          {view === "list" ? (
            <table className="tbl" style={{ width: "100%" }}>
              <thead><tr style={{ position: "sticky", top: 0, background: "var(--bg)", zIndex: 1 }}>
                <th style={{ paddingLeft: 22, width: 38 }}>
                  <input type="checkbox" checked={allChecked} onChange={()=>setChecked(allChecked?new Set():new Set(listing.map(f=>f.id)))} style={{ accentColor: "var(--accent)", width: 15, height: 15 }} />
                </th>
                <th>Tên hồ sơ</th><th>Bộ môn</th><th>Phiên bản</th><th>Trạng thái</th><th>Dung lượng</th><th>Cập nhật</th><th style={{ width: 40 }}></th>
              </tr></thead>
              <tbody>
                {/* subfolders first */}
                {filter==="all" && !q && subFolders.map(sf => {
                  const n = files.filter(f => descendantIds(sf.id).includes(f.folder)).length;
                  return (
                    <tr key={sf.id} onClick={()=>navTo(sf.id)} style={{ cursor: "pointer" }}>
                      <td style={{ paddingLeft: 22 }}></td>
                      <td className="t-strong">
                        <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
                          <span style={{ width: 34, height: 34, borderRadius: 9, flex: "none", display: "grid", placeItems: "center", background: `${DISC_COL[sf.disc]||"var(--accent)"}1c`, color: DISC_COL[sf.disc]||"var(--accent)" }}><Icon.layers size={17} /></span>
                          {sf.name}
                        </div>
                      </td>
                      <td>{sf.disc ? <span className={`chip ${sf.disc}`}>{DISC_NAME[sf.disc]}</span> : "—"}</td>
                      <td style={{ color: "var(--ink-4)" }}>—</td><td style={{ color: "var(--ink-4)" }}>Thư mục</td>
                      <td className="tnum" style={{ color: "var(--ink-3)" }}>{n} tệp</td><td style={{ color: "var(--ink-4)" }}>—</td>
                      <td><Icon.chevR size={15} color="var(--ink-4)" /></td>
                    </tr>
                  );
                })}
                {listing.map(f => {
                  const st = STATUS[f.status]; const Sico = Icon[st.icon];
                  return (
                    <tr key={f.id} onClick={()=>setSel(f)} style={{ cursor: "pointer", background: sel?.id===f.id ? "var(--accent-soft)" : undefined }}>
                      <td style={{ paddingLeft: 22 }} onClick={(e)=>e.stopPropagation()}>
                        <input type="checkbox" checked={checked.has(f.id)} onChange={()=>toggleCheck(f.id)} style={{ accentColor: "var(--accent)", width: 15, height: 15 }} />
                      </td>
                      <td>
                        <div style={{ minWidth: 0 }}>
                          <div className="mono t-strong" style={{ fontSize: 12.5, whiteSpace: "nowrap" }}>{f.name}</div>
                          <div style={{ fontSize: 11.5, color: "var(--ink-3)", fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: 230 }}>{f.desc}</div>
                        </div>
                      </td>
                      <td><span className={`chip ${f.disc}`}>{DISC_NAME[f.disc]}</span></td>
                      <td><span className="tag-mono">{f.rev}</span></td>
                      <td><span className={`chip ${st.cls}`}><Sico size={12} /> {st.label}</span></td>
                      <td className="tnum">{f.size}</td>
                      <td><div style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink-2)" }}>{f.date}</div><div style={{ fontSize: 11.5, color: "var(--ink-4)", fontWeight: 500 }}>{f.by}</div></td>
                      <td onClick={(e)=>e.stopPropagation()} style={{ position: "relative" }}>
                        <button className="icon-btn" style={{ width: 32, height: 32, borderRadius: 8 }}
                          onClick={()=>setMenuFor(menuFor===f.id?null:f.id)}><Icon.dots size={16} /></button>
                        {menuFor===f.id && (() => {
                          const key = f.versions?.[0]?.r2_key;
                          const mi = (icon, label, fn, danger) => (
                            <button onClick={()=>{ setMenuFor(null); fn(); }}
                              style={{ display: "flex", alignItems: "center", gap: 9, width: "100%", padding: "8px 10px", border: 0,
                                background: "transparent", borderRadius: 7, cursor: "pointer", font: "inherit", fontSize: 13, fontWeight: 600,
                                color: danger ? "var(--danger)" : "var(--ink-2)", textAlign: "left", whiteSpace: "nowrap" }}
                              onMouseEnter={e=>e.currentTarget.style.background="var(--sunken)"}
                              onMouseLeave={e=>e.currentTarget.style.background="transparent"}>
                              {React.createElement(Icon[icon], { size: 15 })} {label}
                            </button>
                          );
                          return (
                            <>
                              <div onClick={()=>setMenuFor(null)} style={{ position: "fixed", inset: 0, zIndex: 40 }} />
                              <div style={{ position: "absolute", right: 8, top: 42, zIndex: 41, width: 188, padding: 6,
                                background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 10, boxShadow: "var(--shadow-lg)" }}>
                                {mi("eye", "Xem chi tiết", ()=>setSel(f))}
                                {mi("download", "Tải về", ()=> key ? window.open(cdeData.downloadUrl(key), "_blank") : window.alert("Phiên bản này chưa có tệp."))}
                                {mi("link", "Chia sẻ link", ()=>shareLink(key))}
                                {f.status==="wip" && mi("checkCircle", "Gửi duyệt", ()=>doSubmit(f))}
                                <div style={{ height: 1, background: "var(--line-soft)", margin: "4px 6px" }} />
                                {mi("trash", "Xoá", ()=>doDelete(f), true)}
                              </div>
                            </>
                          );
                        })()}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          ) : (
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", gap: 16, padding: 22 }}>
              {filter==="all" && !q && subFolders.map(sf => {
                const n = files.filter(f => descendantIds(sf.id).includes(f.folder)).length;
                return (
                  <div key={sf.id} onClick={()=>navTo(sf.id)} className="card card-pad card-hover" style={{ display: "flex", alignItems: "center", gap: 12, padding: 16 }}>
                    <span style={{ width: 42, height: 42, borderRadius: 11, flex: "none", display: "grid", placeItems: "center", background: `${DISC_COL[sf.disc]||"var(--accent)"}1c`, color: DISC_COL[sf.disc]||"var(--accent)" }}><Icon.layers size={20} /></span>
                    <div><div style={{ fontWeight: 800, fontSize: 14 }}>{sf.name}</div><div style={{ fontSize: 12, color: "var(--ink-3)", fontWeight: 600 }}>{n} tệp</div></div>
                  </div>
                );
              })}
              {listing.map(f => {
                const st = STATUS[f.status]; const Sico = Icon[st.icon];
                return (
                  <div key={f.id} onClick={()=>setSel(f)} className="card card-hover" style={{ overflow: "hidden", border: sel?.id===f.id?"1.5px solid var(--accent)":undefined }}>
                    <div style={{ padding: 12 }}><SheetPreview file={f} /></div>
                    <div style={{ padding: "0 14px 14px" }}>
                      <div className="mono t-strong" style={{ fontSize: 12.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{f.name}</div>
                      <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 9, flexWrap: "wrap" }}>
                        <span className={`chip ${st.cls}`} style={{ height: 22, fontSize: 11 }}><Sico size={11} /> {st.label}</span>
                        <span className="tag-mono">{f.rev}</span>
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
          {listing.length === 0 && (subFolders.length === 0 || filter!=="all" || q) && (
            <div style={{ padding: 60, textAlign: "center", color: "var(--ink-3)" }}>
              <Icon.doc size={32} color="var(--ink-4)" />
              {(filter!=="all" || q) ? (
                <>
                  <div style={{ fontWeight: 700, marginTop: 12, fontSize: 14 }}>Không có hồ sơ phù hợp</div>
                  <div style={{ fontSize: 13, color: "var(--ink-4)", marginTop: 4 }}>Thử đổi bộ lọc hoặc từ khoá tìm kiếm</div>
                </>
              ) : (
                <>
                  <div style={{ fontWeight: 700, marginTop: 12, fontSize: 14 }}>Thư mục trống</div>
                  <div style={{ fontSize: 13, color: "var(--ink-4)", marginTop: 4 }}>Bấm “Nạp tài liệu” để bắt đầu</div>
                </>
              )}
            </div>
          )}
        </div>
        {sel && <DetailDrawer file={sel} live={live} onClose={()=>setSel(null)}
          onChanged={(newStatus)=>{ setSel(s => s ? { ...s, status: newStatus } : s); reload(); }} />}
        </div>
      </div>

      {uploading && <UploadModal folderName={curFolder.name} folderKey={subFolders[0]?.id || cur} live={live}
        onClose={()=>setUploading(false)} onAdd={addFile} onUploaded={reload} />}
      {creatingFolder && <CreateFolderModal parentName={curFolder.name} onClose={()=>setCreatingFolder(false)} onCreate={createFolder} />}
    </div>
  );
}

window.FileManager = FileManager;
