// Life Memory Tree — shared primitives.
//
// Tiny composable building blocks used across every viewport. Each one maps
// to a concept from the LMT docs: a leaf = an event, a scene chip = a privacy
// container, a connection edge = a relation between events, etc.

const { useState: lus, useEffect: lue, useRef: lur } = React;
const lcx = (...a) => a.filter(Boolean).join(' ');

// Sample dataset — used by every screen so the viewports stay coherent.
window.LMTData = (function () {
  // Days-since values seed the recency gradient.
  const events = [
    { id: 'e01', title: 'Lin called from Kyoto — first snow', t: '2d',  daysSince: 2,   scene: 'Lin & me',         mood: 4, tags: ['lin','snow','phone-call'],   people: ['Lin Park'],                 place: 'Kyoto · Higashiyama',     visibility: 'scene',   fragile: false, links: 3 },
    { id: 'e02', title: 'Submitted the residency application',   t: '4d',  daysSince: 4,   scene: 'Work · 2026',        mood: 3, tags: ['residency','writing'],       people: [],                            place: 'Home · desk',              visibility: 'private', fragile: false, links: 2 },
    { id: 'e03', title: 'Mom\'s biopsy came back clean',         t: '6d',  daysSince: 6,   scene: 'Family',             mood: 5, tags: ['mom','health','relief'],     people: ['Vera (mom)'],                place: 'Hospital — Aurora',        visibility: 'private', fragile: true,  links: 5 },
    { id: 'e04', title: 'Walked the Buena Vista loop with Theo', t: '11d', daysSince: 11,  scene: 'Theo · weekly',      mood: 4, tags: ['walk','park','theo'],        people: ['Theo (dog)'],                place: 'Buena Vista Park',         visibility: 'scene',   fragile: false, links: 2 },
    { id: 'e05', title: 'First real fight with N. in months',    t: '18d', daysSince: 18,  scene: 'N. & me',            mood: 2, tags: ['conflict','partner'],        people: ['N.'],                        place: 'Apartment · kitchen',      visibility: 'private', fragile: true,  links: 4 },
    { id: 'e06', title: 'Book club — finally finished Sebald',   t: '24d', daysSince: 24,  scene: 'Reading',            mood: 4, tags: ['book-club','sebald'],        people: ['Anna','Will','Priya'],       place: 'Anna\'s flat',             visibility: 'scene',   fragile: false, links: 1 },
    { id: 'e07', title: 'Repotted the fig — it survived winter', t: '32d', daysSince: 32,  scene: 'Apartment · plants', mood: 4, tags: ['plants','fig','spring'],     people: [],                            place: 'Home · sunroom',           visibility: 'private', fragile: false, links: 0 },
    { id: 'e08', title: 'Dad\'s 70th — dinner at the lake',      t: '47d', daysSince: 47,  scene: 'Family',             mood: 5, tags: ['dad','birthday','family'],   people: ['Vera','Marcus','Joel'],      place: 'Lake Anza',                visibility: 'scene',   fragile: false, links: 6 },
    { id: 'e09', title: 'Cried on the BART for no reason',       t: '58d', daysSince: 58,  scene: 'Quiet · me',         mood: 2, tags: ['feelings','commute'],        people: [],                            place: 'BART · 12th St Oakland',   visibility: 'private', fragile: true,  links: 1 },
    { id: 'e10', title: 'Quit the agency contract',              t: '71d', daysSince: 71,  scene: 'Work · 2026',        mood: 3, tags: ['work','contract','decision'],people: ['Aidan (mgr)'],                place: 'Cafe · Trouble',           visibility: 'private', fragile: false, links: 3 },
    { id: 'e11', title: 'Saw the comet from the roof',           t: '88d', daysSince: 88,  scene: 'Nights',             mood: 5, tags: ['comet','sky','roof'],        people: ['N.'],                        place: 'Apartment · roof',         visibility: 'public',  fragile: false, links: 2 },
    { id: 'e12', title: 'Started running again after the surgery', t: '120d', daysSince: 120, scene: 'Body',              mood: 4, tags: ['running','recovery'],        people: [],                            place: 'Lake Merritt',             visibility: 'private', fragile: false, links: 4 },
  ];

  const scenes = [
    { id: 's-family',  title: 'Family',             count: 47, privacy: 'scene',   collaborators: 3, color: '#d97706', glyph: '🜂' },
    { id: 's-lin',     title: 'Lin & me',           count: 28, privacy: 'private', collaborators: 0, color: '#15803d', glyph: '✦' },
    { id: 's-work',    title: 'Work · 2026',        count: 31, privacy: 'private', collaborators: 0, color: '#2563eb', glyph: '◇' },
    { id: 's-reading', title: 'Reading',            count: 19, privacy: 'scene',   collaborators: 4, color: '#9333ea', glyph: '☐' },
    { id: 's-theo',    title: 'Theo · weekly',      count: 64, privacy: 'private', collaborators: 0, color: '#84cc16', glyph: '◐' },
    { id: 's-body',    title: 'Body',               count: 22, privacy: 'private', collaborators: 0, color: '#dc2626', glyph: '○' },
    { id: 's-nights',  title: 'Nights',             count: 14, privacy: 'public',  collaborators: 0, color: '#16a34a', glyph: '☾' },
    { id: 's-quiet',   title: 'Quiet · me',         count: 38, privacy: 'private', collaborators: 0, color: '#64748b', glyph: '◍' },
  ];

  // AI suggestions surfaced into the right panel.
  const suggestions = [
    { id: 'sg1', kind: 'link',    confidence: 0.91, target: 'e03', text: 'Link "Mom\'s biopsy" to "Dad\'s 70th" — same scene, 41 days apart, same people.', action: 'Create part-of link' },
    { id: 'sg2', kind: 'media',   confidence: 0.84, target: 'e01', text: 'You have 4 photos from Dec 14 — attach to "Lin called from Kyoto"?',                  action: 'Review 4 photos' },
    { id: 'sg3', kind: 'tag',     confidence: 0.77, target: 'e10', text: 'Add tag #transition? This event is connected to 3 others tagged that way.',          action: 'Add tag' },
    { id: 'sg4', kind: 'emotion', confidence: 0.72, target: 'e09', text: 'You haven\'t set a mood for this entry. Want to add one?',                            action: 'Set mood' },
    { id: 'sg5', kind: 'person',  confidence: 0.69, target: 'e06', text: '"Priya" appears in 3 unlinked entries — promote to a Person?',                       action: 'Promote' },
  ];

  // Today buckets (matches EnhancedTodayPanel.tsx)
  const todayItems = [
    { id: 't1', bucket: 'time-bound', title: 'Send Lin photos before she lands',     why: 'She lands at 11pm tonight (SFO) — last surfaced 2d ago', dur: 8,  when: 'today · 4pm' },
    { id: 't2', bucket: 'unblocker',  title: 'Reply to Aidan about the contract',     why: '3 entries waiting on this · blocking Work · 2026 scene',  dur: 15, when: 'today' },
    { id: 't3', bucket: 'quick-win',  title: 'Write 2 lines about mom\'s good news',  why: 'Fragile event from 6d ago has no description yet',        dur: 3,  when: 'today' },
    { id: 't4', bucket: 'new',        title: 'Review 4 photos from yesterday',        why: 'Auto-imported from camera roll — needs your sort',        dur: 5,  when: 'today' },
  ];

  // Notifications / echoes
  const echoes = [
    { id: 'ec1', kind: 'anniversary', text: 'One year ago today: "Theo\'s first walk after surgery"',      meta: 'Theo · weekly · 365d' },
    { id: 'ec2', kind: 'recurring',   text: '5th time at "Lake Anza" — promote to a Place?',                meta: 'Place · pending' },
    { id: 'ec3', kind: 'pattern',     text: 'Mood pattern: 3 low-mood Sundays in a row',                    meta: 'Pattern · last 3w' },
    { id: 'ec4', kind: 'gap',         text: 'Gap of 12 days in Work · 2026 — capture a check-in?',          meta: 'Work · 2026' },
  ];

  return { events, scenes, suggestions, todayItems, echoes };
})();

