/* FILES space — folder sidebar + file card grid, wired to Cloudinary + Supabase.
   Real schema: files(id,name,url,public_id,size[bytes],type[mime],folder_id,created_at),
   folders(id,name,type='file'). */

function fmtBytes(n) {
  if (n == null) return '';
  if (n < 1024) return n + ' B';
  if (n < 1024 * 1024) return (n / 1024).toFixed(0) + ' KB';
  return (n / 1048576).toFixed(1) + ' MB';
}
function kindOf(f) {
  const mime = (f.type || '').toLowerCase();
  const ext = (f.name.split('.').pop() || '').toLowerCase();
  if (mime.startsWith('image/') || ['png','jpg','jpeg','gif','webp','svg'].includes(ext)) return 'img';
  return 'doc';
}

function FilesSpace({ tabs, utils }) {
  const DB = window.VaultDB;
  const [files, setFiles] = React.useState([]);
  const [folders, setFolders] = React.useState([]);   // [{id,name}]
  const [query, setQuery] = React.useState('');
  const [filter, setFilter] = React.useState(null);    // folder_id or null = all
  const [loaded, setLoaded] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [dragId, setDragId] = React.useState(null);
  const [dropTarget, setDropTarget] = React.useState(null); // folder_id | 'loose'
  const [adding, setAdding] = React.useState(false);
  const [newName, setNewName] = React.useState('');
  const fileInputRef = React.useRef(null);

  const fromRow = (r) => ({ id: r.id, folder_id: r.folder_id || null, name: r.name, url: r.url, public_id: r.public_id, size: r.size, type: r.type, kind: kindOf(r), ts: new Date(r.created_at || Date.now()).getTime() });

  React.useEffect(() => {
    let alive = true;
    (async () => {
      try {
        const [fl, fs] = await Promise.all([DB.files.list(), DB.folders.list('file')]);
        if (!alive) return;
        setFiles(fl.map(fromRow));
        setFolders(fs.map(f => ({ id: f.id, name: f.name })));
        setLoaded(true);
      } catch (e) { setLoaded(true); }
    })();
    const unsub = DB.subscribe((table) => {
      if (table === 'files') DB.files.list().then(fl => setFiles(fl.map(fromRow))).catch(() => {});
      if (table === 'folders') DB.folders.list('file').then(fs => setFolders(fs.map(f => ({ id: f.id, name: f.name })))).catch(() => {});
    });
    return () => { alive = false; unsub(); };
  }, []);

  const folderName = (id) => (folders.find(f => f.id === id) || {}).name || '';
  const q = query.trim().toLowerCase();
  const visible = files.filter(f => (!q || f.name.toLowerCase().includes(q)) && (filter == null || f.folder_id === filter));

  const doUpload = async (fileList) => {
    const arr = [...fileList];
    if (!arr.length) return;
    setBusy(true);
    for (const file of arr) {
      try {
        const row = await DB.files.upload(file, filter || null);
        setFiles(prev => [fromRow(row), ...prev]);
      } catch (e) { /* surfaced via realtime / next load */ }
    }
    setBusy(false);
  };
  const del = async (f) => {
    if (!confirm('Delete "' + f.name + '"? This cannot be undone.')) return;
    setFiles(prev => prev.filter(x => x.id !== f.id));
    try { await DB.files.remove(f.id, f.public_id); } catch (e) {}
  };
  const rename = async (f) => {
    const next = prompt('Rename file', f.name);
    if (!next || !next.trim() || next.trim() === f.name) return;
    const nm = next.trim();
    setFiles(prev => prev.map(x => x.id === f.id ? { ...x, name: nm, kind: kindOf({ name: nm, type: x.type }) } : x));
    try { await DB.files.rename(f.id, nm); } catch (e) {}
  };
  const moveFile = async (id, folder_id) => {
    setFiles(prev => prev.map(x => x.id === id ? { ...x, folder_id } : x));
    try { await DB.files.move(id, folder_id); } catch (e) {}
  };
  const addFolder = async () => {
    const name = newName.trim();
    setNewName(''); setAdding(false);
    if (!name) return;
    if (folders.some(fd => fd.name.toLowerCase() === name.toLowerCase())) return;
    try { const fd = await DB.folders.create(name, 'file'); setFolders(prev => [...prev, { id: fd.id, name: fd.name }]); setFilter(fd.id); } catch (e) {}
  };
  const deleteFolder = async (fd, e) => {
    e.stopPropagation();
    if (!confirm('Delete folder "' + fd.name + '"? Files inside become loose files.')) return;
    setFolders(prev => prev.filter(x => x.id !== fd.id));
    setFiles(prev => prev.map(x => x.folder_id === fd.id ? { ...x, folder_id: null } : x));
    if (filter === fd.id) setFilter(null);
    try { await DB.folders.remove(fd.id); } catch (e2) {}
  };
  // Only ever navigate to http(s) URLs — a stored javascript:/data: URL must
  // never be opened (it would execute in the vault's origin).
  const safeUrl = (u) => { try { return ['http:', 'https:'].includes(new URL(u, location.href).protocol) ? u : null; } catch (e) { return null; } };
  const open = (f) => { const u = safeUrl(f.url); if (u) window.open(u, '_blank', 'noopener'); else alert('This file has an unsafe link and won’t be opened.'); };
  const download = (f) => {
    const u = safeUrl(DB.files.downloadUrl(f.url)); if (!u) { alert('This file has an unsafe link and won’t be downloaded.'); return; }
    const a = document.createElement('a'); a.href = u; a.download = f.name; a.rel = 'noopener'; document.body.appendChild(a); a.click(); a.remove();
  };

  const iconFor = (kind) => kind === 'img' ? Icons.image : Icons.fileText;

  const card = (f) => React.createElement('div', {
    key: f.id, className: 'fcard' + (dragId === f.id ? ' dragging' : ''),
    draggable: true,
    onDragStart: () => setDragId(f.id),
    onDragEnd: () => { setDragId(null); setDropTarget(null); },
  },
    React.createElement('div', { className: 'fcard-top' },
      React.createElement('span', { className: 'fcard-icon' + (f.kind === 'img' ? ' img' : '') },
        React.createElement(iconFor(f.kind), { size: 16 })),
      React.createElement('div', { style: { minWidth: 0 } },
        React.createElement('div', { className: 'fcard-name' }, f.name),
        React.createElement('div', { className: 'fcard-meta' }, fmtBytes(f.size) + ' · ' + timeAgo(f.ts) + ' ago'))),
    React.createElement('div', { className: 'fcard-actions' },
      React.createElement('button', { className: 'fcard-btn', onClick: () => open(f) }, 'Open'),
      React.createElement('button', { className: 'fcard-btn', onClick: () => rename(f) }, 'Rename'),
      React.createElement('button', { className: 'fcard-btn', onClick: () => download(f) }, 'Download'),
      React.createElement('button', { className: 'fcard-btn danger', onClick: () => del(f) }, 'Delete')));

  const sections = filter == null
    ? [...folders.map(fd => ({ name: fd.name, items: visible.filter(x => x.folder_id === fd.id) })),
       { name: 'Loose files', items: visible.filter(x => !x.folder_id) }]
    : [{ name: folderName(filter), items: visible }];

  return React.createElement('div', { className: 'space-root' },
    React.createElement(SpaceTopbar, { tabs, utils },
      React.createElement('div', { className: 'cal-spacer' }),
      React.createElement('span', { className: 'vault-label', style: { marginRight: 10, letterSpacing: '0.08em' } }, files.length + ' files'),
      React.createElement('input', { ref: fileInputRef, type: 'file', multiple: true, style: { display: 'none' },
        onChange: (e) => { doUpload(e.target.files); e.target.value = ''; } }),
      React.createElement('button', { className: 'btn-primary', onClick: () => fileInputRef.current && fileInputRef.current.click(), disabled: busy },
        React.createElement(Icons.upload, { size: 15 }), busy ? 'Uploading…' : 'Upload')),
    React.createElement('div', { className: 'space-body' },
      React.createElement('aside', { className: 'cal-side' },
        React.createElement('div', null,
          React.createElement('div', { className: 'side-search' },
            React.createElement(Icons.search, { size: 14 }),
            React.createElement('input', { placeholder: 'Search files', value: query, onChange: (e) => setQuery(e.target.value) })),
          React.createElement('div', { className: 'side-section-label' },
            React.createElement('span', { className: 'vault-label' }, 'Folders'),
            React.createElement('button', { className: 'folder-add-btn', title: 'New folder', onClick: () => setAdding(true) },
              React.createElement(Icons.folderPlus, { size: 14 }))),
          React.createElement('div', { className: 'tree' },
            // All files — also the "remove from folder" drop target (loose)
            React.createElement('div', {
              className: 'tree-leaf' + (filter == null ? ' active' : '') + (dropTarget === 'loose' ? ' drop' : ''),
              onClick: () => setFilter(null),
              onDragOver: (e) => { if (dragId) { e.preventDefault(); setDropTarget('loose'); } },
              onDragLeave: () => setDropTarget(t => t === 'loose' ? null : t),
              onDrop: (e) => { e.preventDefault(); if (dragId) moveFile(dragId, null); setDragId(null); setDropTarget(null); },
            },
              React.createElement(Icons.grid, { size: 13 }),
              React.createElement('span', { className: 'lname' }, 'All files'),
              React.createElement('span', { className: 'lmeta' }, files.length)),
            folders.map(fd => React.createElement('div', {
              key: fd.id,
              className: 'tree-leaf' + (filter === fd.id ? ' active' : '') + (dropTarget === fd.id ? ' drop' : ''),
              onClick: () => setFilter(fd.id),
              onDoubleClick: async () => { const nx = prompt('Rename folder', fd.name); if (nx && nx.trim() && nx.trim() !== fd.name) { const nm = nx.trim(); setFolders(prev => prev.map(x => x.id === fd.id ? { ...x, name: nm } : x)); try { await DB.folders.rename(fd.id, nm); } catch (e) {} } },
              onDragOver: (e) => { if (dragId) { e.preventDefault(); setDropTarget(fd.id); } },
              onDragLeave: () => setDropTarget(t => t === fd.id ? null : t),
              onDrop: (e) => { e.preventDefault(); if (dragId) moveFile(dragId, fd.id); setDragId(null); setDropTarget(null); },
            },
              React.createElement(Icons.folder, { size: 13 }),
              React.createElement('span', { className: 'lname' }, fd.name),
              React.createElement('span', { className: 'lmeta' }, files.filter(x => x.folder_id === fd.id).length),
              React.createElement('span', { className: 'leaf-x', title: 'Delete folder', onClick: (e) => deleteFolder(fd, e) }, React.createElement(Icons.x, { size: 11 })))),
            adding ? React.createElement('input', {
              className: 'folder-new-input', autoFocus: true, placeholder: 'Folder name…', value: newName, style: { margin: '4px 0' },
              onChange: (e) => setNewName(e.target.value),
              onKeyDown: (e) => { if (e.key === 'Enter') addFolder(); if (e.key === 'Escape') { setAdding(false); setNewName(''); } },
              onBlur: addFolder,
            }) : null))),
      React.createElement('main', { className: 'files-main' },
        sections.map(sec => sec.items.length === 0 ? null :
          React.createElement('div', { key: sec.name },
            React.createElement('div', { className: 'files-sec' }, React.createElement(Icons.folder, { size: 11 }), sec.name),
            React.createElement('div', { className: 'fgrid' }, sec.items.map(card)))),
        loaded && visible.length === 0
          ? React.createElement('div', { className: 'empty-pane', style: { minHeight: 320, background: 'transparent' } },
              React.createElement(Icons.folder, { size: 36, sw: 1.5 }),
              React.createElement('div', { className: 'et' }, 'No files here'),
              React.createElement('div', { className: 'es' }, 'Upload something to get started'))
          : null)));
}

window.FilesSpace = FilesSpace;
