// reader-saves.jsx
// Save inbox: highlight-to-save, bookmark icons, drag-to-save, drawer/inbox UI, export to .md.
// Persists to localStorage under "lcp.saves".

const LS_KEY = 'lcp.saves.v1';

function loadSaves() {
  try { return JSON.parse(localStorage.getItem(LS_KEY) || '[]'); } catch { return []; }
}
function persistSaves(arr) {
  try { localStorage.setItem(LS_KEY, JSON.stringify(arr)); } catch {}
}

function useSaves() {
  const [items, setItems] = React.useState(loadSaves);
  React.useEffect(() => { persistSaves(items); }, [items]);

  const add = React.useCallback((item) => {
    setItems((prev) => {
      // dedupe by (text + eraId)
      const sig = (it) => `${it.eraId}::${(it.text || '').trim()}`;
      const target = sig(item);
      if (prev.some((it) => sig(it) === target)) return prev;
      return [{ ...item, id: `s-${Date.now()}-${Math.random().toString(36).slice(2,7)}`, ts: Date.now() }, ...prev];
    });
  }, []);
  const remove = React.useCallback((id) => setItems((prev) => prev.filter((it) => it.id !== id)), []);
  const clear  = React.useCallback(() => setItems([]), []);

  return { items, add, remove, clear };
}