// ─── Leaf shape (used everywhere for "an event") ──────────────────────────
// A modern, graphic leaf — single asymmetric blade, crisp tip, thin midrib.
// Snappier than the watercolor woodcut version it replaces.
function LeafShape({ color = '#15803d', size = 32, rotate = 0, vein = true, glow = false, style = {} }) {
  const id = 'lf' + Math.abs(((color + size) + '').split('').reduce((a,c) => a*31 + c.charCodeAt(0), 0));
  return (
    <svg width={size} height={size} viewBox="0 0 32 32" style={{ transform: `rotate(${rotate}deg)`, overflow: 'visible', ...style }}>
      <defs>
        <linearGradient id={id} x1="0" y1="1" x2="1" y2="0">
          <stop offset="0" stopColor={color} stopOpacity="0.78"/>
          <stop offset="1" stopColor={color} stopOpacity="1"/>
        </linearGradient>
      </defs>
      {glow && <circle cx="16" cy="16" r="15" fill={color} opacity="0.14"/>}
      {/* Asymmetric teardrop blade — pointed tip top-right, rounded base bottom-left */}
      <path d="M4 28 C 4 14, 12 4, 28 4 C 28 18, 20 28, 4 28 Z" fill={`url(#${id})`}/>
      <path d="M4 28 C 4 14, 12 4, 28 4 C 28 18, 20 28, 4 28 Z" fill="none" stroke={color} strokeWidth="0.5" opacity="0.55"/>
      {vein && <path d="M5 27 L 27 5" stroke="rgba(255,255,255,0.55)" strokeWidth="0.9" strokeLinecap="round"/>}
    </svg>
  );
}

