// asset-manager.jsx
// The media library UI + the admin field control that spawns it.
//
// Exports (window): AssetManager, AssetField
//   <AssetField kind="image"|"video" label hint value onChange />  — used by the
//     admin's ScalarField for fields typed "image"/"video".
//   <AssetManager assetType onSelect onClose />                    — the popover.
//
// Load AFTER React + asset-store.js. Styles are injected once on load.

const { useState: useAmState, useEffect: useAmEffect, useRef: useAmRef } = React;

const AM_CSS = `
  .am-overlay{position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;
    justify-content:center;padding:24px;background:rgba(10,9,7,.62);
    -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
    font:12px/1.45 ui-sans-serif,system-ui,-apple-system,sans-serif}
  .am-panel{width:min(780px,96vw);max-height:88vh;display:flex;flex-direction:column;
    background:rgba(250,249,247,.99);color:#29261b;border-radius:14px;overflow:hidden;
    box-shadow:0 24px 80px rgba(0,0,0,.5);border:.5px solid rgba(255,255,255,.6)}
  .am-hd{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:.5px solid rgba(0,0,0,.08)}
  .am-hd b{font-size:14px;font-weight:600}
  .am-pill{font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
    color:rgba(41,38,27,.5);background:rgba(0,0,0,.05);padding:3px 8px;border-radius:999px}
  .am-x{margin-left:auto;appearance:none;border:0;background:transparent;color:rgba(41,38,27,.55);
    width:28px;height:28px;border-radius:7px;cursor:pointer;font-size:15px}
  .am-x:hover{background:rgba(0,0,0,.06);color:#29261b}
  .am-tools{display:flex;gap:8px;align-items:center;padding:12px 16px;border-bottom:.5px solid rgba(0,0,0,.06);flex-wrap:wrap}
  .am-search{flex:1;min-width:140px;height:30px;padding:0 10px;border:.5px solid rgba(0,0,0,.12);
    border-radius:8px;background:#fff;font:inherit;outline:none}
  .am-search:focus{border-color:rgba(0,0,0,.3)}
  .am-btn{appearance:none;height:30px;padding:0 12px;border:0;border-radius:8px;font:inherit;
    font-weight:600;cursor:pointer;background:#29261b;color:#fff;white-space:nowrap}
  .am-btn:hover{background:#000}
  .am-btn.ghost{background:rgba(0,0,0,.06);color:#29261b}
  .am-btn.ghost:hover{background:rgba(0,0,0,.11)}
  .am-btn:disabled{opacity:.5;cursor:default}
  .am-urlrow{display:flex;gap:8px;width:100%}
  .am-urlrow input{flex:1;height:30px;padding:0 10px;border:.5px solid rgba(0,0,0,.12);border-radius:8px;background:#fff;font:inherit;outline:none}
  .am-body{padding:14px 16px;overflow-y:auto;min-height:160px}
  .am-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
  .am-card{border:1.5px solid transparent;border-radius:10px;overflow:hidden;cursor:pointer;
    background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.08);position:relative;transition:border-color .15s,transform .15s}
  .am-card:hover{border-color:rgba(0,0,0,.18);transform:translateY(-1px)}
  .am-thumb{aspect-ratio:16/10;background:#1a1714 center/cover no-repeat;display:flex;
    align-items:center;justify-content:center;position:relative}
  .am-thumb .ph{color:rgba(255,255,255,.3);font-size:10px;letter-spacing:.1em;text-transform:uppercase}
  .am-vthumb{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;background:#1a1714}
  .am-play{position:absolute;width:34px;height:34px;border-radius:50%;background:rgba(0,0,0,.5);
    border:1.5px solid rgba(255,255,255,.7);display:flex;align-items:center;justify-content:center}
  .am-play i{width:0;height:0;margin-left:2px;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:10px solid #fff}
  .am-meta{padding:8px 10px}
  .am-name{font-weight:600;font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;background:transparent;width:100%;padding:0;color:#29261b;font-family:inherit}
  .am-name:focus{outline:1px solid rgba(0,0,0,.25);border-radius:3px}
  .am-sub{font-size:10px;color:rgba(41,38,27,.45);margin-top:2px;display:flex;gap:6px;align-items:center}
  .am-ext{background:rgba(0,0,0,.06);border-radius:4px;padding:1px 4px;font-weight:600}
  .am-del{position:absolute;top:6px;right:6px;width:24px;height:24px;border-radius:6px;border:0;
    background:rgba(10,9,7,.55);color:#fff;cursor:pointer;font-size:12px;opacity:0;transition:opacity .15s;z-index:3}
  .am-card:hover .am-del{opacity:1}
  .am-del:hover{background:rgb(180,40,25)}
  .am-foot{padding:10px 16px;border-top:.5px solid rgba(0,0,0,.08);display:flex;
    align-items:center;justify-content:space-between;color:rgba(41,38,27,.5);font-size:10.5px}
  .am-empty{text-align:center;color:rgba(41,38,27,.45);padding:48px 16px;line-height:1.6}

  /* AssetField (in the admin panel) */
  .af-wrap{display:flex;flex-direction:column;gap:5px}
  .af-row{display:flex;gap:6px;align-items:center}
  .af-row .twk-field{flex:1}
  .af-mini{appearance:none;border:.5px solid rgba(0,0,0,.12);background:rgba(255,255,255,.6);
    color:#29261b;font:inherit;font-size:10.5px;font-weight:600;padding:5px 9px;border-radius:7px;cursor:pointer;white-space:nowrap}
  .af-mini:hover{background:#fff;border-color:rgba(0,0,0,.25)}
  .af-focal{position:relative;width:100%;aspect-ratio:2/1;border-radius:8px;overflow:hidden;
    cursor:crosshair;border:.5px solid rgba(0,0,0,.12);background:#1a1714}
  .af-focal img{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
  .af-dot{position:absolute;width:18px;height:18px;border-radius:50%;border:2px solid #fff;
    box-shadow:0 0 0 1.5px rgba(0,0,0,.5),0 1px 4px rgba(0,0,0,.5);transform:translate(-50%,-50%);pointer-events:none}
  .af-hint{font-size:10px;color:rgba(41,38,27,.42);line-height:1.35}
  .af-chip{display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:8px;
    background:rgba(0,0,0,.05);font-size:11px}
  .af-chip .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
`;

