// Ideas — a private, curated shelf of videos & articles on topics I care about
// (Philosophy, Design, Investing, Travel, …). Same grid feel as Objects, but the
// payload is media: a video tile plays a native YouTube/Vimeo player in place; an
// article tile shows a classified thumbnail and opens the source.
//
// Data lives in the `ideas` table (see 20260609000000_ideas.sql). Owner-only —
// gated in the nav/routing and by RLS. Add by pasting a link (auto-classified by
// the ingest function with kind:'idea'), or email a link with `add_to_ideas` in
// the subject for hands-off upload.

const IDEA_TOPICS = ['Philosophy', 'Design', 'Investing', 'Travel', 'Technology', 'Science', 'Art', 'Architecture', 'Business', 'Culture'];

// Build the embeddable player URL for a video idea.
const embedUrl = (idea) => {
  if (idea.video_provider === 'youtube' && idea.video_id) return `https://www.youtube.com/embed/${idea.video_id}?autoplay=1&rel=0&modestbranding=1`;
  if (idea.video_provider === 'vimeo' && idea.video_id) return `https://player.vimeo.com/video/${idea.video_id}?autoplay=1`;
  return null;
};

// Thumbnail with graceful fallback: override → scraped → youtube thumb → placeholder.
const IdeaImage = ({ idea }) => {
  const yt = idea.video_provider === 'youtube' && idea.video_id ? `https://i.ytimg.com/vi/${idea.video_id}/hqdefault.jpg` : null;
  const sources = [idea.image_override, idea.image_url, yt].filter(Boolean);
  const [idx, setIdx] = React.useState(0);
  const src = sources[idx];
  if (!src) {
    return (
      <div style={{ position: 'absolute', inset: 0, background: `linear-gradient(135deg, ${tokens.bgAlt}, ${tokens.paper})`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <span style={{ fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.16em', color: tokens.inkMute, textTransform: 'uppercase' }}>{idea.topic || 'Idea'}</span>
      </div>
    );
  }
  return (
    <img src={src} alt={idea.title} loading="lazy" onError={() => setIdx((i) => i + 1)}
      style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
  );
};

// ── Owner add/edit form ─────────────────────────────────────────────────────
const I_FIELD = { width: '100%', padding: '10px 12px', border: `1px solid ${tokens.inkLine}`, background: tokens.paper, fontSize: '13px', fontFamily: fontDisplay, marginTop: '4px' };
const I_LABEL = { fontFamily: fontMono, fontSize: '10px', letterSpacing: '0.12em', color: tokens.inkMute, textTransform: 'uppercase' };

const IdeaForm = ({ initial, onSaved, onCancel }) => {
  const blank = { title: '', author: '', topic: 'Philosophy', subtopic: '', media_type: 'article', description: '', source_url: '', video_provider: '', video_id: '', image_url: '', image_override: '', published_at: '', tags: [], size: 'md', featured: false, status: 'published', sort_order: 0, attributes: {} };
  const [o, setO] = React.useState({ ...blank, ...(initial || {}) });
  const [busy, setBusy] = React.useState('');
  const [err, setErr] = React.useState('');
  const set = (k, v) => setO((prev) => ({ ...prev, [k]: v }));
  const client = window._supabaseClient;

  const autofill = async () => {
    if (!o.source_url) { setErr('Paste a link first.'); return; }
    setErr(''); setBusy('autofill');
    try {
      const { data, error } = await client.functions.invoke('ingest-object', { body: { url: o.source_url, kind: 'idea', preview: true } });
      let payload = data;
      if (error) { try { payload = await error.context.json(); } catch {} }
      if (!payload || payload.error) throw new Error(payload?.error || error?.message || 'Auto-fill failed');
      const p = payload.object || {};
      setO((prev) => ({ ...prev, ...p, source_url: o.source_url, tags: p.tags || [], attributes: p.attributes || {} }));
    } catch (e) { setErr(e.message); } finally { setBusy(''); }
  };

  const upload = async (file) => {
    if (!file) return;
    setErr(''); setBusy('upload');
    try {
      const ext = (file.name.split('.').pop() || 'jpg').toLowerCase();
      const path = `${(o.title || 'idea').toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 40)}-${Date.now()}.${ext}`;
      const { error } = await client.storage.from('idea-images').upload(path, file, { upsert: true, contentType: file.type });
      if (error) throw error;
      const { data } = client.storage.from('idea-images').getPublicUrl(path);
      set('image_override', data.publicUrl);
    } catch (e) { setErr(e.message); } finally { setBusy(''); }
  };

  const save = async () => {
    if (!o.title) { setErr('Title is required.'); return; }
    setErr(''); setBusy('save');
    const row = { ...o, tags: Array.isArray(o.tags) ? o.tags : String(o.tags).split(',').map((s) => s.trim()).filter(Boolean), updated_at: new Date().toISOString() };
    delete row.id; delete row.created_at; delete row.user_id;
    try {
      let res;
      if (o.id) res = await client.from('ideas').update(row).eq('id', o.id);
      else res = await client.from('ideas').insert(row);
      if (res.error) throw res.error;
      onSaved();
    } catch (e) { setErr(e.message); } finally { setBusy(''); }
  };

  const tagsStr = Array.isArray(o.tags) ? o.tags.join(', ') : (o.tags || '');

  return (
    <div style={{ border: `1px solid ${tokens.ink}`, background: tokens.paper, padding: '24px', marginBottom: '24px', borderRadius: '4px' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '18px' }}>
        <div style={{ fontFamily: fontMono, fontSize: '12px', letterSpacing: '0.14em', textTransform: 'uppercase' }}>{o.id ? 'Edit idea' : 'Add idea'}</div>
        <button onClick={onCancel} style={{ ...I_LABEL, background: 'none', border: 'none', cursor: 'pointer' }}>CLOSE ✕</button>
      </div>

      <div style={{ display: 'flex', gap: '8px', alignItems: 'flex-end', marginBottom: '16px' }}>
        <div style={{ flexGrow: 1 }}>
          <span style={I_LABEL}>Source link (paste a YouTube/Vimeo video or an article URL)</span>
          <input value={o.source_url || ''} onChange={(e) => set('source_url', e.target.value)} placeholder="https://…" style={I_FIELD} />
        </div>
        <button onClick={autofill} disabled={!!busy} style={{ padding: '10px 16px', background: tokens.ink, color: tokens.bg, border: 'none', cursor: 'pointer', fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.08em', whiteSpace: 'nowrap' }}>
          {busy === 'autofill' ? 'READING…' : '✦ AUTO-FILL'}
        </button>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px 16px' }}>
        <label><span style={I_LABEL}>Title</span><input value={o.title} onChange={(e) => set('title', e.target.value)} style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Author / Channel / Publication</span><input value={o.author || ''} onChange={(e) => set('author', e.target.value)} style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Topic</span><input value={o.topic} onChange={(e) => set('topic', e.target.value)} placeholder="Philosophy · Design · Investing…" style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Subtopic</span><input value={o.subtopic || ''} onChange={(e) => set('subtopic', e.target.value)} style={I_FIELD} /></label>
        <label style={{ gridColumn: 'span 2' }}><span style={I_LABEL}>Description</span><textarea value={o.description || ''} onChange={(e) => set('description', e.target.value)} rows={2} style={{ ...I_FIELD, resize: 'vertical' }} /></label>
        <label><span style={I_LABEL}>Media type</span>
          <select value={o.media_type} onChange={(e) => set('media_type', e.target.value)} style={I_FIELD}>
            <option value="article">Article</option><option value="video">Video</option>
          </select>
        </label>
        <label><span style={I_LABEL}>Published</span><input value={o.published_at || ''} onChange={(e) => set('published_at', e.target.value)} placeholder="2024" style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Video provider</span>
          <select value={o.video_provider || ''} onChange={(e) => set('video_provider', e.target.value)} style={I_FIELD}>
            <option value="">— none (article) —</option><option value="youtube">YouTube</option><option value="vimeo">Vimeo</option>
          </select>
        </label>
        <label><span style={I_LABEL}>Video ID</span><input value={o.video_id || ''} onChange={(e) => set('video_id', e.target.value)} placeholder="dQw4w9WgXcQ" style={I_FIELD} /></label>
        <label style={{ gridColumn: 'span 2' }}><span style={I_LABEL}>Tags (comma-separated)</span><input value={tagsStr} onChange={(e) => set('tags', e.target.value.split(',').map((s) => s.trim()).filter(Boolean))} style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Thumbnail URL</span><input value={o.image_url || ''} onChange={(e) => set('image_url', e.target.value)} style={I_FIELD} /></label>
        <label><span style={I_LABEL}>Tile size</span>
          <select value={o.size} onChange={(e) => set('size', e.target.value)} style={I_FIELD}>
            <option value="sm">Small</option><option value="md">Medium</option><option value="lg">Large (hero)</option>
          </select>
        </label>
        <label style={{ gridColumn: 'span 2' }}>
          <span style={I_LABEL}>High-res thumbnail override {o.image_override ? '✓ set' : '(upload to override the scraped image)'}</span>
          <input type="file" accept="image/*" onChange={(e) => upload(e.target.files[0])} style={{ ...I_FIELD, padding: '8px' }} />
        </label>
      </div>

      {err && <div style={{ marginTop: '12px', fontFamily: fontMono, fontSize: '11px', color: tokens.red }}>{err}</div>}

      <div style={{ display: 'flex', gap: '10px', marginTop: '18px', alignItems: 'center' }}>
        <button onClick={save} disabled={!!busy} style={{ padding: '11px 20px', background: tokens.ink, color: tokens.bg, border: 'none', cursor: 'pointer', fontSize: '13px', fontFamily: fontDisplay }}>
          {busy === 'save' ? 'Saving…' : (o.id ? 'Update idea' : 'Add idea')}
        </button>
        <label style={{ ...I_LABEL, display: 'flex', alignItems: 'center', gap: '6px', cursor: 'pointer' }}>
          <input type="checkbox" checked={!!o.featured} onChange={(e) => set('featured', e.target.checked)} /> FEATURED
        </label>
        {busy === 'upload' && <span style={{ ...I_LABEL }}>UPLOADING IMAGE…</span>}
      </div>
    </div>
  );
};

// ── A single tile ────────────────────────────────────────────────────────────
const IdeaTile = ({ idea, isOwner, onEdit, onDelete, spanStyle }) => {
  const [playing, setPlaying] = React.useState(false);
  const player = embedUrl(idea);
  const isVideo = idea.media_type === 'video' && !!player;
  const href = isVideo ? null : (idea.source_url || null);

  // A video that's playing: swap the tile for a native iframe player.
  if (isVideo && playing) {
    return (
      <div style={{ ...spanStyle, position: 'relative', background: '#000', overflow: 'hidden' }}>
        <iframe src={player} title={idea.title} allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowFullScreen
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', border: 'none' }} />
        {isOwner && (
          <button onClick={(e) => { e.preventDefault(); setPlaying(false); }} title="Stop"
            style={{ position: 'absolute', top: '12px', right: '12px', zIndex: 3, width: '26px', height: '26px', borderRadius: '50%', border: 'none', background: 'rgba(251,250,246,0.95)', cursor: 'pointer', fontSize: '11px' }}>✕</button>
        )}
      </div>
    );
  }

  const Wrapper = href ? 'a' : 'div';
  const wrapProps = href
    ? { href, target: '_blank', rel: 'noopener noreferrer' }
    : { onClick: isVideo ? () => setPlaying(true) : undefined };

  return (
    <Wrapper {...wrapProps} className="object-tile" style={{ ...spanStyle, position: 'relative', background: tokens.paper, overflow: 'hidden', cursor: (href || isVideo) ? 'pointer' : 'default', display: 'block' }}>
      <IdeaImage idea={idea} />

      {/* topic + media badge */}
      <div style={{ position: 'absolute', top: '14px', left: '14px', fontFamily: fontMono, fontSize: '9px', letterSpacing: '0.16em', padding: '5px 8px', background: 'rgba(251,250,246,0.92)', color: tokens.ink, fontWeight: 500, textTransform: 'uppercase' }}>
        {idea.topic}{isVideo ? ' · VIDEO' : ' · READ'}
      </div>

      {/* owner controls */}
      {isOwner && (
        <div style={{ position: 'absolute', top: '12px', right: '12px', display: 'flex', gap: '6px', zIndex: 3 }}>
          <button onClick={(e) => { e.preventDefault(); e.stopPropagation(); onEdit(idea); }} style={{ width: '26px', height: '26px', borderRadius: '50%', border: 'none', background: 'rgba(251,250,246,0.95)', cursor: 'pointer', fontSize: '11px' }}>✎</button>
          {roleCanDelete() && <button onClick={(e) => { e.preventDefault(); e.stopPropagation(); onDelete(idea.id); }} style={{ width: '26px', height: '26px', borderRadius: '50%', border: 'none', background: 'rgba(160,74,62,0.95)', color: '#fff', cursor: 'pointer', fontSize: '11px' }}>✕</button>}
        </div>
      )}

      {/* play button for videos */}
      {isVideo && (
        <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' }}>
          <div style={{ width: '64px', height: '64px', borderRadius: '50%', background: 'rgba(14,14,12,0.62)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <div style={{ width: 0, height: 0, borderTop: '11px solid transparent', borderBottom: '11px solid transparent', borderLeft: '18px solid #FBFAF6', marginLeft: '5px' }} />
          </div>
        </div>
      )}

      {/* caption */}
      <div className="object-caption" style={{ position: 'absolute', left: 0, right: 0, bottom: 0, padding: '18px', background: 'linear-gradient(to top, rgba(14,14,12,0.92) 0%, rgba(14,14,12,0.65) 55%, transparent 100%)', color: tokens.bg }}>
        {(idea.subtopic || idea.published_at) && (
          <div style={{ fontFamily: fontMono, fontSize: '9px', letterSpacing: '0.16em', color: 'rgba(244,241,234,0.6)', marginBottom: '6px', textTransform: 'uppercase' }}>
            {[idea.published_at, idea.subtopic].filter(Boolean).join(' · ')}
          </div>
        )}
        <div style={{ fontSize: idea.size === 'lg' ? '20px' : '15px', letterSpacing: '-0.02em', lineHeight: 1.2, marginBottom: '4px' }}>{idea.title}</div>
        {idea.author && <div style={{ fontFamily: fontMono, fontSize: '10px', color: 'rgba(244,241,234,0.6)', letterSpacing: '0.06em' }}>{idea.author.toUpperCase()}</div>}
      </div>

      {href && (
        <div className="object-arrow" style={{ position: 'absolute', bottom: '14px', right: '14px', width: '28px', height: '28px', background: 'rgba(251,250,246,0.92)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: fontMono, fontSize: '12px', color: tokens.ink }}>↗</div>
      )}
    </Wrapper>
  );
};

const Ideas = ({ isOwner }) => {
  const isMobile = useIsMobile();
  const [ideas, setIdeas] = React.useState(null);
  const [filter, setFilter] = React.useState('all');
  const [editing, setEditing] = React.useState(null);
  const [loadErr, setLoadErr] = React.useState('');

  const load = React.useCallback(async () => {
    const client = window._supabaseClient;
    if (!client) { setIdeas([]); return; }
    const { data, error } = await client.from('ideas').select('*').order('featured', { ascending: false }).order('sort_order', { ascending: false }).order('created_at', { ascending: false });
    if (error) { setLoadErr(error.message); setIdeas([]); }
    else setIdeas(data || []);
  }, []);

  React.useEffect(() => { load(); }, [load]);

  const topics = React.useMemo(() => {
    const set = new Set((ideas || []).map((o) => o.topic).filter(Boolean));
    return ['all', ...Array.from(set)];
  }, [ideas]);

  const filtered = (ideas || []).filter((o) => filter === 'all' || o.topic === filter);

  const span = (s) => {
    if (isMobile) return (s === 'lg' || s === 'md') ? { gridColumn: 'span 2', aspectRatio: '16 / 9' } : { gridColumn: 'span 1', aspectRatio: '1' };
    if (s === 'lg') return { gridColumn: 'span 2', gridRow: 'span 2', aspectRatio: '1' };
    if (s === 'md') return { gridColumn: 'span 2', gridRow: 'span 1', aspectRatio: '2 / 1' };
    return { gridColumn: 'span 1', gridRow: 'span 1', aspectRatio: '1' };
  };

  const del = async (id) => {
    if (!roleCanDelete()) { window.alert(DEMO_BLOCK_MSG); return; }
    if (!window.confirm('Delete this idea?')) return;
    await window._supabaseClient.from('ideas').delete().eq('id', id);
    load();
  };

  return (
    <div>
      {/* Hero */}
      <section style={{ padding: '80px 56px 40px', borderBottom: `1px solid ${tokens.inkLine}` }}>
        <div style={{ fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.18em', color: tokens.inkMute, marginBottom: '24px' }}>07 · IDEAS</div>
        <h1 style={{ fontSize: '88px', lineHeight: 0.92, letterSpacing: '-0.05em', fontWeight: 400, margin: 0, marginBottom: '32px' }}>Ideas.</h1>
        <p style={{ fontSize: '22px', lineHeight: 1.45, letterSpacing: '-0.015em', color: tokens.inkSoft, maxWidth: '780px' }}>
          A reading and watching list — videos and essays I keep coming back to, across philosophy, design, investing, travel, and whatever else holds my attention. Videos play here; articles open out.
        </p>
      </section>

      {/* Filter bar */}
      <section style={{ padding: '20px 56px', borderBottom: `1px solid ${tokens.inkLine}`, display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '16px', flexWrap: 'wrap', position: 'sticky', top: isMobile ? 0 : 56, zIndex: 20, background: 'rgba(244,241,234,0.92)', backdropFilter: 'blur(10px)' }}>
        <div style={{ display: 'flex', gap: '20px', fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.12em', flexWrap: 'wrap' }}>
          {topics.map((c) => (
            <button key={c} onClick={() => setFilter(c)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: filter === c ? tokens.ink : tokens.inkMute, borderBottom: filter === c ? `1px solid ${tokens.ink}` : '1px solid transparent', padding: '6px 0', letterSpacing: '0.12em', textTransform: 'uppercase' }}>{c}</button>
          ))}
        </div>
        {isOwner && (
          <button onClick={() => setEditing(editing ? null : {})} style={{ fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.1em', color: tokens.bg, background: tokens.ink, border: 'none', padding: '8px 14px', cursor: 'pointer' }}>
            {editing ? '✕ CLOSE' : '＋ ADD IDEA'}
          </button>
        )}
      </section>

      {/* Owner form */}
      {isOwner && editing && (
        <section style={{ padding: isMobile ? '20px 18px 0' : '24px 56px 0' }}>
          <IdeaForm initial={editing.id ? editing : {}} onSaved={() => { setEditing(null); load(); }} onCancel={() => setEditing(null)} />
        </section>
      )}

      {/* Grid */}
      <section style={{ padding: isMobile ? '12px' : '24px' }}>
        {ideas === null ? (
          <div style={{ padding: '80px', textAlign: 'center', fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.16em', color: tokens.inkMute }}>LOADING…</div>
        ) : filtered.length === 0 ? (
          <div style={{ padding: '80px', textAlign: 'center', fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.12em', color: tokens.inkMute }}>
            {loadErr ? `COULDN'T LOAD — ${loadErr.toUpperCase()}` : 'NO IDEAS YET'}
          </div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: isMobile ? 'repeat(2, minmax(0, 1fr))' : 'repeat(4, minmax(0, 1fr))', gridAutoRows: isMobile ? 'minmax(150px, auto)' : 'minmax(220px, auto)', gap: '4px' }}>
            {filtered.map((o) => (
              <IdeaTile key={o.id} idea={o} isOwner={isOwner} spanStyle={span(o.size)}
                onEdit={(idea) => { setEditing(idea); window.scrollTo({ top: 0, behavior: 'smooth' }); }}
                onDelete={del} />
            ))}
          </div>
        )}
      </section>

      {/* Footer note */}
      <section style={{ padding: '60px 56px', borderTop: `1px solid ${tokens.inkLine}`, background: tokens.bgAlt }}>
        <div style={{ fontFamily: fontMono, fontSize: '11px', letterSpacing: '0.16em', color: tokens.inkMute, marginBottom: '16px' }}>ON THIS LIST</div>
        <p style={{ fontSize: '15px', lineHeight: 1.6, color: tokens.inkSoft, letterSpacing: '-0.005em', maxWidth: '560px', margin: 0 }}>
          A living list — added to over time, often by emailing myself a link. Each piece is classified as it's added; nothing is here because it's popular, only because it earned a second look.
        </p>
      </section>
    </div>
  );
};

window.Ideas = Ideas;