// ─── Chip / Badge / Pill ──────────────────────────────────────────────────
function Chip({ children, tone = 'neutral', size = 'sm', icon, onClick, active = false, style = {} }) {
  const tones = {
    neutral:  { bg: '#edede6', fg: '#54635c', bd: '#dcdcd2' },
    ink:      { bg: '#0d1410', fg: '#ffffff', bd: '#0d1410' },
    accent:   { bg: '#15803d15', fg: '#15803d', bd: '#15803d44' },
    amber:    { bg: '#d9770615', fg: '#92400e', bd: '#d9770644' },
    rose:     { bg: '#dc262615', fg: '#991b1b', bd: '#dc262644' },
    blue:     { bg: '#2563eb15', fg: '#1d4ed8', bd: '#2563eb44' },
    sage:     { bg: '#16a34a22', fg: '#15803d', bd: '#16a34a66' },
    purple:   { bg: '#9333ea15', fg: '#7e22ce', bd: '#9333ea44' },
    paper:    { bg: '#ffffff', fg: '#0d1410', bd: '#dcdcd2' },
    ghost:    { bg: 'transparent', fg: '#54635c', bd: 'transparent' },
  };
  const t = tones[tone] || tones.neutral;
  const sz = size === 'xs'
    ? { fs: 10, px: 6,  py: 1,   gap: 3, h: 18 }
    : size === 'lg'
    ? { fs: 13, px: 12, py: 5,   gap: 6, h: 28 }
    : { fs: 11, px: 8,  py: 2.5, gap: 4, h: 22 };
  return (
    <span onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: sz.gap,
      background: active ? t.fg : t.bg, color: active ? t.bg : t.fg,
      border: `1px solid ${t.bd}`, borderRadius: 999,
      padding: `${sz.py}px ${sz.px}px`, fontSize: sz.fs, fontWeight: 500,
      lineHeight: 1, height: sz.h, whiteSpace: 'nowrap',
      cursor: onClick ? 'pointer' : 'default', ...style
    }}>
      {icon}{children}
    </span>
  );
}

// ─── Visibility lozenge ───────────────────────────────────────────────────
function VisChip({ v = 'private', size = 'sm' }) {
  const { Lock, Eye, Globe } = window.LMTIcons;
  const map = {
    private: { I: Lock,   label: 'Private', tone: 'neutral', color: '#54635c' },
    scene:   { I: Eye,    label: 'Scene',   tone: 'amber',   color: '#92400e' },
    public:  { I: Globe,  label: 'Public',  tone: 'sage',    color: '#15803d' },
  };
  const m = map[v];
  return <Chip tone={m.tone} size={size} icon={<m.I style={{ fontSize: size === 'xs' ? 9 : 11 }}/>}>{m.label}</Chip>;
}