// =====================================================
// Highlight-to-save toolbar (Kindle-style)
// =====================================================
function SelectionToolbar({ onSave, enabled }) {
  const [state, setState] = React.useState(null); // { x, y, text, eraId, eraTitle }
  React.useEffect(() => {
    if (!enabled) { setState(null); return; }
    let raf = null;
    const update = () => {
      const sel = window.getSelection();
      if (!sel || sel.isCollapsed || sel.rangeCount === 0) { setState(null); return; }
      const text = sel.toString().trim();
      if (text.length < 4) { setState(null); return; }
      const range = sel.getRangeAt(0);
      const rect = range.getBoundingClientRect();
      if (!rect.width && !rect.height) { setState(null); return; }
      // find nearest ancestor with [data-era]
      let node = range.commonAncestorContainer;
      while (node && node.nodeType !== 1) node = node.parentNode;
      let eraEl = node ? node.closest('[data-era]') : null;
      const eraId = eraEl ? eraEl.getAttribute('data-era') : null;
      const eraTitle = eraEl ? eraEl.getAttribute('data-era-title') : '';
      setState({
        x: rect.left + rect.width / 2,
        y: rect.top - 8,
        text, eraId, eraTitle
      });
    };
    const onSel = () => { if (raf) cancelAnimationFrame(raf); raf = requestAnimationFrame(update); };
    document.addEventListener('selectionchange', onSel);
    document.addEventListener('scroll', onSel, true);
    return () => {
      document.removeEventListener('selectionchange', onSel);
      document.removeEventListener('scroll', onSel, true);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [enabled]);

  if (!state || !enabled) return null;
  const save = () => {
    onSave({ kind: 'highlight', text: state.text, eraId: state.eraId, eraTitle: state.eraTitle });
    window.getSelection().removeAllRanges();
    setState(null);
  };
  return (
    <div
      className="sel-toolbar"
      style={{
        position: 'fixed',
        left: state.x, top: state.y,
        transform: 'translate(-50%, -100%)',
        zIndex: 1000,
      }}
      onMouseDown={(e) => e.preventDefault()}
    >
      <button onClick={save} className="sel-toolbar-btn">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
        <span>Save highlight</span>
      </button>
    </div>
  );
}

// =====================================================
// Bookmark icon (sits next to saveable items)
// =====================================================
function BookmarkButton({ saved, onClick, title }) {
  return (
    <button
      className={`bookmark-btn ${saved ? 'is-saved' : ''}`}
      onClick={onClick}
      title={title || (saved ? 'Saved — click to remove' : 'Save to reading list')}
      aria-label={saved ? 'Remove from reading list' : 'Save to reading list'}
    >
      <svg width="14" height="14" viewBox="0 0 24 24" fill={saved ? 'currentColor' : 'none'} stroke="currentColor" strokeWidth="2">
        <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/>
      </svg>
    </button>
  );
}

// =====================================================
// Floating drop target (drag any paragraph/quote/reference to it)
// =====================================================
function FloatingInboxButton({ count, onClick, onDrop, dragHover, onDragHover }) {
  return (
    <button
      className={`fab-inbox ${dragHover ? 'fab-hover' : ''}`}
      onClick={onClick}
      onDragOver={(e) => { e.preventDefault(); onDragHover(true); }}
      onDragLeave={() => onDragHover(false)}
      onDrop={(e) => { e.preventDefault(); onDragHover(false); onDrop(e); }}
      title="Reading list"
      aria-label={`Reading list, ${count} saved`}
    >
      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
        <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/>
      </svg>
      <span className="fab-count">{count}</span>
      <span className="fab-hint">Drop to save</span>
    </button>
  );
}

// =====================================================
// Inbox drawer
// =====================================================
function InboxDrawer({ open, items, onClose, onRemove, onClear, onExport }) {
  return (
    <div className={`inbox-drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
      <div className="inbox-head">
        <div className="inbox-title-row">
          <div className="inbox-title">Your reading list</div>
          <button className="inbox-close" onClick={onClose} aria-label="Close reading list">×</button>
        </div>
        <div className="inbox-sub">{items.length} saved · stored on this device</div>
      </div>
      <div className="inbox-actions">
        <button className="inbox-action" onClick={onExport} disabled={!items.length}>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
          Export .md
        </button>
        <button className="inbox-action danger" onClick={onClear} disabled={!items.length}>Clear all</button>
      </div>
      <div className="inbox-list">
        {items.length === 0 && (
          <div className="inbox-empty">
            <div className="inbox-empty-mark">¶</div>
            <p>Nothing saved yet.</p>
            <p className="inbox-empty-hint">
              Highlight any passage, click any bookmark, or drag a paragraph here to add it.
            </p>
          </div>
        )}
        {items.map((it) => (
          <div key={it.id} className={`inbox-card kind-${it.kind}`}>
            <div className="inbox-card-meta">
              <span className="inbox-kind">{kindLabel(it.kind)}</span>
              {it.eraTitle && <span className="inbox-era">· {it.eraTitle}</span>}
            </div>
            <div className="inbox-card-text">
              {it.kind === 'reference' ? <em>{it.text}</em> : it.text}
            </div>
            {it.cite && <div className="inbox-card-cite">{it.cite}</div>}
            {it.note && <div className="inbox-card-note">{it.note}</div>}
            <button className="inbox-remove" onClick={() => onRemove(it.id)} aria-label="Remove">remove</button>
          </div>
        ))}
      </div>
    </div>
  );
}

function kindLabel(k) {
  return ({
    highlight: 'Highlight',
    bookmark: 'Saved passage',
    reference: 'Reference',
    sidenote: 'Margin note',
    quote: 'Pull quote'
  })[k] || 'Saved';
}

// =====================================================
// Export to markdown
// =====================================================
function exportToMarkdown(items) {
  const grouped = {};
  items.forEach((it) => {
    const k = it.eraTitle || 'Unsorted';
    grouped[k] = grouped[k] || [];
    grouped[k].push(it);
  });
  const lines = [];
  lines.push('# Reading list');
  lines.push('');
  lines.push(`_Saved from Eras of Organizational Philosophy. ${items.length} items._`);
  lines.push('');
  Object.keys(grouped).forEach((era) => {
    lines.push(`## ${era}`);
    lines.push('');
    grouped[era].forEach((it) => {
      lines.push(`### ${kindLabel(it.kind)}`);
      lines.push('');
      lines.push(`> ${(it.text || '').replace(/\n/g, '\n> ')}`);
      lines.push('');
      if (it.cite) { lines.push(`_${it.cite}_`); lines.push(''); }
      if (it.note) { lines.push(it.note); lines.push(''); }
    });
  });
  const blob = new Blob([lines.join('\n')], { type: 'text/markdown' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `reading-list-${new Date().toISOString().slice(0,10)}.md`;
  document.body.appendChild(a);
  a.click();
  setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(url); }, 200);
}

Object.assign(window, {
  useSaves, SelectionToolbar, BookmarkButton, FloatingInboxButton, InboxDrawer,
  exportToMarkdown, kindLabel,
});