const amFmtBytes = (b) => b >= 1048576 ? (b / 1048576).toFixed(1) + " MB" : b >= 1024 ? Math.round(b / 1024) + " KB" : b ? b + " B" : "—";

// ── Media library popover ──────────────────────────────────────────
function AssetManager({ assetType, onSelect, onClose }) {
  const [assets, setAssets] = useAmState(null);
  const [query, setQuery] = useAmState("");
  const [busy, setBusy] = useAmState(false);
  const [err, setErr] = useAmState("");
  const [urlMode, setUrlMode] = useAmState(false);
  const [urlVal, setUrlVal] = useAmState("");
  const [renaming, setRenaming] = useAmState(null);
  const fileRef = useAmRef(null);

  const refresh = async () => { setAssets(await window.AssetStore.list()); };
  useAmEffect(() => { refresh(); }, []);
  useAmEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    const prev = document.body.style.overflow; document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = prev; };
  }, [onClose]);

  const typed = (assets || []).filter((a) => a.type === assetType);
  const shown = typed.filter((a) => a.name.toLowerCase().includes(query.toLowerCase()));
  const usage = (assets || []).reduce((s, a) => s + (a.size || 0), 0);

  const doUpload = async (files) => {
    setErr(""); setBusy(true);
    try {
      for (const f of files) {
        const isVid = (f.type || "").startsWith("video");
        if ((assetType === "image" && isVid) || (assetType === "video" && !isVid && f.type.startsWith("image"))) {
          setErr(`Skipped “${f.name}” — wrong type for this field.`); continue;
        }
        await window.AssetStore.upload(f);
      }
      await refresh();
    } catch (e) { setErr("Upload failed: " + e.message); }
    setBusy(false);
  };

  const addUrl = async () => {
    const u = urlVal.trim(); if (!u) return;
    setErr(""); setBusy(true);
    try { await window.AssetStore.addByUrl(u, assetType); setUrlVal(""); setUrlMode(false); await refresh(); }
    catch (e) { setErr("Couldn't add URL: " + e.message); }
    setBusy(false);
  };

  return (
    <div className="am-overlay" onClick={onClose}>
      <div className="am-panel" onClick={(e) => e.stopPropagation()}>
        <div className="am-hd">
          <b>Media library</b>
          <span className="am-pill">{assetType === "image" ? "Images" : "Videos"}</span>
          <button className="am-x" onClick={onClose} aria-label="Close">✕</button>
        </div>

        <div className="am-tools">
          <input className="am-search" placeholder="Search by name…" value={query} onChange={(e) => setQuery(e.target.value)} />
          <button className="am-btn" disabled={busy} onClick={() => fileRef.current && fileRef.current.click()}>
            {busy ? "Working…" : "Upload"}
          </button>
          <button className="am-btn ghost" onClick={() => setUrlMode((v) => !v)}>Add by URL</button>
          <input ref={fileRef} type="file" multiple style={{ display: "none" }}
            accept={assetType === "image" ? "image/*" : "video/*"}
            onChange={(e) => { doUpload([...e.target.files]); e.target.value = ""; }} />
          {urlMode && (
            <div className="am-urlrow">
              <input placeholder={assetType === "image" ? "https://…/image.jpg" : "https://…/video.mp4"}
                value={urlVal} autoFocus onChange={(e) => setUrlVal(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") addUrl(); }} />
              <button className="am-btn" disabled={busy} onClick={addUrl}>Add</button>
            </div>
          )}
          {err && <div style={{ width: "100%", color: "rgb(180,40,25)", fontSize: 10.5 }}>{err}</div>}
        </div>

        <div className="am-body">
          {assets === null ? (
            <div className="am-empty">Loading…</div>
          ) : shown.length === 0 ? (
            <div className="am-empty">
              {typed.length === 0
                ? `No ${assetType}s yet. Upload one or add by URL.`
                : "Nothing matches your search."}
            </div>
          ) : (
            <div className="am-grid">
              {shown.map((a) => (
                <div key={a.id} className="am-card" onClick={() => onSelect(a)}>
                  <button className="am-del" title="Delete" onClick={(e) => { e.stopPropagation(); if (confirm(`Delete “${a.name}”?`)) window.AssetStore.remove(a.id).then(refresh); }}>✕</button>
                  <div className="am-thumb" style={{ backgroundImage: (a.type === "image" || a.poster) ? `url("${a.type === "image" ? a.url : a.poster}")` : "none" }}>
                    {a.type === "video" && !a.poster && a.url && (
                      <video className="am-vthumb" src={a.url} muted playsInline preload="metadata"
                        onLoadedMetadata={(e) => { try { e.currentTarget.currentTime = Math.min(Math.max((e.currentTarget.duration || 0) * 0.1, 0.4), 2); } catch (err) {} }} />
                    )}
                    {a.type === "video" && <div className="am-play"><i /></div>}
                    {a.type === "image" && !a.url && <span className="ph">No preview</span>}
                  </div>
                  <div className="am-meta">
                    <input className="am-name" value={renaming && renaming.id === a.id ? renaming.name : a.name}
                      onClick={(e) => e.stopPropagation()}
                      onFocus={() => setRenaming({ id: a.id, name: a.name })}
                      onChange={(e) => setRenaming({ id: a.id, name: e.target.value })}
                      onBlur={() => { if (renaming) { window.AssetStore.rename(a.id, renaming.name).then(refresh); setRenaming(null); } }}
                      onKeyDown={(e) => { if (e.key === "Enter") e.target.blur(); }} />
                    <div className="am-sub">
                      {a.external && <span className="am-ext">URL</span>}
                      {a.width ? <span>{a.width}×{a.height}</span> : null}
                      {a.size ? <span>· {amFmtBytes(a.size)}</span> : null}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>

        <div className="am-foot">
          <span>{(assets || []).length} item{(assets || []).length === 1 ? "" : "s"} · {amFmtBytes(usage)} stored locally</span>
          <span>Click an item to use it</span>
        </div>
      </div>
    </div>
  );
}

// ── Focal-point picker (non-destructive crop framing) ──────────────
function FocalPicker({ url, focalX, focalY, onChange }) {
  const ref = useAmRef(null);
  const set = (clientX, clientY) => {
    const r = ref.current.getBoundingClientRect();
    const x = Math.min(1, Math.max(0, (clientX - r.left) / r.width));
    const y = Math.min(1, Math.max(0, (clientY - r.top) / r.height));
    onChange(Math.round(x * 100) / 100, Math.round(y * 100) / 100);
  };
  const onDown = (e) => {
    set(e.clientX, e.clientY);
    const move = (ev) => set(ev.clientX, ev.clientY);
    const up = () => { window.removeEventListener("pointermove", move); window.removeEventListener("pointerup", up); };
    window.addEventListener("pointermove", move); window.addEventListener("pointerup", up);
  };
  return (
    <div className="af-focal" ref={ref} onPointerDown={onDown}>
      <img src={url} alt="" style={{ objectPosition: `${focalX * 100}% ${focalY * 100}%` }} />
      <div className="af-dot" style={{ left: `${focalX * 100}%`, top: `${focalY * 100}%` }} />
    </div>
  );
}

// ── Admin control for image / video fields ─────────────────────────
function AssetField({ label, hint, kind, value, onChange }) {
  const [open, setOpen] = useAmState(false);

  if (kind === "image") {
    const v = value && typeof value === "object" ? value : { url: "", focalX: 0.5, focalY: 0.5 };
    const fx = typeof v.focalX === "number" ? v.focalX : 0.5;
    const fy = typeof v.focalY === "number" ? v.focalY : 0.5;
    return (
      <div className="twk-row">
        <div className="twk-lbl"><span>{label}</span></div>
        {hint && <div className="af-hint">{hint}</div>}
        <div className="af-wrap">
          {v.url ? (
            <>
              <FocalPicker url={v.url} focalX={fx} focalY={fy}
                onChange={(x, y) => onChange({ ...v, focalX: x, focalY: y })} />
              <div className="af-hint">Drag the dot to set the focal point (kept in frame at every crop).</div>
              <div className="af-row">
                <button className="af-mini" onClick={() => setOpen(true)}>Replace</button>
                <button className="af-mini" onClick={() => onChange({ url: "", focalX: 0.5, focalY: 0.5 })}>Clear</button>
              </div>
            </>
          ) : (
            <>
              <div className="af-row">
                <button className="af-mini" onClick={() => setOpen(true)}>Choose image…</button>
              </div>
              <input className="twk-field" placeholder="…or paste an image URL" value=""
                onChange={(e) => onChange({ ...v, url: e.target.value })} />
            </>
          )}
        </div>
        {open && <AssetManager assetType="image"
          onSelect={(a) => { onChange({ url: a.url, focalX: 0.5, focalY: 0.5 }); setOpen(false); }}
          onClose={() => setOpen(false)} />}
      </div>
    );
  }

  // video — value is a plain URL string
  const url = typeof value === "string" ? value : "";
  return (
    <div className="twk-row">
      <div className="twk-lbl"><span>{label}</span></div>
      {hint && <div className="af-hint">{hint}</div>}
      <div className="af-wrap">
        {url ? (
          <>
            <div className="af-chip"><span className="nm">{url.split("/").pop()}</span></div>
            <div className="af-row">
              <button className="af-mini" onClick={() => setOpen(true)}>Replace</button>
              <button className="af-mini" onClick={() => onChange("")}>Clear</button>
            </div>
          </>
        ) : (
          <>
            <div className="af-row">
              <button className="af-mini" onClick={() => setOpen(true)}>Choose video…</button>
            </div>
            <input className="twk-field" placeholder="…or paste a video URL" value=""
              onChange={(e) => onChange(e.target.value)} />
          </>
        )}
      </div>
      {open && <AssetManager assetType="video"
        onSelect={(a) => { onChange(a.url); setOpen(false); }}
        onClose={() => setOpen(false)} />}
    </div>
  );
}

(function () {
  if (!document.getElementById("__am_css")) {
    const s = document.createElement("style");
    s.id = "__am_css"; s.textContent = AM_CSS;
    document.head.appendChild(s);
  }
})();

Object.assign(window, { AssetManager, AssetField, FocalPicker });