// ─── Mood dot ─────────────────────────────────────────────────────────────
function MoodDot({ level = 3, size = 10, label = false }) {
  const m = LMT.mood[level] || LMT.mood[3];
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#54635c', fontSize: 11 }}>
      <span style={{ width: size, height: size, borderRadius: '50%', background: m.color, boxShadow: `inset 0 0 0 1px rgba(0,0,0,0.06)` }} />
      {label && <span className="lmt-mono" style={{ fontSize: 10, color: '#8d958f' }}>{m.label}</span>}
    </span>
  );
}

// ─── EventLeaf — the core event card ──────────────────────────────────────
// Renders one event as a "leaf card": leaf icon left, title + meta middle,
// connections + mood right. Density tunable for mobile/desktop.
function EventLeaf({ event, dense = false, onClick, selected = false, showScene = true, surface = 'card' }) {
  const c = LMT.leafFor(event.daysSince);
  const surfaces = {
    card:  { bg: '#ffffff', bd: '#e8e8df', sh: '0 1px 2px rgba(13, 20, 16,0.04)' },
    sunk:  { bg: '#edede6', bd: 'transparent', sh: 'none' },
    paper: { bg: 'transparent', bd: 'transparent', sh: 'none' },
  };
  const s = surfaces[surface];
  return (
    <div onClick={onClick} style={{
      display: 'flex', alignItems: 'flex-start', gap: dense ? 8 : 10,
      padding: dense ? '8px 10px' : '12px 14px',
      background: selected ? '#eaf3ec' : s.bg,
      border: `1px solid ${selected ? '#d9770688' : s.bd}`,
      borderRadius: 12, boxShadow: s.sh, cursor: onClick ? 'pointer' : 'default',
      transition: 'background .15s, border-color .15s, transform .15s',
    }}>
      <div style={{ position: 'relative', flex: '0 0 auto', paddingTop: 2 }}>
        <LeafShape color={c} size={dense ? 22 : 28} rotate={-22 + (event.id ? event.id.charCodeAt(2) % 30 : 0)} />
        {event.fragile && (
          <span title="Fragile" style={{ position: 'absolute', top: -2, right: -3, width: 8, height: 8, borderRadius: '50%', background: '#dc2626', border: '1.5px solid #ffffff' }}/>
        )}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="lmt-display" style={{ fontSize: dense ? 14 : 15.5, lineHeight: 1.25, color: '#0d1410', fontWeight: 500, textWrap: 'pretty' }}>
          {event.title}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: dense ? 3 : 5, color: '#8d958f', fontSize: 11 }}>
          <span className="lmt-mono lmt-tnum">{event.t}</span>
          {showScene && <><span style={{ color: '#dcdcd2' }}>·</span><span style={{ color: '#54635c' }}>{event.scene}</span></>}
          {event.place && <><span style={{ color: '#dcdcd2' }}>·</span><span>{event.place.split(' · ')[0]}</span></>}
        </div>
        {!dense && event.tags && event.tags.length > 0 && (
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginTop: 6 }}>
            {event.tags.slice(0, 3).map(t => (
              <span key={t} style={{ fontSize: 10, color: '#54635c', background: '#edede6', padding: '2px 6px', borderRadius: 4 }}>#{t}</span>
            ))}
          </div>
        )}
      </div>
      <div style={{ flex: '0 0 auto', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6, paddingTop: 2 }}>
        <MoodDot level={event.mood} size={dense ? 8 : 9} />
        {event.links > 0 && (
          <span style={{ fontSize: 10, color: '#8d958f', display: 'inline-flex', alignItems: 'center', gap: 3 }}>
            <span style={{ width: 4, height: 4, borderRadius: '50%', background: '#b6bbb6' }}/>
            <span className="lmt-mono lmt-tnum">{event.links}</span>
          </span>
        )}
      </div>
    </div>
  );
}

