/* ---------- Table ---------- */
/* All tables: drag headers to reorder columns, gear menu to show/hide. Prefs persist per table. */

/* Columns declare a *physical* align ("right" for money/counts). Applied as-is
   that pins every cell to a physical edge, which inline styles put out of reach
   of the [dir="rtl"] rules — in Arabic the text columns stayed flush left and
   money stayed flush right, exactly backwards. Map to logical values instead so
   the browser flips them with the direction: start/end follow the writing mode. */
const logicalAlign = (align) =>
  align === "right" ? "end" : align === "left" ? "start" : align || "start";

/* `dense` is for tables that live in a narrow column (the 1fr side of a .grid-23):
   it trades cell padding for column width so they fit instead of side-scrolling. */
function DataTable({ cols, rows, rowKey, onRow, empty, tableId, expanded, dense }) {
  const { useState, useEffect, useRef } = React;
  const id = "verp-dt-" + (tableId || cols.map((c) => c.k).join("_"));

  const load = () => {
    try { return JSON.parse(localStorage.getItem(id)) || {}; } catch (e) { return {}; }
  };
  const reconcile = (saved) => {
    const keys = cols.map((c) => c.k);
    const order = (saved.order || []).filter((k) => keys.includes(k));
    keys.forEach((k) => { if (!order.includes(k)) order.push(k); });
    const hidden = (saved.hidden || []).filter((k) => keys.includes(k));
    return { order, hidden };
  };
  const [prefs, setPrefs] = useState(() => reconcile(load()));
  const [menu, setMenu] = useState(false);
  const [menuPos, setMenuPos] = useState(null);
  const [drag, setDrag] = useState(null);
  const [dragOver, setDragOver] = useState(null);
  const gearRef = useRef(null);
  const menuRef = useRef(null);

  useEffect(() => { setPrefs((p) => reconcile({ order: p.order, hidden: p.hidden })); }, [cols.map((c) => c.k).join(",")]);

  const save = (next) => {
    setPrefs(next);
    try { localStorage.setItem(id, JSON.stringify(next)); } catch (e) {}
  };

  useEffect(() => {
    if (!menu) return;
    const onDown = (e) => {
      if (menuRef.current && !menuRef.current.contains(e.target) && gearRef.current && !gearRef.current.contains(e.target)) setMenu(false);
    };
    document.addEventListener("mousedown", onDown);
    return () => document.removeEventListener("mousedown", onDown);
  }, [menu]);

  const byKey = {};
  cols.forEach((c) => { byKey[c.k] = c; });
  const ordered = prefs.order.map((k) => byKey[k]).filter(Boolean);
  const visibleCols = ordered.filter((c) => !prefs.hidden.includes(c.k));

  const toggle = (k) => {
    const hidden = prefs.hidden.includes(k) ? prefs.hidden.filter((x) => x !== k) : [...prefs.hidden, k];
    if (hidden.length >= ordered.length) { notify(T("table.keepOneColumn")); return; }
    save({ ...prefs, hidden });
  };

  const onDrop = (targetK) => {
    if (!drag || drag === targetK) { setDrag(null); setDragOver(null); return; }
    const order = prefs.order.filter((k) => k !== drag);
    order.splice(order.indexOf(targetK) + (prefs.order.indexOf(drag) < prefs.order.indexOf(targetK) ? 1 : 0), 0, drag);
    save({ ...prefs, order });
    setDrag(null); setDragOver(null);
  };

  const openMenu = () => {
    if (gearRef.current) {
      const r = gearRef.current.getBoundingClientRect();
      setMenuPos({ top: r.bottom + 6, right: Math.max(8, window.innerWidth - r.right - 4) });
    }
    setMenu((m) => !m);
  };

  return (
    <div className={"dt" + (dense ? " dense" : "")}>
      <table>
        <thead>
          <tr>
            {visibleCols.map((c) => (
              <th key={c.k} style={{ textAlign: logicalAlign(c.align), width: c.w }}
                draggable
                className={"dt-th" + (drag === c.k ? " dragging" : "") + (dragOver === c.k && drag !== c.k ? " dropover" : "")}
                title={T("table.dragToReorder")}
                onDragStart={(e) => { setDrag(c.k); e.dataTransfer.effectAllowed = "move"; }}
                onDragOver={(e) => { e.preventDefault(); setDragOver(c.k); }}
                onDragLeave={() => setDragOver((d) => (d === c.k ? null : d))}
                onDrop={(e) => { e.preventDefault(); onDrop(c.k); }}
                onDragEnd={() => { setDrag(null); setDragOver(null); }}>
                {c.label}
              </th>
            ))}
            <th className="dt-gearcell">
              <button ref={gearRef} className={"dt-gear" + (menu ? " on" : "")} onClick={openMenu} title={T("table.showHideColumns")} aria-label={T("table.columnSettings")}>
                <Icon name="sliders" size={14} />
              </button>
            </th>
          </tr>
        </thead>
        <tbody>
          {rows.length === 0 ? (
            <tr><td className="dt-empty" colSpan={visibleCols.length + 1}>{empty || T("table.emptyDefault")}</td></tr>
          ) : rows.map((r) => (
            <React.Fragment key={rowKey(r)}>
            <tr className={onRow ? "clickable" : ""} onClick={onRow ? () => onRow(r) : undefined}>
              {visibleCols.map((c) => (
                <td key={c.k} style={{ textAlign: logicalAlign(c.align) }}>{c.render ? c.render(r) : r[c.k]}</td>
              ))}
              <td></td>
            </tr>
            {expanded && expanded(r) ? (
              <tr className="dt-expand"><td colSpan={visibleCols.length + 1}>{expanded(r)}</td></tr>
            ) : null}
            </React.Fragment>
          ))}
        </tbody>
      </table>
      {menu ? (
        <div ref={menuRef} className="dt-menu" style={menuPos || {}}>
          <div className="dt-menu-head">{T("table.columns")}</div>
          {ordered.map((c) => (
            <button key={c.k} className="dt-menu-row" onClick={() => toggle(c.k)}>
              <span className={"dt-tick" + (!prefs.hidden.includes(c.k) ? " on" : "")}>
                {!prefs.hidden.includes(c.k) ? <Icon name="check" size={12} stroke={2.6} /> : null}
              </span>
              <span>{c.label || c.k}</span>
            </button>
          ))}
          <div className="dt-menu-hint">{T("table.dragHeadersHint")}</div>
        </div>
      ) : null}
    </div>
  );
}


Object.assign(window, { DataTable });
