import React, { useCallback, useEffect, useRef, useState } from 'react';
import { api, fileUrl, fileToBase64 } from './api.js';

const isImage = (m) => /^image\//.test(m || '');
const isText = (f) => f.kind === 'text' || /^text\/|json|markdown|javascript|xml|csv/.test(f.mime || '');
const human = (n) => (n < 1024 ? `${n} B` : n < 1048576 ? `${(n / 1024).toFixed(1)} KB` : `${(n / 1048576).toFixed(1)} MB`);

// Netdisk file browser. `onPick` (optional) turns rows into a picker for the whiteboard.
export default function Netdisk({ onPick, compact }) {
  const [files, setFiles] = useState([]);
  const [folder, setFolder] = useState('');
  const [sel, setSel] = useState(null);
  const [err, setErr] = useState('');
  const [busy, setBusy] = useState(false);
  const fileInput = useRef(null);

  const load = useCallback(async () => {
    setErr('');
    try { const d = await api('/files'); setFiles(d.files || []); } catch (e) { setErr(e.message); }
  }, []);
  useEffect(() => { load(); }, [load]);

  const folders = Array.from(new Set(['', ...files.map((f) => f.folder || '')])).sort();
  const shown = files.filter((f) => (folder ? (f.folder || '') === folder : true));

  const upload = async (fileList) => {
    setBusy(true); setErr('');
    try {
      for (const file of fileList) {
        const data = await fileToBase64(file);
        await api('/files', { method: 'POST', body: { name: file.name, folder, mime: file.type || 'application/octet-stream', data } });
      }
      await load();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };
  const newTextFile = async () => {
    const name = window.prompt('New text file name', 'note.md'); if (!name) return;
    try { await api('/files', { method: 'POST', body: { name, folder, kind: 'text', text: '', mime: name.endsWith('.md') ? 'text/markdown' : 'text/plain' } }); load(); }
    catch (e) { setErr(e.message); }
  };
  const del = async (id) => { if (!window.confirm('Delete file?')) return; try { await api(`/files/${id}`, { method: 'DELETE' }); setSel(null); load(); } catch (e) { setErr(e.message); } };

  return (
    <div className={`nd ${compact ? 'nd-compact' : ''}`}>
      <div className="nd-bar">
        <select value={folder} onChange={(e) => setFolder(e.target.value)}>
          {folders.map((f) => <option key={f} value={f}>{f || '— all / root —'}</option>)}
        </select>
        <input className="nd-folder-input" placeholder="folder for new uploads" value={folder} onChange={(e) => setFolder(e.target.value)} />
        <button className="cs-btn" onClick={() => fileInput.current?.click()} disabled={busy}>{busy ? '…' : 'Upload'}</button>
        <button className="cs-btn" onClick={newTextFile}>New text</button>
        <input ref={fileInput} type="file" multiple hidden onChange={(e) => { upload([...e.target.files]); e.target.value = ''; }} />
      </div>
      {err && <p className="cs-err">{err}</p>}
      <div className="nd-grid">
        <div className="nd-list">
          {shown.map((f) => (
            <div key={f.id} className={`nd-row${sel?.id === f.id ? ' on' : ''}`} onClick={() => setSel(f)}>
              <span className="nd-icon">{isImage(f.mime) ? '🖼' : isText(f) ? '📄' : '📦'}</span>
              <span className="nd-name" title={f.name}>{f.name}</span>
              <span className="nd-meta">{f.folder || '/'} · {human(f.size)}</span>
              {onPick && <button className="cs-btn nd-pick" onClick={(e) => { e.stopPropagation(); onPick(f); }}>link</button>}
              <button className="nd-del" onClick={(e) => { e.stopPropagation(); del(f.id); }}>✕</button>
            </div>
          ))}
          {!shown.length && <div className="nd-empty">no files — upload or create one</div>}
        </div>
        {!compact && <FilePreview file={sel} onChange={load} />}
      </div>
    </div>
  );
}

export function FilePreview({ file, onChange }) {
  const [editing, setEditing] = useState(false);
  const [text, setText] = useState('');
  const [err, setErr] = useState('');
  useEffect(() => {
    setEditing(false); setErr('');
    if (file && (file.kind === 'text')) {
      api(`/files/${file.id}`).then((d) => setText(d.file.text_body || '')).catch((e) => setErr(e.message));
    }
  }, [file]);
  if (!file) return <div className="nd-preview nd-preview-empty">select a file</div>;
  const save = async () => { try { await api(`/files/${file.id}`, { method: 'PATCH', body: { text } }); setEditing(false); onChange && onChange(); } catch (e) { setErr(e.message); } };
  return (
    <div className="nd-preview">
      <div className="nd-preview-head">
        <strong>{file.name}</strong>
        <span>{file.mime} · {human(file.size)}</span>
        <a className="cs-btn" href={fileUrl(file.id)} target="_blank" rel="noreferrer">Open ↗</a>
        {file.kind === 'text' && !editing && <button className="cs-btn" onClick={() => setEditing(true)}>Edit</button>}
        {editing && <button className="cs-btn cs-primary" onClick={save}>Save</button>}
      </div>
      {err && <p className="cs-err">{err}</p>}
      <div className="nd-preview-body">
        {isImage(file.mime) && <img src={fileUrl(file.id)} alt={file.name} className="nd-img" />}
        {file.kind === 'text' && editing && <textarea className="nd-text" value={text} onChange={(e) => setText(e.target.value)} />}
        {file.kind === 'text' && !editing && <pre className="nd-textview">{text}</pre>}
        {!isImage(file.mime) && file.kind !== 'text' && <div className="nd-binary">Binary file — <a href={fileUrl(file.id)} target="_blank" rel="noreferrer">download / open</a></div>}
      </div>
    </div>
  );
}
