// Journal screen — ported (session S-D), extended (session 23). Demo entries
// replaced by real listJournal(). Session 23 course correction: the
// prototype's Like/Share/Co-write buttons were removed in S-D, then Jay
// asked for them to be built instead of cut. Built per his direction:
//   - Like -> a personal Favorite toggle (owner-only star, no social graph;
//     journal_entries.favorite, migration 0003).
//   - Share -> generates a real public link (sets visibility='public',
//     served by /entry.html via new public-read RLS policies, migration
//     0003) and copies it to the clipboard (or opens the native share sheet
//     via navigator.share when available). A future phase may add a
//     community feed or social cross-posting; not built yet, not implied.
//   - Co-write -> explicitly deferred per Jay's answer ("not now"); the
//     button stays removed rather than shipped as a dead click target.

function NewEntryComposer({ parkIndex, onSaved, onClose }) {
  const [parkSlug, setParkSlug] = React.useState(parkIndex[0] ? parkIndex[0].slug : '');
  const [title, setTitle] = React.useState('');
  const [body, setBody] = React.useState('');
  const [miles, setMiles] = React.useState('');
  const [weather, setWeather] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => { const t = setTimeout(() => setMounted(true), 10); return () => clearTimeout(t); }, []);

  const save = async () => {
    if (!parkSlug) return;
    setSaving(true);
    try {
      await window.PH.createJournalEntry({
        park_slug: parkSlug,
        title: title.trim() || null,
        body: body.trim() || null,
        miles: miles ? Number(miles) : null,
        weather: weather.trim() || null,
      });
      onSaved();
    } finally { setSaving(false); }
  };

  const fieldStyle = { width: '100%', padding: '12px 14px', borderRadius: 2, border: '1px solid var(--line)', background: 'var(--paper)', color: 'var(--ink)', fontFamily: 'DM Sans, sans-serif', fontSize: 14 };

  // Full-screen sheet (spec §3.3) — uses standard tokens, so Day/Night is inherited for free.
  return (
    <div style={{
      position: 'fixed', inset: 0, zIndex: 60, background: 'var(--bg)',
      display: 'flex', flexDirection: 'column',
      transform: mounted ? 'translateY(0)' : 'translateY(100%)',
      transition: 'transform 240ms ease',
      paddingTop: 'env(safe-area-inset-top)', paddingBottom: 'env(safe-area-inset-bottom)',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '18px 22px' }}>
        <Caps s={9} c="var(--accent)">New Entry</Caps>
        <button onClick={onClose} style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--ink-3)' }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
        </button>
      </div>
      <div style={{ flex: 1, overflowY: 'auto', padding: '0 22px' }}>
        <select value={parkSlug} onChange={e => setParkSlug(e.target.value)} style={{ ...fieldStyle, marginTop: 6 }}>
          {parkIndex.map(p => <option key={p.slug} value={p.slug}>{p.name}</option>)}
        </select>
        <input value={title} onChange={e => setTitle(e.target.value)} placeholder="Title (optional)"
          style={{ width: '100%', marginTop: 14, padding: '10px 0', border: 'none', borderBottom: '1px solid var(--line)', background: 'transparent', color: 'var(--ink)', fontFamily: 'Space Grotesk, sans-serif', fontSize: 22, fontWeight: 600 }}/>
        <textarea value={body} onChange={e => setBody(e.target.value)} placeholder="What happened today?"
          style={{ width: '100%', marginTop: 14, padding: 0, border: 'none', background: 'transparent', color: 'var(--ink)', fontFamily: 'Space Grotesk, sans-serif', fontSize: 16, lineHeight: 1.5, resize: 'vertical', minHeight: '40vh' }}/>
        <div style={{ display: 'flex', gap: 10, marginTop: 10, marginBottom: 24 }}>
          <input value={miles} onChange={e => setMiles(e.target.value)} type="number" step="0.1" placeholder="Miles" style={{ ...fieldStyle, flex: 1, fontSize: 13 }}/>
          <input value={weather} onChange={e => setWeather(e.target.value)} placeholder="Weather" style={{ ...fieldStyle, flex: 1, fontSize: 13 }}/>
        </div>
      </div>
      <div style={{ display: 'flex', gap: 8, padding: '16px 22px', borderTop: '1px solid var(--line)' }}>
        <button disabled={saving} onClick={save} style={{ flex: 1, padding: '13px 0', background: 'var(--ink)', color: 'var(--bg)', border: 'none', borderRadius: 100, cursor: saving ? 'default' : 'pointer', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', opacity: saving ? 0.6 : 1 }}>{saving ? 'Saving…' : 'Save entry'}</button>
        <button onClick={onClose} style={{ padding: '13px 20px', background: 'transparent', color: 'var(--ink-2)', border: '1px solid var(--line)', borderRadius: 100, cursor: 'pointer', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase' }}>Cancel</button>
      </div>
    </div>
  );
}

/* Quiet topographic empty-state plate (spec §3.4) — hand-authored contour paths, no imagery. */
function EmptyJournalPlate() {
  return (
    <svg width="100%" height="140" viewBox="0 0 320 140" fill="none" style={{ display: 'block' }}>
      <path d="M-10 90 C 40 60, 80 100, 130 70 C 170 48, 210 78, 260 55 C 290 42, 310 50, 330 40" stroke="var(--line)" strokeWidth="1.2"/>
      <path d="M-10 110 C 45 85, 85 118, 135 92 C 175 72, 215 98, 265 78 C 295 65, 310 70, 330 62" stroke="var(--line)" strokeWidth="1.2"/>
      <path d="M-10 70 C 35 45, 75 78, 125 50 C 165 30, 205 58, 255 38 C 285 26, 305 32, 330 24" stroke="var(--line)" strokeWidth="1.2"/>
    </svg>
  );
}

function monthLabel(dateStr) {
  const d = new Date(dateStr);
  return d.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }).toUpperCase();
}
function dayNum(dateStr) { return new Date(dateStr).getDate(); }
function monthAbbrev(dateStr) { return new Date(dateStr).toLocaleDateString('en-US', { month: 'short', year: '2-digit' }).toUpperCase().replace(' ', ' \u2019'); }
function coordLine(park) {
  if (!park || park.lat == null || park.lon == null) return null;
  const latH = park.lat >= 0 ? 'N' : 'S';
  const lonH = park.lon >= 0 ? 'E' : 'W';
  return `${Math.abs(park.lat).toFixed(4)}\u00b0 ${latH} \u00b7 ${Math.abs(park.lon).toFixed(4)}\u00b0 ${lonH}`;
}

