// Journal.jsx — Fase 2.4
// Design source: v2/New_design/Journal Comparison.html (mobil + desktop side om side)
// Data: logbook_entries (heading, notes), mood_entries (mood 1-5), logbook_tracker_entries (sleep, energy)
const {
  useState: useJState,
  useEffect: useJEffect,
  useRef: useJRef,
  useMemo: useJMemo,
} = React;

function journalDemo() {
  return window.EASYLIFE_DEMO?.enabled ? window.EASYLIFE_DEMO : null;
}

// ── Date helpers ─────────────────────────────────────────────────
const J_DAY_SHORT = ['Søn','Man','Tir','Ons','Tor','Fre','Lør'];
const J_DAY_FULL  = ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'];
const J_MONTH     = ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'];
const J_MONTH_SHORT = ['Jan','Feb','Mar','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Des'];

function jToKey(d) {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${dd}`;
}
function jFromKey(k) {
  const [y, m, d] = k.split('-').map(Number);
  return new Date(y, m - 1, d);
}
function jSameDay(a, b) {
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
}
function jFmtFull(d) {
  return `${J_DAY_FULL[d.getDay()]} ${d.getDate()}. ${J_MONTH[d.getMonth()]}`;
}
function jStrip(center) {
  return Array.from({ length: 7 }, (_, i) => {
    const d = new Date(center);
    d.setDate(center.getDate() - 3 + i);
    return d;
  });
}

const J_MOODS = [
  { emoji: '😔', label: 'Trist' },
  { emoji: '😕', label: 'Ned' },
  { emoji: '😐', label: 'Nøytral' },
  { emoji: '🙂', label: 'Bra' },
  { emoji: '😄', label: 'Topp' },
];

// ── MoodPicker (shared) ──────────────────────────────────────────
function JMoodPicker({ value, onChange, size = 22 }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', gap: 4 }}>
      {J_MOODS.map((m, i) => {
        const sel = value === i;
        return (
          <button
            key={i}
            onClick={() => onChange(sel ? null : i)}
            className={`j-mood-btn ${sel ? 'sel' : ''}`}
            style={{
              flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
              background: sel ? 'var(--accent-d)' : 'var(--surface-b)',
              border: sel ? '1.5px solid var(--accent)' : '1.5px solid transparent',
              cursor: 'pointer', padding: '8px 4px', borderRadius: 12,
              fontFamily: 'inherit',
              transition: 'transform 0.18s cubic-bezier(0.34,1.56,0.64,1)',
              transform: sel ? 'scale(1.08)' : 'scale(1)',
            }}
          >
            <span style={{ fontSize: size, lineHeight: 1, filter: value == null ? 'grayscale(0.5) opacity(0.6)' : sel ? 'none' : 'grayscale(1) opacity(0.25)', transition: 'filter 0.2s' }}>{m.emoji}</span>
            <span style={{ fontSize: 8, fontWeight: 600, color: sel ? 'var(--accent)' : 'var(--mut)', letterSpacing: '0.2px' }}>{m.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ── DateStrip (mobile) ───────────────────────────────────────────
function JDateStrip({ selected, onSelect, entries }) {
  const today = new Date();
  const days = jStrip(selected);
  const ref = useJRef(null);

  useJEffect(() => {
    const el = ref.current;
    if (!el) return;
    const btn = el.querySelector('[data-sel="1"]');
    if (btn) el.scrollLeft = btn.offsetLeft - el.offsetWidth / 2 + btn.offsetWidth / 2;
  }, [jToKey(selected)]);

  return (
    <div style={{ position: 'relative', flexShrink: 0 }}>
      <div ref={ref} style={{ display: 'flex', gap: 7, padding: '2px 20px', overflowX: 'auto', scrollbarWidth: 'none' }}>
        {days.map((d, i) => {
          const isSel = jSameDay(d, selected);
          const isToday = jSameDay(d, today);
          const hasData = !!entries[jToKey(d)];
          return (
            <button
              key={i}
              data-sel={isSel ? '1' : '0'}
              onClick={() => onSelect(d)}
              style={{
                flexShrink: 0, width: 47, height: 66, borderRadius: 18,
                display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 3,
                border: isSel ? '1.5px solid var(--accent)' : '1.5px solid transparent',
                background: isSel ? 'var(--accent-d)' : 'var(--surface-b)',
                cursor: 'pointer', transition: 'all 0.2s', fontFamily: 'inherit',
              }}
            >
              <span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.6px', textTransform: 'uppercase', color: isSel ? 'var(--accent)' : isToday ? 'var(--sec)' : 'var(--mut)' }}>{J_DAY_SHORT[d.getDay()]}</span>
              <span style={{ fontSize: 19, fontWeight: isSel ? 800 : 600, lineHeight: 1, color: isSel ? 'var(--accent)' : isToday ? 'var(--pri)' : 'var(--sec)' }}>{d.getDate()}</span>
              <div style={{ width: 4, height: 4, borderRadius: '50%', background: hasData ? (isSel ? 'var(--accent)' : 'var(--accent-bd)') : 'transparent' }} />
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── JournalEditor (shared rich text editor) ──────────────────────
function JEditor({ text, onChange, placeholder, minHeight = 132 }) {
  const editorRef = useJRef(null);
  useJEffect(() => {
    if (editorRef.current) editorRef.current.innerHTML = text || '';
  }, []);

  function onInput() {
    onChange(editorRef.current?.innerHTML || '');
  }

  return (
    <div style={{ position: 'relative', minHeight }}>
      {!text && (
        <p style={{
          position: 'absolute', top: 0, left: 0, right: 0,
          color: 'var(--mut)', fontSize: 15, lineHeight: 1.8,
          pointerEvents: 'none', userSelect: 'none',
        }}>{placeholder}</p>
      )}
      <div
        ref={editorRef}
        contentEditable
        suppressContentEditableWarning
        onInput={onInput}
        style={{
          minHeight, outline: 'none', fontSize: 15, lineHeight: 1.82,
          color: 'var(--pri)', fontFamily: 'inherit', caretColor: 'var(--accent)',
          wordBreak: 'break-word',
        }}
      />
    </div>
  );
}

// ── TrackerCard (slider 1-10) ────────────────────────────────────
function JTrackerCard({ icon, label, value, onChange }) {
  const containerRef = useJRef(null);
  const dragging = useJRef(false);

  const updateValue = (e) => {
    if (!containerRef.current) return;
    const rect = containerRef.current.getBoundingClientRect();
    const ratio = (e.clientX - rect.left) / rect.width;
    onChange(Math.round(Math.max(0, Math.min(1, ratio)) * 9) + 1);
  };

  useJEffect(() => {
    const move = (e) => { if (dragging.current) updateValue(e); };
    const up = () => { dragging.current = false; };
    document.addEventListener('mousemove', move);
    document.addEventListener('mouseup', up);
    return () => {
      document.removeEventListener('mousemove', move);
      document.removeEventListener('mouseup', up);
    };
  }, []);

  const pct = value ? ((value - 1) / 9) * 100 : 0;

  return (
    <div style={{
      flex: 1, background: 'var(--bg-card)', borderRadius: 18,
      padding: '16px 14px', border: '1px solid var(--bdr)',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14 }}>
        <span style={{ fontSize: 18 }}>{icon}</span>
        <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--sec)', flex: 1 }}>{label}</span>
        {value != null && <span style={{ fontSize: 16, fontWeight: 800, color: 'var(--accent)' }}>{value}</span>}
      </div>
      <div
        ref={containerRef}
        onMouseDown={(e) => { dragging.current = true; updateValue(e); }}
        style={{
          position: 'relative', height: 48, borderRadius: 10,
          background: 'var(--surface-b)', cursor: 'pointer',
          border: '1px solid var(--bdr)',
        }}
      >
        <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: pct + '%', background: 'var(--accent-d)', borderRadius: 10 }} />
        {value != null && (
          <div style={{
            position: 'absolute', top: '50%', left: pct + '%',
            transform: 'translate(-50%,-50%)',
            width: 40, height: 40, borderRadius: 999,
            background: 'radial-gradient(circle, var(--accent), var(--accent-d))',
            border: '2px solid var(--accent)',
            boxShadow: '0 0 12px var(--accent-bd)',
          }} />
        )}
        <div style={{ position: 'absolute', inset: 0, display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '0 8px', pointerEvents: 'none' }}>
          <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--mut)', opacity: 0.5 }}>1</span>
          <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--mut)', opacity: 0.5 }}>10</span>
        </div>
      </div>
    </div>
  );
}

// ── MiniCalendar (desktop sidebar) ───────────────────────────────
function JMiniCalendar({ selected, onSelect, entries, currentMonth, onMonthChange }) {
  const year = currentMonth.getFullYear();
  const month = currentMonth.getMonth();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const firstDay = new Date(year, month, 1).getDay();
  const today = new Date();

  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <button onClick={() => onMonthChange(new Date(year, month - 1, 1))} style={{
          background: 'none', border: '1px solid var(--bdr)', color: 'var(--sec)',
          cursor: 'pointer', fontSize: 14, width: 24, height: 24, borderRadius: 6,
          display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'inherit',
        }}>‹</button>
        <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--pri)', letterSpacing: '0.4px' }}>
          {J_MONTH_SHORT[month].toUpperCase()} {year}
        </span>
        <button onClick={() => onMonthChange(new Date(year, month + 1, 1))} style={{
          background: 'none', border: '1px solid var(--bdr)', color: 'var(--sec)',
          cursor: 'pointer', fontSize: 14, width: 24, height: 24, borderRadius: 6,
          display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'inherit',
        }}>›</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 1, marginBottom: 3 }}>
        {['S','M','T','O','T','F','L'].map((d, i) => (
          <div key={i} style={{ textAlign: 'center', fontSize: 9, color: 'var(--mut)', fontWeight: 700, padding: '2px 0' }}>{d}</div>
        ))}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 1 }}>
        {Array.from({ length: firstDay }, (_, i) => <div key={`b${i}`} />)}
        {Array.from({ length: daysInMonth }, (_, i) => {
          const day = i + 1;
          const d = new Date(year, month, day);
          const isSel = jSameDay(d, selected);
          const isTod = jSameDay(d, today);
          const hasEntry = !!entries[jToKey(d)];
          return (
            <button
              key={day}
              onClick={() => onSelect(d)}
              style={{
                aspectRatio: '1', border: 'none', borderRadius: 5, cursor: 'pointer', padding: 0,
                background: isSel ? 'var(--accent)' : 'transparent',
                color: isSel ? '#000' : isTod ? 'var(--accent)' : hasEntry ? 'var(--pri)' : 'var(--sec)',
                fontSize: 10, fontWeight: isSel || isTod ? 700 : 400,
                fontFamily: 'inherit', position: 'relative',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}
            >
              {day}
              {hasEntry && !isSel && (
                <div style={{ position: 'absolute', bottom: 1, left: '50%', transform: 'translateX(-50%)', width: 2.5, height: 2.5, borderRadius: '50%', background: 'var(--accent)' }} />
              )}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── HistorySheet (mobile bottom sheet) ───────────────────────────
function JHistorySheet({ isOpen, onClose, entries, onSelectDate }) {
  const sorted = Object.entries(entries).sort(([a], [b]) => b.localeCompare(a)).slice(0, 20);
  return (
    <div
      onClick={onClose}
      style={{
        position: 'fixed', inset: 0, zIndex: 1000,
        background: 'rgba(3,5,8,0.82)', backdropFilter: 'blur(10px)',
        display: 'flex', alignItems: 'flex-end',
        opacity: isOpen ? 1 : 0, pointerEvents: isOpen ? 'auto' : 'none',
        transition: 'opacity 0.28s',
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          width: '100%', background: 'var(--bg-card)',
          borderRadius: '24px 24px 0 0',
          border: '1px solid var(--bdr)', borderBottom: 'none',
          maxHeight: '72%', display: 'flex', flexDirection: 'column',
          transform: isOpen ? 'translateY(0)' : 'translateY(100%)',
          transition: 'transform 0.36s cubic-bezier(0.25,1,0.5,1)',
        }}
      >
        <div style={{ padding: '14px 20px 14px', flexShrink: 0, borderBottom: '1px solid var(--bdr)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', position: 'relative' }}>
          <div style={{ position: 'absolute', top: 8, left: '50%', transform: 'translateX(-50%)', width: 36, height: 4, borderRadius: 4, background: 'var(--bdr)' }} />
          <p style={{ fontSize: 15, fontWeight: 800, color: 'var(--pri)', paddingTop: 6, margin: 0 }}>Tidligere innlegg</p>
          <button onClick={onClose} style={{
            background: 'var(--surface-b)', border: 'none', width: 28, height: 28, borderRadius: 999,
            color: 'var(--sec)', cursor: 'pointer', fontSize: 16,
            display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 6,
          }}>×</button>
        </div>
        <div style={{ overflowY: 'auto', padding: '12px 20px 40px', display: 'flex', flexDirection: 'column', gap: 8 }}>
          {sorted.length === 0 && (
            <p style={{ color: 'var(--mut)', fontSize: 13, textAlign: 'center', padding: '24px 0', fontStyle: 'italic' }}>Ingen innlegg ennå</p>
          )}
          {sorted.map(([k, v], i) => {
            const d = jFromKey(k);
            const prev = (v.text || '').replace(/<[^>]*>/g, '').trim().slice(0, 55);
            return (
              <button
                key={i}
                onClick={() => { onSelectDate(d); onClose(); }}
                style={{
                  padding: '12px 14px', borderRadius: 14,
                  background: 'var(--surface-b)', border: '1px solid var(--bdr)',
                  cursor: 'pointer', display: 'flex', gap: 12, alignItems: 'center',
                  textAlign: 'left', fontFamily: 'inherit',
                }}
              >
                <div style={{ flexShrink: 0, textAlign: 'center', minWidth: 36 }}>
                  <p style={{ fontSize: 20, fontWeight: 800, color: 'var(--pri)', lineHeight: 1, margin: 0 }}>{d.getDate()}</p>
                  <p style={{ fontSize: 9, color: 'var(--mut)', fontWeight: 700, textTransform: 'uppercase', margin: 0 }}>{J_MONTH_SHORT[d.getMonth()]}</p>
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <p style={{ fontSize: 13, color: prev ? 'var(--sec)' : 'var(--mut)', fontStyle: prev ? 'normal' : 'italic', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', margin: 0 }}>{prev || 'Ingen tekst'}</p>
                </div>
                {v.mood != null && <span style={{ fontSize: 20, flexShrink: 0 }}>{J_MOODS[v.mood]?.emoji}</span>}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ══════════════════════════════════════════════════════════════════
// Journal main page
// ══════════════════════════════════════════════════════════════════
function Journal() {
  const today = new Date();
  const [selected, setSelected] = useJState(today);
  const [entries, setEntries] = useJState({});
  const [loading, setLoading] = useJState(true);
  const [saved, setSaved] = useJState(false);
  const [showHistory, setShowHistory] = useJState(false);
  const [currentMonth, setCurrentMonth] = useJState(new Date(today.getFullYear(), today.getMonth(), 1));
  const [isMobile, setIsMobile] = useJState(() => window.innerWidth < 900);
  const [todayActivity, setTodayActivity] = useJState({ tasksDone: 0, routinesDone: 0, focusMin: 0 });

  useJEffect(() => {
    const onResize = () => setIsMobile(window.innerWidth < 900);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  // Load data
  useJEffect(() => { loadData(); }, []);

  async function loadData() {
    setLoading(true);

    // Load today's activity stats (tasks done, routines done, focus time)
    try {
      const uid = await window.ensureCurrentUserId();
      if (uid) {
        const todayStr = new Date().toISOString().split('T')[0];
        const [todayTasks, todayRoutines] = await Promise.all([
          supabaseClient.from('todo_tasks').select('id', { count: 'exact', head: true }).eq('user_id', uid).not('completed_at', 'is', null).gte('completed_at', todayStr),
          supabaseClient.from('routines').select('id, completed_dates').eq('user_id', uid),
        ]);
        const completedRoutines = (todayRoutines.data || []).filter(r => Array.isArray(r.completed_dates) && r.completed_dates.includes(todayStr));
        const focusMin = parseInt(localStorage.getItem(`el-focus-mins-${todayStr}`) || '0', 10);
        setTodayActivity({ tasksDone: todayTasks.count || 0, routinesDone: completedRoutines.length, focusMin });
      }
    } catch (_) { /* activity stats are non-critical */ }

    try {
      const demo = journalDemo();
      if (demo) {
        // Demo: load from localStorage so demo users can still test journal
        const cached = localStorage.getItem('el-journal-v2-demo');
        setEntries(cached ? JSON.parse(cached) : {});
        setLoading(false);
        return;
      }

      const uid = await window.ensureCurrentUserId();
      if (!uid) { setEntries({}); setLoading(false); return; }

      // logbook_entries: heading + notes (text)
      const { data: logs } = await supabaseClient
        .from('logbook_entries')
        .select('entry_date, heading, notes')
        .eq('user_id', uid)
        .order('entry_date', { ascending: false })
        .limit(120);

      // mood_entries: 5-trinns mood
      const { data: moods } = await supabaseClient
        .from('mood_entries')
        .select('entry_date, mood')
        .eq('user_id', uid)
        .order('entry_date', { ascending: false })
        .limit(120);

      // logbook_tracker_entries: sleep, energy (filtered client-side by tracker name)
      const { data: trackers } = await supabaseClient
        .from('logbook_tracker_entries')
        .select('entry_date, tracker_name, value_number')
        .eq('user_id', uid)
        .in('tracker_name', ['sleep', 'energy'])
        .order('entry_date', { ascending: false })
        .limit(240);

      const map = {};
      (logs || []).forEach(r => {
        const k = r.entry_date;
        map[k] = { ...(map[k] || {}), text: r.notes || '', heading: r.heading || '' };
      });
      (moods || []).forEach(r => {
        const k = r.entry_date;
        // mood stored as text in v1; map to 0-4 index
        const moodMap = { 'very_sad': 0, 'sad': 1, 'neutral': 2, 'happy': 3, 'very_happy': 4 };
        const idx = typeof r.mood === 'number' ? r.mood : moodMap[String(r.mood)];
        if (idx != null) map[k] = { ...(map[k] || {}), mood: idx };
      });
      (trackers || []).forEach(r => {
        const k = r.entry_date;
        if (r.value_number == null) return;
        map[k] = { ...(map[k] || {}), [r.tracker_name]: r.value_number };
      });

      setEntries(map);
    } catch (e) {
      console.warn('[Journal] load failed', e);
      setEntries({});
    } finally {
      setLoading(false);
    }
  }

  const key = jToKey(selected);
  const entry = entries[key] || {};

  // Streak (sammenhengende dager bakover med innhold)
  const streak = useJMemo(() => {
    let n = 0;
    for (let i = 0; i < 90; i++) {
      const d = new Date(today);
      d.setDate(today.getDate() - i);
      if (entries[jToKey(d)]) n++;
      else break;
    }
    return n;
  }, [entries]);

  const wordCount = (entry.text || '').replace(/<[^>]*>/g, '').trim().split(/\s+/).filter(Boolean).length;

  // Debounced save for text + heading (autosave)
  const saveTimerRef = useJRef(null);
  function update(patch) {
    const next = { ...entries, [key]: { ...entry, ...patch } };
    setEntries(next);
    setSaved(false);

    // Persist
    if (journalDemo()) {
      localStorage.setItem('el-journal-v2-demo', JSON.stringify(next));
      return;
    }

    // Debounce text-saves; immediate for mood/sleep/energy
    if ('text' in patch || 'heading' in patch) {
      clearTimeout(saveTimerRef.current);
      saveTimerRef.current = setTimeout(() => persistEntry(next[key]), 800);
    } else {
      persistEntry(next[key]);
    }
  }

  async function persistEntry(e) {
    const uid = await window.ensureCurrentUserId();
    if (!uid) return;
    try {
      if ('text' in e || 'heading' in e) {
        await supabaseClient
          .from('logbook_entries')
          .upsert({
            user_id: uid,
            entry_date: key,
            heading: e.heading || null,
            notes: e.text || '',
          }, { onConflict: 'user_id,entry_date' });
      }
      if ('mood' in e && e.mood != null) {
        const moodNames = ['very_sad','sad','neutral','happy','very_happy'];
        await supabaseClient
          .from('mood_entries')
          .upsert({
            user_id: uid,
            entry_date: key,
            mood: moodNames[e.mood] || 'neutral',
          }, { onConflict: 'user_id,entry_date' });
      }
      if ('sleep' in e && e.sleep != null) {
        await supabaseClient
          .from('logbook_tracker_entries')
          .upsert({
            user_id: uid, entry_date: key,
            tracker_name: 'sleep', value_number: e.sleep,
          }, { onConflict: 'user_id,entry_date,tracker_name' });
      }
      if ('energy' in e && e.energy != null) {
        await supabaseClient
          .from('logbook_tracker_entries')
          .upsert({
            user_id: uid, entry_date: key,
            tracker_name: 'energy', value_number: e.energy,
          }, { onConflict: 'user_id,entry_date,tracker_name' });
      }
    } catch (err) {
      console.warn('[Journal] save failed', err);
    }
  }

  function handleSave() {
    setSaved(true);
    persistEntry(entry);
    setTimeout(() => setSaved(false), 2600);
  }

  async function handleDelete() {
    if (!confirm('Slette innlegget for ' + jFmtFull(selected) + '?')) return;
    const next = { ...entries };
    delete next[key];
    setEntries(next);
    if (journalDemo()) {
      localStorage.setItem('el-journal-v2-demo', JSON.stringify(next));
      return;
    }
    const uid = await window.ensureCurrentUserId();
    if (!uid) return;
    await supabaseClient.from('logbook_entries').delete().eq('user_id', uid).eq('entry_date', key);
    await supabaseClient.from('mood_entries').delete().eq('user_id', uid).eq('entry_date', key);
    await supabaseClient.from('logbook_tracker_entries').delete().eq('user_id', uid).eq('entry_date', key).in('tracker_name', ['sleep','energy']);
  }

  function fmt(cmd) {
    if (cmd === 'bold') document.execCommand('bold');
    if (cmd === 'italic') document.execCommand('italic');
    if (cmd === 'ul') document.execCommand('insertUnorderedList');
    if (cmd === 'hr') document.execCommand('insertHTML', false, '<hr style="border:none;border-top:1px solid var(--bdr);margin:10px 0">');
    if (cmd === 'quote') document.execCommand('insertHTML', false, '<blockquote style="border-left:2px solid var(--accent);margin:6px 0;padding-left:12px;color:var(--sec);font-style:italic">Sitat...</blockquote>');
  }

  if (loading) {
    return (
      <div className="v2-page" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 400 }}>
        <div style={{ color: 'var(--sec)' }}>Laster journal…</div>
      </div>
    );
  }

  // ─── MOBILE ───
  if (isMobile) {
    return (
      <div className="v2-page j-mobile">
        <div className="j-mobile-head">
          <div style={{ textAlign: 'center' }}>
            <p style={{ fontSize: 16, fontWeight: 800, color: 'var(--pri)', letterSpacing: '-0.3px', lineHeight: 1, margin: 0 }}>Journal</p>
            {streak > 0 && (
              <p style={{ fontSize: 11, color: 'var(--sec)', fontWeight: 500, marginTop: 2, marginBottom: 0 }}>
                <span style={{ color: 'var(--accent)', fontWeight: 700 }}>{streak}</span> dagers serie 🔥
              </p>
            )}
          </div>
          <button onClick={() => setShowHistory(true)} className="j-pill">
            <svg width="15" height="12" viewBox="0 0 15 12" fill="none">
              <rect y="0.5" width="9" height="2" rx="1" fill="currentColor"/>
              <rect y="5" width="15" height="2" rx="1" fill="currentColor"/>
              <rect y="9.5" width="12" height="2" rx="1" fill="currentColor"/>
            </svg>
          </button>
        </div>

        <JDateStrip selected={selected} onSelect={setSelected} entries={entries} />

        {/* Today's activity row */}
        <div style={{ display: 'flex', gap: 10, padding: '14px 20px 0', justifyContent: 'space-between' }}>
          {[
            { icon: 'ti-circle-check', label: 'Fullført', val: todayActivity.tasksDone },
            { icon: 'ti-rotate', label: 'Rutiner', val: todayActivity.routinesDone },
            { icon: 'ti-brain', label: 'Fokus', val: todayActivity.focusMin > 0 ? `${todayActivity.focusMin}m` : '0' },
          ].map(({ icon, label, val }) => (
            <div key={label} style={{ flex: 1, background: 'var(--bg-card)', borderRadius: 14, border: '1px solid var(--bdr)', padding: '10px 8px', textAlign: 'center' }}>
              <i className={`ti ${icon}`} style={{ fontSize: 16, display: 'block', marginBottom: 4, color: 'var(--accent)' }}></i>
              <div style={{ fontSize: 15, fontWeight: 800, color: 'var(--pri)', lineHeight: 1 }}>{val}</div>
              <div style={{ fontSize: 10, color: 'var(--sec)', marginTop: 2 }}>{label}</div>
            </div>
          ))}
        </div>

        <div style={{ padding: '0 20px', marginTop: 16 }}>
          <div style={{
            background: 'var(--bg-card)', borderRadius: 22,
            padding: '18px 18px 14px', border: '1px solid var(--bdr)',
            position: 'relative', overflow: 'hidden',
          }}>
            <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 16 }}>
              <p style={{ fontSize: 14, fontWeight: 700, color: 'var(--pri)', margin: 0 }}>{jFmtFull(selected)}</p>
              <span style={{ fontSize: 10, fontWeight: 600, color: wordCount > 0 ? 'var(--sec)' : 'var(--mut)', background: 'var(--surface-b)', borderRadius: 6, padding: '3px 7px' }}>{wordCount} ord</span>
            </div>
            <JEditor key={key} text={entry.text || ''} onChange={(t) => update({ text: t })} placeholder="Hva har du på hjertet?" />
            <div style={{ display: 'flex', gap: 5, marginTop: 12, paddingTop: 12, borderTop: '1px solid var(--bdr)' }}>
              {[{ lbl: 'B', cmd: 'bold', s: { fontWeight: 800 } }, { lbl: 'I', cmd: 'italic', s: { fontStyle: 'italic' } }, { lbl: '•', cmd: 'ul', s: { fontSize: 16 } }, { lbl: '—', cmd: 'hr', s: {} }, { lbl: '"', cmd: 'quote', s: { fontSize: 16 } }].map((b, i) => (
                <button key={i} onClick={() => fmt(b.cmd)} className="j-tb-btn" style={b.s}>{b.lbl}</button>
              ))}
            </div>
          </div>
        </div>

        <div style={{ padding: '16px 20px 0' }}>
          <p style={{ fontSize: 11, fontWeight: 700, color: 'var(--mut)', textTransform: 'uppercase', letterSpacing: '1.1px', marginBottom: 10 }}>Trackers</p>
          <div style={{ marginBottom: 12 }}>
            <p style={{ fontSize: 10, fontWeight: 700, color: 'var(--mut)', textTransform: 'uppercase', letterSpacing: '1px', marginBottom: 8 }}>Hvordan føler du deg?</p>
            <JMoodPicker value={entry.mood ?? null} onChange={(v) => update({ mood: v })} size={22} />
          </div>
          <div style={{ display: 'flex', gap: 10 }}>
            <JTrackerCard icon="🌙" label="Søvn" value={entry.sleep ?? null} onChange={(v) => update({ sleep: v })} />
            <JTrackerCard icon="⚡" label="Energi" value={entry.energy ?? null} onChange={(v) => update({ energy: v })} />
          </div>
        </div>

        <div style={{ padding: '20px', marginTop: 'auto', display: 'flex', gap: 8 }}>
          <button onClick={handleSave} style={{
            flex: 1, padding: '12px 16px', borderRadius: 12,
            border: saved ? '1px solid var(--accent-bd)' : 'none',
            background: saved ? 'var(--accent-d)' : 'var(--accent)',
            color: saved ? 'var(--accent)' : '#000',
            cursor: 'pointer', fontFamily: 'inherit', fontWeight: 700, fontSize: 13,
          }}>{saved ? '✓ Lagret' : 'Lagre'}</button>
          <button onClick={handleDelete} style={{
            padding: '12px 14px', borderRadius: 10, border: 'none',
            background: 'rgba(255,76,76,0.12)', color: '#ff4c4c',
            fontFamily: 'inherit', fontSize: 14, fontWeight: 600,
            cursor: 'pointer', minWidth: 40,
          }}>🗑</button>
        </div>

        <JHistorySheet
          isOpen={showHistory}
          onClose={() => setShowHistory(false)}
          entries={entries}
          onSelectDate={setSelected}
        />
      </div>
    );
  }

  // ─── DESKTOP ───
  const readTime = Math.max(1, Math.round(wordCount / 200));
  const sortedEntries = Object.entries(entries).sort(([a], [b]) => b.localeCompare(a)).slice(0, 14);

  return (
    <div className="v2-page j-desktop" style={{ display: 'flex', flexDirection: 'column', minHeight: 'calc(100vh - 120px)' }}>
      <div className="j-desk-head">
        <span style={{ fontSize: 15, fontWeight: 800, color: 'var(--pri)', letterSpacing: '-0.2px' }}>Journal</span>
        {streak > 0 && (
          <span style={{ fontSize: 11, fontWeight: 700, background: 'var(--accent-d)', border: '1px solid var(--accent-bd)', borderRadius: 999, padding: '3px 11px', color: 'var(--accent)' }}>
            {streak} dagers serie 🔥
          </span>
        )}
        <div style={{ flex: 1 }} />
        <span style={{ fontSize: 12, color: 'var(--sec)', fontWeight: 500 }}>{jFmtFull(selected)}</span>
        <div style={{ width: 1, height: 18, background: 'var(--bdr)' }} />
        <button onClick={handleDelete} className="j-desk-btn-icon" title="Slett">🗑</button>
        <button onClick={handleSave} className="j-desk-btn-save">
          {saved ? '✓ Lagret' : 'Lagre innlegg'}
        </button>
      </div>

      {/* Today's activity row — desktop */}
      <div style={{ display: 'flex', gap: 12, padding: '12px 0 0' }}>
        {[
          { icon: 'ti-circle-check', label: 'Oppgaver fullført', val: todayActivity.tasksDone },
          { icon: 'ti-rotate', label: 'Rutiner fullført', val: todayActivity.routinesDone },
          { icon: 'ti-brain', label: 'Fokustid', val: todayActivity.focusMin > 0 ? `${todayActivity.focusMin}m` : '0' },
        ].map(({ icon, label, val }) => (
          <div key={label} style={{ flex: 1, background: 'var(--surface)', border: '1px solid var(--surface-b)', borderRadius: 12, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10 }}>
            <i className={`ti ${icon}`} style={{ fontSize: 18, color: 'var(--accent)', flexShrink: 0 }}></i>
            <div>
              <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--pri)', lineHeight: 1 }}>{val}</div>
              <div style={{ fontSize: 10, color: 'var(--sec)', marginTop: 2 }}>{label}</div>
            </div>
          </div>
        ))}
      </div>

      <div className="j-desk-body">
        <aside className="j-desk-sidebar">
          <div style={{ padding: '16px 16px 14px', borderBottom: '1px solid var(--bdr)' }}>
            <JMiniCalendar
              selected={selected}
              onSelect={setSelected}
              entries={entries}
              currentMonth={currentMonth}
              onMonthChange={setCurrentMonth}
            />
          </div>
          <div style={{ flex: 1, overflowY: 'auto', padding: '12px 12px 20px' }}>
            <p style={{ fontSize: 9, fontWeight: 700, color: 'var(--mut)', textTransform: 'uppercase', letterSpacing: '1px', marginBottom: 8 }}>Tidligere innlegg</p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
              {sortedEntries.length === 0 && (
                <p style={{ fontSize: 11, color: 'var(--mut)', fontStyle: 'italic', textAlign: 'center', padding: '16px 0', margin: 0 }}>Ingen innlegg ennå</p>
              )}
              {sortedEntries.map(([k, v], i) => {
                const d = jFromKey(k);
                const isSel = k === key;
                const snippet = (v.text || '').replace(/<[^>]*>/g, '').trim().slice(0, 30);
                return (
                  <button
                    key={i}
                    onClick={() => setSelected(d)}
                    style={{
                      padding: '8px 10px', borderRadius: 10,
                      border: isSel ? '1px solid var(--accent-bd)' : '1px solid transparent',
                      background: isSel ? 'var(--accent-d)' : 'transparent',
                      cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit',
                      display: 'flex', flexDirection: 'column', gap: 3,
                    }}
                  >
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                      <span style={{ fontSize: 11, fontWeight: 700, color: isSel ? 'var(--accent)' : 'var(--pri)' }}>
                        {J_DAY_SHORT[d.getDay()]} {d.getDate()} {J_MONTH_SHORT[d.getMonth()]}
                      </span>
                      {v.mood != null && <span style={{ fontSize: 11 }}>{J_MOODS[v.mood]?.emoji}</span>}
                    </div>
                    {snippet && (
                      <span style={{ fontSize: 10, color: 'var(--sec)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{snippet}</span>
                    )}
                  </button>
                );
              })}
            </div>
          </div>
        </aside>

        <main className="j-desk-main">
          <div style={{ padding: '22px 40px 16px', borderBottom: '1px solid var(--bdr)' }}>
            <h1 style={{ fontSize: 26, fontWeight: 800, color: 'var(--pri)', letterSpacing: '-0.6px', margin: 0 }}>{jFmtFull(selected)}</h1>
            <p style={{ fontSize: 12, color: 'var(--mut)', marginTop: 5, fontWeight: 500, margin: '5px 0 0' }}>
              {wordCount > 0 ? `${wordCount} ord · ~${readTime} min lesetid` : 'Start å skrive…'}
            </p>
          </div>
          <div style={{ flex: 1, padding: '24px 40px 40px', overflowY: 'auto' }}>
            <JEditor
              key={key}
              text={entry.text || ''}
              onChange={(t) => update({ text: t })}
              placeholder="Hva tenker du på i dag?"
              minHeight={420}
            />
          </div>
          <div className="j-desk-toolbar">
            {[{ lbl: 'B', cmd: 'bold', s: { fontWeight: 800 } }, { lbl: 'I', cmd: 'italic', s: { fontStyle: 'italic' } }, { lbl: '•', cmd: 'ul', s: {} }, { lbl: '—', cmd: 'hr', s: {} }, { lbl: '"', cmd: 'quote', s: { fontSize: 15 } }].map((b, i) => (
              <button key={i} onClick={() => fmt(b.cmd)} className="j-tb-btn" style={b.s}>{b.lbl}</button>
            ))}
            <div style={{ width: 1, height: 18, background: 'var(--bdr)', margin: '0 8px' }} />
            <span style={{ fontSize: 11, color: 'var(--mut)', fontWeight: 500 }}>{wordCount} ord</span>
          </div>
        </main>

        <aside className="j-desk-rightpanel">
          <div style={{ padding: '16px 16px 14px', borderBottom: '1px solid var(--bdr)' }}>
            <p style={{ fontSize: 9, fontWeight: 700, color: 'var(--mut)', textTransform: 'uppercase', letterSpacing: '1px', marginBottom: 10 }}>Hvordan føler du deg?</p>
            <JMoodPicker value={entry.mood ?? null} onChange={(v) => update({ mood: v })} size={20} />
          </div>
          <div style={{ padding: '16px 16px 14px', borderBottom: '1px solid var(--bdr)' }}>
            <p style={{ fontSize: 9, fontWeight: 700, color: 'var(--mut)', textTransform: 'uppercase', letterSpacing: '1px', marginBottom: 14 }}>Trackers</p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
              <JTrackerCard icon="🌙" label="Søvn" value={entry.sleep ?? null} onChange={(v) => update({ sleep: v })} />
              <JTrackerCard icon="⚡" label="Energi" value={entry.energy ?? null} onChange={(v) => update({ energy: v })} />
            </div>
          </div>
          <div style={{ padding: '16px 16px 20px' }}>
            <div style={{ borderRadius: 12, border: '1px solid var(--bdr)', background: 'var(--accent-d)', padding: '12px 14px' }}>
              <p style={{ fontSize: 10, fontWeight: 700, color: 'var(--accent)', marginBottom: 6, margin: 0 }}>💡 Dagens spørsmål</p>
              <p style={{ fontSize: 11, color: 'var(--sec)', lineHeight: 1.6, margin: '6px 0 0' }}>Hva var én ting som gjorde at du stoppet opp i dag — og hvorfor?</p>
            </div>
          </div>
        </aside>
      </div>
    </div>
  );
}
