/* ============================================================
   Custom document properties — type meta, cell render, value editor
   ============================================================ */
const PROP_TYPES = [
  { type: "text",         label: "Văn bản",    icon: "doc" },
  { type: "number",       label: "Số",         icon: "hash" },
  { type: "select",       label: "Chọn 1",     icon: "chevUD" },
  { type: "multi_select", label: "Chọn nhiều", icon: "layers" },
  { type: "folder",       label: "Folder mở",  icon: "folder" },
  { type: "status",       label: "Trạng thái", icon: "checkCircle" },
  { type: "date",         label: "Ngày",       icon: "calendar" },
  { type: "person",       label: "Người",      icon: "users" },
  { type: "url",          label: "Liên kết",   icon: "link" },
  { type: "checkbox",     label: "Đánh dấu",   icon: "check" },
];
const PROP_COLORS = ["#14b8a6","#60a5fa","#a78bfa","#f59e0b","#ef4444","#10b981","#6b7280"];
// "folder" carries options too (admin seed + member-added via add_folder_option RPC)
const OPT_TYPES = ["select", "multi_select", "status", "folder"]; // types that carry coloured options
// signature colour per property type (icon tiles in admin UI)
const PROP_TYPE_COLORS = { text: "#60a5fa", number: "#f59e0b", select: "#a78bfa", multi_select: "#14b8a6", folder: "#eab308", status: "#10b981", date: "#f472b6", person: "#fb923c", url: "#38bdf8", checkbox: "#34d399" };

function optLabel(prop, id) { return (prop.options || []).find(x => x.id === id) || null; }
function fmtDate(s) { if (!s) return ""; const d = new Date(s); return isNaN(d) ? s : (String(d.getDate()).padStart(2,"0")+"/"+String(d.getMonth()+1).padStart(2,"0")+"/"+d.getFullYear()); }
function initialsOfName(name) { const p = String(name||"").trim().split(/\s+/); return ((p[p.length-1]?.[0]||"")+(p.length>1?p[0][0]:"")).toUpperCase() || "?"; }

function Chip({ o, dot }) {
  return <span style={{ display: "inline-flex", alignItems: "center", gap: 5, height: 20, padding: "0 8px", borderRadius: 99, fontSize: 11, fontWeight: 700,
    color: o.color || "var(--ink-2)", background: (o.color || "#6b7280") + "22" }}>
    {dot && <span style={{ width: 6, height: 6, borderRadius: 99, background: o.color || "var(--ink-3)", flex: "none" }} />}{o.label}</span>;
}