function JournalScreen({ go, openPark }) {
  const [loading, setLoading] = React.useState(true);
  const [entries, setEntries] = React.useState([]);
  const [parkIndex, setParkIndex] = React.useState([]);
  const [composerOpen, setComposerOpen] = React.useState(false);
  const [uploadingId, setUploadingId] = React.useState(null);

  const load = React.useCallback(async () => {
    const [e, idx] = await Promise.all([window.PH.listJournal({ limit: 50 }), window.PH.getParkIndex()]);
    setEntries(e); setParkIndex(idx);
  }, []);

  React.useEffect(() => { (async () => { setLoading(true); await load(); setLoading(false); })(); }, [load]);

  const addPhoto = async (entryId, file) => {
    setUploadingId(entryId);
    try { await window.PH.addJournalPhoto(entryId, file); await load(); }
    finally { setUploadingId(null); }
  };
  const removeEntry = async (id) => {
    if (!confirm('Delete this entry and its photos?')) return;
    await window.PH.deleteJournalEntry(id); await load();
  };
  const toggleFavorite = async (e) => {
    await window.PH.toggleJournalFavorite(e.id, !e.favorite); await load();
  };
  const share = async (e) => {
    const url = await window.PH.shareJournalEntry(e.id);
    if (navigator.share) {
      try { await navigator.share({ title: e.title || 'My National Parks Adventure', url }); return; }
      catch { /* user cancelled the share sheet — fall through to clipboard copy */ }
    }
    await navigator.clipboard.writeText(url);
    alert('Link copied. This entry is now public to anyone with the link — the rest of your journal stays private.');
  };

  if (loading) return <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-3)', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase' }}>Loading your journal…</div>;

  const photoCount = entries.reduce((a, e) => a + (e.photos ? e.photos.length : 0), 0);
  const parkCount = new Set(entries.map(e => e.park_slug)).size;
  const byd = Object.fromEntries(parkIndex.map(p => [p.slug, p]));

  // Month-group the entries (already date-sorted by listJournal). Spec §3.2.
  const groups = [];
  let curLabel = null, curGroup = null;
  for (const e of entries) {
    const label = monthLabel(e.entry_date);
    if (label !== curLabel) { curGroup = { label, items: [] }; groups.push(curGroup); curLabel = label; }
    curGroup.items.push(e);
  }

  return (
    <div style={{ background: 'var(--bg)', minHeight: '100%', paddingBottom: 110 }}>
      <div style={{ padding: '58px 22px 0' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <Caps s={10} c="var(--accent)">Field Notes</Caps>
            <h1 style={{ margin: '6px 0 0', fontFamily: 'Space Grotesk, sans-serif', fontWeight: 700, fontSize: 44, lineHeight: 0.95, letterSpacing: '-0.02em', color: 'var(--ink)' }}>The journal.</h1>
          </div>
          <button onClick={() => setComposerOpen(true)} style={{ width: 40, height: 40, borderRadius: '50%', border: '1px solid var(--line)', background: 'var(--paper)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-2)' }}>{I.plus()}</button>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16, marginTop: 24, padding: '18px 0', borderTop: '1px solid var(--line)', borderBottom: '1px solid var(--line)' }}>
          <Metric n={entries.length} l="Entries"/>
          <Metric n={photoCount} l="Photos"/>
          <Metric n={parkCount} l="Parks"/>
        </div>
      </div>

      {composerOpen && parkIndex.length > 0 && (
        <NewEntryComposer parkIndex={parkIndex} onClose={() => setComposerOpen(false)} onSaved={async () => { setComposerOpen(false); await load(); }}/>
      )}

      <SectionHead eyebrow="Previous Entries" title="All field notes"/>
      <div style={{ padding: '0 22px' }}>
        {entries.length === 0 && (
          <div style={{ padding: '10px 0 24px', textAlign: 'center' }}>
            <EmptyJournalPlate/>
            <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontStyle: 'italic', color: 'var(--ink-3)', marginTop: 10 }}>Your first entry is the hardest one.</div>
            <button onClick={() => setComposerOpen(true)} style={{ marginTop: 14, padding: '11px 22px', background: 'var(--ink)', color: 'var(--bg)', border: 'none', borderRadius: 100, cursor: 'pointer', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase' }}>+ Start writing</button>
          </div>
        )}
        {groups.map(g => (
          <div key={g.label}>
            <div style={{ position: 'sticky', top: 0, background: 'var(--bg)', padding: '10px 0', borderBottom: '1px solid var(--line)', zIndex: 5 }}>
              <Caps s={9}>{g.label} · {g.items.length} ENTR{g.items.length === 1 ? 'Y' : 'IES'}</Caps>
            </div>
            {g.items.map((e) => {
              const p = byd[e.park_slug] || { name: e.park_slug };
              const coords = coordLine(p);
              return (
                <div key={e.id} style={{ position: 'relative', margin: '16px 0', padding: '20px', border: '1px solid var(--line)', borderRadius: 3, background: 'var(--paper)' }}>
                  {e.favorite && <CornerMarks c="var(--accent)" pad={10} len={12} w={1.4}/>}
                  <div style={{ display: 'grid', gridTemplateColumns: '64px 1fr', gap: 16 }}>
                    <div>
                      <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontWeight: 700, fontSize: 32, lineHeight: 1, color: 'var(--ink)' }}>{dayNum(e.entry_date)}</div>
                      <Caps s={8} style={{ display: 'block', marginTop: 3 }}>{monthAbbrev(e.entry_date)}</Caps>
                    </div>
                    <div>
                      <button onClick={() => openPark(e.park_slug)} style={{ border: 'none', background: 'none', padding: 0, cursor: 'pointer', display: 'block' }}>
                        <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontSize: 20, color: 'var(--ink)' }}>{p.name}</div>
                      </button>
                      {coords && <Caps s={9} style={{ display: 'block', marginTop: 2 }}>{coords}</Caps>}
                      {e.title && <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontSize: 17, fontWeight: 600, color: 'var(--ink)', marginTop: 10 }}>{e.title}</div>}
                      {e.body && <div style={{ fontFamily: 'DM Sans, sans-serif', fontSize: 15, lineHeight: 1.55, color: 'var(--ink-2)', marginTop: 6 }}>{e.body}</div>}
                    </div>
                  </div>

                  {e.photos.length > 0 && (
                    <div style={{ display: 'flex', gap: 8, marginTop: 16, overflowX: 'auto', scrollbarWidth: 'none' }}>
                      {e.photos.map(ph => (
                        <div key={ph.id} style={{ flex: '0 0 auto', width: 96, height: 96, borderRadius: 2, border: '1px solid var(--line)', overflow: 'hidden' }}>
                          <img src={ph.url} style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
                        </div>
                      ))}
                      <label style={{ flex: '0 0 auto', width: 96, height: 96, borderRadius: 2, border: '1px dashed var(--line)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-3)' }}>
                        {uploadingId === e.id ? <Caps s={8}>…</Caps> : I.camera('var(--ink-3)')}
                        <input type="file" accept="image/*" style={{ display: 'none' }} disabled={uploadingId === e.id}
                          onChange={ev => { const f = ev.target.files[0]; if (f) addPhoto(e.id, f); ev.target.value = ''; }}/>
                      </label>
                    </div>
                  )}
                  {e.photos.length === 0 && (
                    <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginTop: 16, border: '1px dashed var(--line)', borderRadius: 100, padding: '7px 13px', cursor: 'pointer', color: 'var(--ink-3)', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.08em', textTransform: 'uppercase' }}>
                      {I.camera('var(--ink-3)')} {uploadingId === e.id ? 'Uploading…' : 'Add photo'}
                      <input type="file" accept="image/*" style={{ display: 'none' }} disabled={uploadingId === e.id}
                        onChange={ev => { const f = ev.target.files[0]; if (f) addPhoto(e.id, f); ev.target.value = ''; }}/>
                    </label>
                  )}

                  <div style={{ display: 'flex', gap: 16, marginTop: 16, paddingTop: 14, borderTop: '1px solid var(--line)', alignItems: 'center', flexWrap: 'wrap' }}>
                    {e.miles != null && <Caps s={9}>{e.miles} MI</Caps>}
                    {e.weather && <Caps s={9}>{e.weather}</Caps>}
                    <div style={{ flex: 1 }}/>
                    <button onClick={() => toggleFavorite(e)} style={{ border: 'none', background: 'none', padding: 0, cursor: 'pointer', color: e.favorite ? 'var(--accent)' : 'var(--ink-3)' }} title="Favorite">
                      {e.favorite ? '★' : '☆'}
                    </button>
                    <button onClick={() => share(e)} style={{ border: 'none', background: 'none', padding: 0, cursor: 'pointer', color: 'var(--ink-3)', display: 'flex', alignItems: 'center' }} title="Share">
                      {I.share()}
                    </button>
                    <button onClick={() => removeEntry(e.id)} style={{ border: 'none', background: 'none', padding: 0, cursor: 'pointer', color: 'var(--ink-3)', fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Delete</button>
                  </div>
                </div>
              );
            })}
          </div>
        ))}
      </div>

      <SectionHead eyebrow="Before, During, or After" title="Reading List"/>
      <div style={{ padding: '0 22px' }}>
        <ReadingListSection/>
      </div>
    </div>
  );
}

Object.assign(window, { JournalScreen });