// ─── Section header ───────────────────────────────────────────────────────
function SectionH({ kicker, title, right, level = 1, style = {} }) {
  return (
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, ...style }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        {kicker && <div className="lmt-mono" style={{ fontSize: 10, color: '#8d958f', textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 4 }}>{kicker}</div>}
        <div className="lmt-display" style={{ fontSize: level === 1 ? 22 : level === 2 ? 17 : 14, fontWeight: 500, color: '#0d1410', lineHeight: 1.2, textWrap: 'balance' }}>{title}</div>
      </div>
      {right && <div style={{ flex: '0 0 auto' }}>{right}</div>}
    </div>
  );
}

// ─── BucketChip — Today buckets ───────────────────────────────────────────
function BucketChip({ bucket, count, active = false, onClick }) {
  const b = LMT.buckets[bucket];
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '6px 10px', borderRadius: 999, fontSize: 12,
      border: `1px solid ${active ? b.tone : '#dcdcd2'}`,
      background: active ? `${b.tone}15` : '#ffffff',
      color: active ? b.tone : '#54635c',
      fontWeight: 500, cursor: 'pointer', whiteSpace: 'nowrap',
    }}>
      <span style={{ color: b.tone, fontSize: 13 }}>{b.glyph}</span>
      <span>{b.label}</span>
      {count != null && <span className="lmt-mono lmt-tnum" style={{ color: '#8d958f', fontSize: 11 }}>{count}</span>}
    </button>
  );
}

// ─── SceneChip ────────────────────────────────────────────────────────────
function SceneChip({ scene, active = false, onClick }) {
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '5px 10px 5px 7px', borderRadius: 999, fontSize: 12,
      border: `1px solid ${active ? scene.color + 'aa' : '#dcdcd2'}`,
      background: active ? scene.color + '15' : '#ffffff',
      color: '#0d1410', cursor: 'pointer', whiteSpace: 'nowrap',
    }}>
      <span style={{ width: 6, height: 6, borderRadius: '50%', background: scene.color }}/>
      <span>{scene.title}</span>
      <span className="lmt-mono lmt-tnum" style={{ color: '#8d958f', fontSize: 10 }}>{scene.count}</span>
    </button>
  );
}

// ─── Button ───────────────────────────────────────────────────────────────
function Btn({ children, kind = 'ghost', size = 'md', icon, onClick, style = {} }) {
  const kinds = {
    primary: { bg: '#0d1410', fg: '#ffffff',   bd: '#0d1410' },
    accent:  { bg: '#15803d', fg: '#ffffff',   bd: '#15803d' },
    amber:   { bg: '#d97706', fg: '#ffffff',   bd: '#d97706' },
    paper:   { bg: '#ffffff', fg: '#0d1410',   bd: '#dcdcd2' },
    ghost:   { bg: 'transparent', fg: '#0d1410', bd: 'transparent' },
    danger:  { bg: '#dc2626', fg: '#ffffff',   bd: '#dc2626' },
  };
  const k = kinds[kind] || kinds.ghost;
  const sz = size === 'sm' ? { fs: 12, px: 10, py: 5 } : size === 'lg' ? { fs: 14, px: 18, py: 10 } : { fs: 13, px: 14, py: 8 };
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      background: k.bg, color: k.fg, border: `1px solid ${k.bd}`,
      borderRadius: 8, padding: `${sz.py}px ${sz.px}px`,
      fontSize: sz.fs, fontWeight: 500, fontFamily: 'inherit',
      cursor: 'pointer', ...style
    }}>{icon}{children}</button>
  );
}

// Connection edge label
function EdgeLabel({ rel = 'leads-to' }) {
  const c = LMT.connections[rel];
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10, color: c.c, background: c.c + '12', padding: '2px 6px', borderRadius: 4 }} className="lmt-mono">
      <span>{c.arrow}</span><span>{c.label}</span>
    </span>
  );
}

Object.assign(window, {
  LeafShape, Chip, VisChip, MoodDot, EventLeaf, SectionH, BucketChip,
  SceneChip, Btn, EdgeLabel, lcx,
});