// read-only cell render of a value for a given property
function PropCell({ prop, value }) {
  if (value == null || value === "" || (Array.isArray(value) && !value.length))
    return <span style={{ color: "var(--ink-4)" }}>—</span>;
  if (prop.type === "checkbox") return value ? <Icon.check size={15} color="var(--ok)" /> : <span style={{ color: "var(--ink-4)" }}>—</span>;
  if (prop.type === "number") return <span className="tnum">{value}</span>;
  if (prop.type === "date") return <span>{fmtDate(value)}</span>;
  if (prop.type === "url") return <a href={value} target="_blank" rel="noopener noreferrer" onClick={e => e.stopPropagation()}
    style={{ color: "var(--accent)", textDecoration: "none", display: "inline-flex", alignItems: "center", gap: 4, fontWeight: 600 }}>
    <Icon.link size={12} />{String(value).replace(/^https?:\/\//, "").slice(0, 28)}</a>;
  if (prop.type === "person") return <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
    <span className="avatar" style={{ width: 20, height: 20, fontSize: 9.5 }}>{initialsOfName(value)}</span>{value}</span>;
  if (prop.type === "select" || prop.type === "folder") { const o = optLabel(prop, value); return o ? <Chip o={o} /> : <span style={{ color: "var(--ink-4)" }}>—</span>; }
  if (prop.type === "status") { const o = optLabel(prop, value); return o ? <Chip o={o} dot /> : <span style={{ color: "var(--ink-4)" }}>—</span>; }
  if (prop.type === "multi_select") return <span style={{ display: "inline-flex", gap: 4, flexWrap: "wrap" }}>{value.map(id => { const o = optLabel(prop, id); return o ? <Chip key={id} o={o} /> : null; })}</span>;
  return <span>{String(value)}</span>;
}

const propInp = { width: "100%", height: 36, padding: "0 10px", borderRadius: 8, border: "1px solid var(--line)", background: "var(--surface)", color: "var(--ink)", font: "inherit", fontSize: 13, fontWeight: 600, outline: "none" };

// dynamic member picker for the Person type (loads the project roster)
function PersonEditor({ value, onChange }) {
  const [members, setMembers] = React.useState([]);
  React.useEffect(() => { if (window.cdeData && cdeData.members) cdeData.members().then(setMembers).catch(() => setMembers([])); }, []);
  return <select style={propInp} value={value || ""} onChange={e => onChange(e.target.value || null)}>
    <option value="">—</option>
    {members.map(m => <option key={m.id} value={m.name}>{m.name}</option>)}
  </select>;
}

// "Folder mở" value editor: pick an existing folder OR create a new one inline (persists
// project-wide via add_folder_option). New folder shows in the tree on next props reload.
function FolderEditor({ prop, value, onChange }) {
  const [opts, setOpts] = React.useState(prop.options || []);
  const [adding, setAdding] = React.useState(false);
  const [name, setName] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => { setOpts(prop.options || []); }, [prop.id, (prop.options || []).length]);
  const add = async () => {
    const label = name.trim(); if (!label || busy) return;
    setBusy(true);
    try {
      const o = await cdeData.addFolderOption(prop.id, label);
      setOpts(prev => prev.find(x => x.id === o.id) ? prev : [...prev, o]);
      onChange(o.id); setName(""); setAdding(false);
      if (typeof window.cdeReloadFiles === "function") window.cdeReloadFiles();
    } catch (e) { window.alert(e.message || "Tạo folder thất bại"); }
    finally { setBusy(false); }
  };
  return (
    <div>
      <select style={propInp} value={value || ""} onChange={e => onChange(e.target.value || null)}>
        <option value="">—</option>
        {opts.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
      </select>
      {adding ? (
        <div style={{ display: "flex", gap: 6, marginTop: 6 }}>
          <input autoFocus style={{ ...propInp, height: 32 }} value={name} placeholder="Tên folder mới"
            onChange={e => setName(e.target.value)} onKeyDown={e => { if (e.key === "Enter") add(); }} />
          <button className="btn sm" disabled={busy} onClick={add}>{busy ? "…" : "Thêm"}</button>
          <button className="btn sm" onClick={() => { setAdding(false); setName(""); }}>Huỷ</button>
        </div>
      ) : (
        <button className="btn sm" style={{ marginTop: 6 }} onClick={() => setAdding(true)}><Icon.plus size={12} /> Tạo folder mới</button>
      )}
    </div>
  );
}

// editable input for a value (used in the drawer). onChange(newValue).
function PropEditor({ prop, value, onChange }) {
  if (prop.type === "folder") return <FolderEditor prop={prop} value={value} onChange={onChange} />;
  if (prop.type === "text")   return <input style={propInp} value={value || ""} onChange={e => onChange(e.target.value)} />;
  if (prop.type === "number") return <input style={propInp} type="number" value={value ?? ""} onChange={e => onChange(e.target.value === "" ? null : Number(e.target.value))} />;
  if (prop.type === "date")   return <input style={propInp} type="date" value={value || ""} onChange={e => onChange(e.target.value || null)} />;
  if (prop.type === "url")    return <input style={propInp} type="url" placeholder="https://…" value={value || ""} onChange={e => onChange(e.target.value || null)} />;
  if (prop.type === "person") return <PersonEditor value={value} onChange={onChange} />;
  if (prop.type === "checkbox") return <input type="checkbox" checked={!!value} onChange={e => onChange(e.target.checked)} style={{ width: 16, height: 16, accentColor: "var(--accent)" }} />;
  if (prop.type === "select" || prop.type === "status")
    return <select style={propInp} value={value || ""} onChange={e => onChange(e.target.value || null)}>
      <option value="">—</option>
      {(prop.options || []).map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
    </select>;
  if (prop.type === "multi_select") {
    const arr = Array.isArray(value) ? value : [];
    const toggle = id => onChange(arr.includes(id) ? arr.filter(x => x !== id) : [...arr, id]);
    return <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
      {(prop.options || []).map(o => {
        const on = arr.includes(o.id);
        return <span key={o.id} onClick={() => toggle(o.id)} style={{ cursor: "pointer", height: 24, padding: "0 9px", borderRadius: 99, fontSize: 11.5, fontWeight: 700, display: "inline-flex", alignItems: "center",
          color: on ? "#fff" : (o.color || "var(--ink-3)"), background: on ? (o.color || "var(--accent)") : ((o.color || "#6b7280") + "1c") }}>{o.label}</span>;
      })}
    </div>;
  }
  return null;
}

// icon picker — choose a Lucide glyph for a property (uses window.PROP_ICON_GROUPS / window.PropIcon)
function IconPicker({ value, onChange }) {
  const [open, setOpen] = React.useState(false);
  const [q, setQ] = React.useState("");
  const [pos, setPos] = React.useState({ top: 0, left: 0, maxH: 432, up: false });
  const ref = React.useRef(null);
  const PW = 392, GAP = 6, MGN = 10;
  const place = React.useCallback(() => {
    const el = ref.current; if (!el) return;
    const r = el.getBoundingClientRect();
    const below = window.innerHeight - r.bottom - MGN;
    const above = r.top - MGN;
    const up = below < 300 && above > below;
    const maxH = Math.max(220, Math.min(432, (up ? above : below) - GAP));
    const left = Math.max(MGN, Math.min(r.left, window.innerWidth - PW - MGN));
    setPos({ top: up ? r.top - GAP : r.bottom + GAP, left, maxH, up });
  }, []);
  React.useLayoutEffect(() => {
    if (!open) return;
    place();
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    const onMove = () => place();
    document.addEventListener("mousedown", h);
    window.addEventListener("scroll", onMove, true);
    window.addEventListener("resize", onMove);
    return () => {
      document.removeEventListener("mousedown", h);
      window.removeEventListener("scroll", onMove, true);
      window.removeEventListener("resize", onMove);
    };
  }, [open, place]);
  const groups = window.PROP_ICON_GROUPS || [];
  const query = q.trim().toLowerCase();
  const pick = (name) => { onChange(name); setOpen(false); setQ(""); };
  const hasResults = groups.some(g => g.names.some(n => !query || n.includes(query)));
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button type="button" onClick={() => setOpen(o => !o)}
        style={{ display: "inline-flex", alignItems: "center", justifyContent: "space-between", gap: 10, width: 220, height: 40, padding: "0 10px 0 9px", borderRadius: 9, cursor: "pointer", font: "inherit", fontSize: 13, fontWeight: 600,
          border: open ? "1.5px solid var(--accent)" : "1px solid var(--line)", background: "var(--surface)", color: "var(--ink)" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 9, minWidth: 0 }}>
          <span style={{ width: 26, height: 26, borderRadius: 7, flex: "none", display: "grid", placeItems: "center", background: value ? "var(--accent-soft)" : "var(--sunken)", color: value ? "var(--accent)" : "var(--ink-4)" }}>
            {value && window.PropIcon ? <window.PropIcon name={value} size={16} /> : window.PropIcon ? <window.PropIcon name="image" size={15} /> : <Icon.plus size={14} />}
          </span>
          <span style={{ color: value ? "var(--ink)" : "var(--ink-3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{value ? "Biểu tượng" : "Chọn biểu tượng"}</span>
        </span>
        <Icon.chevD size={14} style={{ flex: "none", color: "var(--ink-4)", transform: open ? "rotate(180deg)" : "none", transition: "transform .15s" }} />
      </button>
      {open && (
        <div style={{ position: "fixed", zIndex: 200, top: pos.top, left: pos.left, transform: pos.up ? "translateY(-100%)" : "none", width: PW, maxHeight: pos.maxH, display: "flex", flexDirection: "column", overflow: "hidden", borderRadius: 13, border: "1px solid var(--line)", background: "var(--surface)", boxShadow: "var(--shadow-lg)" }}>
          <div style={{ padding: 12, borderBottom: "1px solid var(--line)" }}>
            <div style={{ position: "relative" }}>
              <span style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)", color: "var(--ink-4)", pointerEvents: "none", display: "flex" }}><Icon.search size={15} /></span>
              <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Tìm biểu tượng…"
                style={{ width: "100%", height: 38, padding: "0 12px 0 34px", borderRadius: 9, border: "1px solid var(--line)", background: "var(--sunken)", color: "var(--ink)", font: "inherit", fontSize: 13, fontWeight: 500, outline: "none" }} />
            </div>
          </div>
          <div style={{ flex: 1, minHeight: 0, overflowY: "auto", padding: "8px 12px 12px" }}>
            <button type="button" onClick={() => pick(null)}
              onMouseEnter={e => { if (value) e.currentTarget.style.background = "var(--sunken)"; }}
              onMouseLeave={e => { if (value) e.currentTarget.style.background = "transparent"; }}
              style={{ display: "flex", alignItems: "center", gap: 9, width: "100%", height: 36, padding: "0 9px", borderRadius: 8, border: "none", cursor: "pointer", font: "inherit", fontSize: 13, fontWeight: 600, transition: "background .12s",
                background: !value ? "var(--accent-soft)" : "transparent", color: !value ? "var(--accent)" : "var(--ink-3)" }}>
              <Icon.ban size={16} /> Không có biểu tượng
            </button>
            {!hasResults && (
              <div style={{ padding: "26px 0", textAlign: "center", color: "var(--ink-4)", fontSize: 12.5, fontWeight: 600 }}>
                Không tìm thấy biểu tượng nào
              </div>
            )}
            {groups.map(g => {
              const names = g.names.filter(n => !query || n.includes(query));
              if (!names.length) return null;
              return (
                <div key={g.label} style={{ marginTop: 12 }}>
                  <div style={{ fontSize: 11, fontWeight: 700, color: "var(--ink-4)", margin: "0 2px 8px" }}>{g.label}</div>
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(7, 1fr)", gap: 5 }}>
                    {names.map(n => {
                      const on = value === n;
                      return (
                        <button key={n} type="button" title={n} onClick={() => pick(n)}
                          onMouseEnter={e => { if (!on) e.currentTarget.style.background = "var(--sunken)"; }}
                          onMouseLeave={e => { if (!on) e.currentTarget.style.background = "transparent"; }}
                          style={{ height: 40, display: "grid", placeItems: "center", borderRadius: 9, cursor: "pointer", transition: "background .12s, color .12s",
                            border: on ? "1.5px solid var(--accent)" : "1px solid transparent",
                            background: on ? "var(--accent-soft)" : "transparent", color: on ? "var(--accent)" : "var(--ink-3)" }}>
                          {window.PropIcon ? <window.PropIcon name={n} size={19} /> : null}
                        </button>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

// reusable property form — create (no `prop`) or edit (`prop` given); name + icon + tile type picker + option editor
// `personal`: target the caller's own user_doc_properties instead of the project pool
function PropertyForm({ prop, onCreated, personal }) {
  const editing = !!(prop && prop.id);
  const [name, setName] = React.useState(editing ? prop.name : "");
  const [type, setType] = React.useState(editing ? prop.type : "text");
  const [icon, setIcon] = React.useState(editing && prop.icon ? prop.icon : null);
  const [options, setOptions] = React.useState(editing && prop.options ? prop.options.map(o => ({ ...o })) : []);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState("");
  const needsOptions = OPT_TYPES.includes(type);
  const addOpt = () => setOptions(o => [...o, { id: "o" + Date.now().toString(36) + o.length, label: "", color: PROP_COLORS[o.length % PROP_COLORS.length] }]);
  const setOpt = (i, patch) => setOptions(o => o.map((x, j) => j === i ? { ...x, ...patch } : x));
  const delOpt = (i) => setOptions(o => o.filter((_, j) => j !== i));
  const save = async () => {
    if (!name.trim()) { setErr("Nhập tên thuộc tính"); return; }
    setBusy(true); setErr("");
    const body = { name: name.trim(), type, icon: icon || null, options: needsOptions ? options.filter(o => o.label.trim()) : null };
    try {
      if (editing) await (personal ? cdeData.updateUserProperty(prop.id, body) : cdeData.updateProperty(prop.id, body));
      else {
        await (personal ? cdeData.createUserProperty(body) : cdeData.createProperty(body));
        setName(""); setType("text"); setIcon(null); setOptions([]);
      }
      onCreated && onCreated();
    } catch (e) { setErr(e.message || (personal ? "Lưu thất bại" : "Lưu thất bại (cần quyền admin)")); }
    finally { setBusy(false); }
  };
  const inp = { width: "100%", height: 38, padding: "0 10px", borderRadius: 9, border: "1px solid var(--line)", background: "var(--sunken)", color: "var(--ink)", font: "inherit", fontSize: 13.5, fontWeight: 600, outline: "none" };
  const lbl = { display: "block", fontSize: 11, fontWeight: 800, letterSpacing: ".06em", color: "var(--ink-4)", margin: "14px 0 7px" };
  return (
    <div>
      <label style={lbl}>TÊN THUỘC TÍNH</label>
      <input style={inp} value={name} onChange={e => setName(e.target.value)} placeholder="VD: Gói thầu, Hạng mục, Ưu tiên…" />
      <label style={lbl}>KIỂU DỮ LIỆU</label>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 7 }}>
        {PROP_TYPES.map(t => {
          const Ico = Icon[t.icon] || Icon.doc;
          const on = type === t.type;
          const c = PROP_TYPE_COLORS[t.type] || "#6b7280";
          return (
            <button key={t.type} onClick={() => setType(t.type)}
              style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 7, padding: "11px 4px 9px", borderRadius: 11, cursor: "pointer",
                border: on ? "1.5px solid var(--accent)" : "1px solid var(--line)", background: on ? "var(--accent-soft)" : "var(--surface)",
                color: on ? "var(--accent)" : "var(--ink-2)", font: "inherit", fontSize: 12, fontWeight: 700, transition: "all .12s" }}>
              <span style={{ width: 30, height: 30, borderRadius: 9, display: "grid", placeItems: "center", background: c + "22", color: c }}><Ico size={15} /></span>
              {t.label}
            </button>
          );
        })}
      </div>
      <label style={lbl}>ICON</label>
      <IconPicker value={icon} onChange={setIcon} />
      {needsOptions && (
        <div>
          <label style={lbl}>LỰA CHỌN</label>
          {options.map((o, i) => (
            <div key={o.id} style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 6 }}>
              <span style={{ display: "flex", gap: 3, flex: "none" }}>
                {PROP_COLORS.map(c => <span key={c} onClick={() => setOpt(i, { color: c })} style={{ width: 15, height: 15, borderRadius: 99, background: c, cursor: "pointer", outline: o.color === c ? "2px solid var(--ink)" : "none", outlineOffset: 1 }} />)}
              </span>
              <input style={{ ...inp, height: 32 }} value={o.label} onChange={e => setOpt(i, { label: e.target.value })} placeholder="Nhãn" />
              <button className="icon-btn" style={{ width: 28, height: 28, flex: "none" }} onClick={() => delOpt(i)}>✕</button>
            </div>
          ))}
          <button className="btn sm" onClick={addOpt}><Icon.plus size={13} /> Thêm lựa chọn</button>
        </div>
      )}
      {err && <div style={{ marginTop: 10, fontSize: 12, color: "var(--danger)", fontWeight: 600 }}>{err}</div>}
      <button className="btn primary" disabled={busy} style={{ marginTop: 16, width: "100%", justifyContent: "center" }} onClick={save}>
        {editing ? <Icon.check size={14} /> : <Icon.plus size={14} />} {busy ? "Đang lưu…" : (editing ? "Lưu thay đổi" : "Thêm thuộc tính")}
      </button>
    </div>
  );
}

function PropertyManager({ properties, onClose, onChanged }) {
  const [name, setName] = React.useState("");
  const [type, setType] = React.useState("text");
  const [options, setOptions] = React.useState([]);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState("");
  const needsOptions = OPT_TYPES.includes(type);
  const addOpt = () => setOptions(o => [...o, { id: "o" + Date.now().toString(36) + o.length, label: "", color: PROP_COLORS[o.length % PROP_COLORS.length] }]);
  const setOpt = (i, patch) => setOptions(o => o.map((x, j) => j === i ? { ...x, ...patch } : x));
  const delOpt = (i) => setOptions(o => o.filter((_, j) => j !== i));
  const create = async () => {
    if (!name.trim()) { setErr("Nhập tên thuộc tính"); return; }
    setBusy(true); setErr("");
    try {
      await cdeData.createProperty({ name: name.trim(), type, options: needsOptions ? options.filter(o => o.label.trim()) : null });
      setName(""); setType("text"); setOptions([]); onChanged && onChanged();
    } catch (e) { setErr(e.message || "Tạo thất bại (cần quyền admin)"); }
    finally { setBusy(false); }
  };
  const remove = async (p) => {
    if (!window.confirm(`Xoá thuộc tính "${p.name}"? Dữ liệu đã nhập sẽ bị ẩn.`)) return;
    try { await cdeData.deleteProperty(p.id); onChanged && onChanged(); }
    catch (e) { window.alert("Xoá thất bại: " + e.message); }
  };
  const inp = { width: "100%", height: 38, padding: "0 10px", borderRadius: 8, border: "1px solid var(--line)", background: "var(--surface)", color: "var(--ink)", font: "inherit", fontSize: 13.5, fontWeight: 600, outline: "none" };
  const lbl = { display: "block", fontSize: 11.5, fontWeight: 700, color: "var(--ink-3)", margin: "12px 0 6px" };
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 55, background: "rgba(8,19,23,.5)", backdropFilter: "blur(3px)", display: "grid", placeItems: "center" }}>
      <div onClick={e => e.stopPropagation()} className="card" style={{ width: 480, maxHeight: "90vh", overflowY: "auto", padding: 22, boxShadow: "var(--shadow-lg)" }}>
        <div style={{ fontWeight: 800, fontSize: 16 }}>Thuộc tính tài liệu</div>
        <div style={{ fontSize: 12.5, color: "var(--ink-3)", fontWeight: 500, marginTop: 2 }}>Chỉ quản trị viên định nghĩa được</div>

        {properties.length > 0 && (
          <div style={{ marginTop: 14 }}>
            {properties.map(p => {
              const meta = PROP_TYPES.find(t => t.type === p.type) || {};
              const Ico = Icon[meta.icon] || Icon.doc;
              return (
                <div key={p.id} style={{ display: "flex", alignItems: "center", gap: 9, padding: "8px 0", borderBottom: "1px solid var(--line-soft)" }}>
                  <Ico size={15} color="var(--ink-3)" />
                  <span style={{ flex: 1, fontWeight: 700, fontSize: 13 }}>{p.name}</span>
                  <span style={{ fontSize: 11.5, color: "var(--ink-4)", fontWeight: 700 }}>{meta.label || p.type}</span>
                  <button className="icon-btn" style={{ width: 28, height: 28, borderRadius: 7 }} title="Xoá" onClick={() => remove(p)}><Icon.trash size={14} /></button>
                </div>
              );
            })}
          </div>
        )}

        <div style={{ marginTop: 16, padding: 14, borderRadius: 10, background: "var(--sunken)" }}>
          <div style={{ fontSize: 12.5, fontWeight: 800 }}>Thêm thuộc tính</div>
          <label style={lbl}>Tên</label>
          <input style={inp} value={name} onChange={e => setName(e.target.value)} placeholder="VD: Gói thầu" />
          <label style={lbl}>Kiểu</label>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6 }}>
            {PROP_TYPES.map(t => {
              const Ico = Icon[t.icon] || Icon.doc;
              const on = type === t.type;
              return (
                <button key={t.type} onClick={() => setType(t.type)}
                  style={{ display: "flex", alignItems: "center", gap: 9, padding: "9px 11px", borderRadius: 9, cursor: "pointer", textAlign: "left",
                    border: `1px solid ${on ? "var(--accent)" : "var(--line)"}`, background: on ? "var(--accent-soft)" : "var(--surface)",
                    color: on ? "var(--accent)" : "var(--ink-2)", font: "inherit", fontSize: 13, fontWeight: 700 }}>
                  <Ico size={16} /> {t.label}
                </button>
              );
            })}
          </div>
          {needsOptions && (
            <div style={{ marginTop: 12 }}>
              <label style={lbl}>Lựa chọn</label>
              {options.map((o, i) => (
                <div key={o.id} style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }}>
                  <span style={{ display: "flex", gap: 3 }}>
                    {PROP_COLORS.map(c => <span key={c} onClick={() => setOpt(i, { color: c })} style={{ width: 14, height: 14, borderRadius: 4, background: c, cursor: "pointer", outline: o.color === c ? "2px solid var(--ink)" : "none" }} />)}
                  </span>
                  <input style={{ ...inp, height: 32 }} value={o.label} onChange={e => setOpt(i, { label: e.target.value })} placeholder="Nhãn" />
                  <button className="icon-btn" style={{ width: 28, height: 28 }} onClick={() => delOpt(i)}>✕</button>
                </div>
              ))}
              <button className="btn sm" onClick={addOpt}><Icon.plus size={13} /> Thêm lựa chọn</button>
            </div>
          )}
          {err && <div style={{ marginTop: 10, fontSize: 12, color: "var(--danger)", fontWeight: 600 }}>{err}</div>}
          <button className="btn primary" disabled={busy} style={{ marginTop: 12, width: "100%", justifyContent: "center" }} onClick={create}>
            <Icon.plus size={14} /> {busy ? "Đang thêm…" : "Thêm thuộc tính"}
          </button>
        </div>

        <div style={{ display: "flex", justifyContent: "flex-end", marginTop: 16 }}>
          <button className="btn" onClick={onClose}>Đóng</button>
        </div>
      </div>
    </div>
  );
}

window.PROP_TYPES = PROP_TYPES; window.PROP_COLORS = PROP_COLORS; window.OPT_TYPES = OPT_TYPES; window.PROP_TYPE_COLORS = PROP_TYPE_COLORS;
window.PropCell = PropCell; window.PropEditor = PropEditor; window.PropChip = Chip;
window.PropertyForm = PropertyForm; window.PropertyManager = PropertyManager;
window.IconPicker = IconPicker;
