/* global React */
// =========================================================================
// TRACKER — sleep dashboard, charts, debt, cycle prediction, dreams journal
// =========================================================================

const { useState: useTrState, useEffect: useTrEffect, useMemo: useTrMemo } = React;

const DAYS = ['MON','TUE','WED','THU','FRI','SAT','SUN'];
const SLEEP_STORAGE_KEY = 'somnia.sleepEntries.v1';
const DREAM_STORAGE_KEY = 'somnia.dreamEntries.v1';
const TARGET_HOURS = 8;
const RED_ALERT_AVG = 7;

// Fingerprint of the old demo week — used once to clear persisted sample data.
const LEGACY_SEED_HOURS = [6.2, 7.5, 5.8, 8.1, 6.7, 9.2, 7.1];
const LEGACY_SEED_DREAM_TEXTS = [
  'Library with shifting hallways. Realised I could read the books backwards and they made more sense.',
  'Stanford courtyard, but the fountain was full of glowing koi. They spelled out a math problem I could almost solve.',
  'The train scene again. Different conductor this time — kept asking what year it was.',
];

function pad2(n) {
  return n.toString().padStart(2, '0');
}

function toInputDate(d) {
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
}

function todayInput() {
  return toInputDate(new Date());
}

function dayLabel(date) {
  const d = new Date(`${date}T12:00:00`);
  if (Number.isNaN(d.getTime())) return 'DAY';
  return DAYS[(d.getDay() + 6) % 7];
}

function prettyDate(date) {
  const d = new Date(`${date}T12:00:00`);
  if (Number.isNaN(d.getTime())) return date || 'NO DATE';
  return d.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' }).toUpperCase();
}

function moodFromQuality(q) {
  return q >= 4 ? 'rested' : q >= 3 ? 'ok' : 'tired';
}

function isLegacySeedWeek(entries) {
  if (!Array.isArray(entries) || entries.length !== 7) return false;
  const hours = sortEntries(entries.map(normalizeEntry)).map(e => +(e.hours.toFixed(1)));
  return LEGACY_SEED_HOURS.every((h, i) => hours[i] === h);
}

function isLegacySeedDreams(dreams) {
  if (!Array.isArray(dreams) || dreams.length !== 3) return false;
  const texts = dreams.map(d => d.text);
  return LEGACY_SEED_DREAM_TEXTS.every((t, i) => texts[i] === t);
}

function sortEntries(entries) {
  return entries.slice().sort((a, b) => `${a.date || ''}${a.bedtime || ''}`.localeCompare(`${b.date || ''}${b.bedtime || ''}`));
}

function normalizeEntry(entry, i = 0) {
  const fallbackDate = (() => {
    const d = new Date();
    d.setDate(d.getDate() - i);
    return toInputDate(d);
  })();
  const date = entry.date || fallbackDate;
  const quality = Number(entry.quality || 3);
  const hours = Number(entry.hours || 0);
  return {
    date,
    day: dayLabel(date),
    hours,
    quality,
    mood: entry.mood || moodFromQuality(quality),
    bedtime: entry.bedtime || '23:30',
    wake: entry.wake || entry.waketime || '07:00',
    notes: entry.notes || '',
  };
}

function readJson(key) {
  try {
    const raw = localStorage.getItem(key);
    return raw ? JSON.parse(raw) : null;
  } catch (e) {
    return null;
  }
}

function writeJson(key, value) {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch (e) {}
}

function loadSleepEntries() {
  const stored = readJson(SLEEP_STORAGE_KEY);
  if (!Array.isArray(stored)) return [];
  if (isLegacySeedWeek(stored)) {
    writeJson(SLEEP_STORAGE_KEY, []);
    return [];
  }
  return sortEntries(stored.map(normalizeEntry));
}

function loadDreamEntries() {
  const stored = readJson(DREAM_STORAGE_KEY);
  if (!Array.isArray(stored)) return [];
  if (isLegacySeedDreams(stored)) {
    writeJson(DREAM_STORAGE_KEY, []);
    return [];
  }
  return stored;
}

function buildSleepSummary(entries, dreamCount = 0) {
  const sorted = sortEntries(entries.map(normalizeEntry));
  const latestSeven = sorted.slice(-7);
  const latestThree = sorted.slice(-3);
  const totalSlept = latestSeven.reduce((s, d) => s + d.hours, 0);
  const avg = latestSeven.length ? totalSlept / latestSeven.length : 0;
  const debt = Math.max(0, TARGET_HOURS * latestSeven.length - totalSlept);
  const rollingAvg3 = latestThree.length === 3
    ? latestThree.reduce((s, d) => s + d.hours, 0) / 3
    : null;

  return {
    entriesCount: sorted.length,
    latestEntriesCount: latestThree.length,
    rollingAvg3,
    isRedAlert: rollingAvg3 !== null && rollingAvg3 < RED_ALERT_AVG,
    weeklyAvg: avg,
    sleepDebt: debt,
    dreamCount,
  };
}

function publishSleepSummary(entries, dreams = []) {
  const detail = buildSleepSummary(entries, dreams.length);
  window.__somnia_sleep_summary = detail;
  window.dispatchEvent(new CustomEvent('somnia:sleep-summary', { detail }));
}

function getSomniaSleepSummary() {
  return buildSleepSummary(loadSleepEntries(), loadDreamEntries().length);
}

function TrackerWindow({ awakeHours, drowsyThreshold }) {
  const [tab, setTab] = useTrState('overview');
  const [entryDate, setEntryDate] = useTrState(todayInput());
  const [bedtime, setBedtime] = useTrState('23:30');
  const [waketime, setWaketime] = useTrState('07:00');
  const [quality, setQuality] = useTrState(4);
  const [notes, setNotes] = useTrState('');
  const [dreams, setDreams] = useTrState(loadDreamEntries);
  const [newDream, setNewDream] = useTrState('');
  const [week, setWeek] = useTrState(loadSleepEntries);

  const targetHours = TARGET_HOURS;
  const latestSeven = useTrMemo(() => sortEntries(week).slice(-7), [week]);
  const latestThree = useTrMemo(() => sortEntries(week).slice(-3), [week]);
  const totalSlept = useTrMemo(() => latestSeven.reduce((s, d) => s + d.hours, 0), [latestSeven]);
  const totalTarget = targetHours * latestSeven.length;
  const debt = Math.max(0, totalTarget - totalSlept);
  const avg = latestSeven.length ? totalSlept / latestSeven.length : 0;
  const rollingAvg3 = latestThree.length === 3
    ? latestThree.reduce((s, d) => s + d.hours, 0) / 3
    : null;
  const redAlert = rollingAvg3 !== null && rollingAvg3 < RED_ALERT_AVG;
  const bestNight = latestSeven.reduce((best, d) => !best || d.hours > best.hours ? d : best, null);
  const worstNight = latestSeven.reduce((worst, d) => !worst || d.hours < worst.hours ? d : worst, null);
  const hasEntries = week.length > 0;
  const recommendation = (() => {
    if (!hasEntries) return 'Log your first night on the Log tab to start tracking sleep debt and trends.';
    if (redAlert) return `You averaged ${rollingAvg3.toFixed(1)} hrs over your last 3 nights — try shifting bedtime 45 min earlier tonight.`;
    if (debt > 8) return 'Heavy sleep debt is building. Protect one full 8-hour opportunity before adding extra work or late caffeine.';
    if (latestSeven.filter(d => d.hours >= RED_ALERT_AVG).length >= 5) return 'Great week! You hit at least 7 hours on 5+ recent nights.';
    if (avg > 0 && avg < targetHours) return `Mild deficit — your recent average is ${(targetHours - avg).toFixed(1)}h short of the 8h target.`;
    return 'On target. Keep the same wake time to anchor the rhythm.';
  })();

  useTrEffect(() => {
    writeJson(SLEEP_STORAGE_KEY, week);
    publishSleepSummary(week, dreams);
  }, [week, dreams.length]);

  useTrEffect(() => {
    writeJson(DREAM_STORAGE_KEY, dreams);
  }, [dreams]);

  // cycle prediction: 5 cycles of 90 min from bedtime
  const cycles = useTrMemo(() => {
    const [h, m] = bedtime.split(':').map(Number);
    const start = h * 60 + m + 15; // ~15 min to fall asleep
    return [3, 4, 5, 6].map(n => {
      const t = (start + n * 90) % (24 * 60);
      const hh = Math.floor(t / 60).toString().padStart(2,'0');
      const mm = (t % 60).toString().padStart(2,'0');
      return { n, time: `${hh}:${mm}` };
    });
  }, [bedtime]);

  const log = () => {
    const [bh, bm] = bedtime.split(':').map(Number);
    const [wh, wm] = waketime.split(':').map(Number);
    let mins = (wh * 60 + wm) - (bh * 60 + bm);
    if (mins < 0) mins += 24 * 60;
    const hours = +(mins / 60).toFixed(1);
    const moodLabel = quality >= 4 ? 'rested' : quality >= 3 ? 'ok' : 'tired';
    setWeek(w => {
      const next = sortEntries([...w]);
      const idx = next.findIndex(d => d.date === entryDate);
      const entry = {
        date: entryDate,
        day: dayLabel(entryDate),
        hours,
        quality,
        mood: moodLabel,
        bedtime,
        wake: waketime,
        notes: notes.trim(),
      };
      if (idx >= 0) next[idx] = entry; else next.push(entry);
      return sortEntries(next);
    });
    setNotes('');
  };

  const addDream = () => {
    if (!newDream.trim()) return;
    const now = new Date();
    const day = DAYS[(now.getDay() + 6) % 7];
    const hh = now.getHours().toString().padStart(2,'0');
    const mm = now.getMinutes().toString().padStart(2,'0');
    setDreams(d => [{ date: `${day} ${hh}:${mm}`, tag: 'logged', text: newDream.trim() }, ...d]);
    setNewDream('');
  };

  return (
    <div className="window-inner">
      <h1>SLEEP TRACKER</h1>
      <p className="muted" style={{margin: '8px 0 16px'}}>
        Stanford Sleep & Dreams • personal dashboard. Target: <span className="accent-moon">{targetHours}h / night</span>
      </p>

      <div className="tabs">
        {['overview', 'log', 'cycles', 'dreams'].map(t => (
          <button key={t} className={`tab ${tab === t ? 'active' : ''}`} onClick={() => setTab(t)}>
            {t.toUpperCase()}
          </button>
        ))}
      </div>

      {tab === 'overview' && (
        <div>
          <div className="stats">
            <div className="stat">
              <div className="stat-label">RECENT AVG</div>
              <div className="stat-value">{latestSeven.length ? `${avg.toFixed(1)}h` : '--'}</div>
              <div className="stat-sub">{latestSeven.length} night{latestSeven.length === 1 ? '' : 's'} logged</div>
            </div>
            <div className="stat">
              <div className="stat-label">SLEEP DEBT</div>
              <div className="stat-value" style={{color: debt > 5 ? 'var(--danger)' : 'var(--moon)'}}>{latestSeven.length ? `${debt.toFixed(1)}h` : '--'}</div>
              <div className="stat-sub">vs. {latestSeven.length ? `${totalTarget}h` : '—'} target</div>
            </div>
            <div className="stat">
              <div className="stat-label">3-DAY AVG</div>
              <div className="stat-value" style={{color: redAlert ? 'var(--danger)' : 'var(--moon)'}}>
                {rollingAvg3 === null ? '--' : `${rollingAvg3.toFixed(1)}h`}
              </div>
              <div className="stat-sub">red alert below {RED_ALERT_AVG}h</div>
            </div>
            <div className="stat">
              <div className="stat-label">DREAMS LOGGED</div>
              <div className="stat-value">{dreams.length}</div>
              <div className="stat-sub">this month</div>
            </div>
          </div>

          <div className="pixel-divider" />

          {redAlert && (
            <div className="pixel-card tracker-red-alert">
              <h4>DROWSINESS IS RED ALERT!</h4>
              <p style={{fontSize: 18, marginTop: 6}}>
                Your recent average is below 7 hours. Impaired alertness is a serious safety risk — please protect sleep tonight.
              </p>
            </div>
          )}

          <h3 style={{marginBottom: 12}}>HOURS / NIGHT</h3>
          {latestSeven.length === 0 ? (
            <p className="muted" style={{fontSize: 18}}>No nights logged yet. Open the Log tab and save your first entry.</p>
          ) : (
            <PixelBlockChart entries={latestSeven} />
          )}

          <div style={{marginTop: 18}} className="pixel-card">
            <h4 style={{marginBottom: 8}}>WEEKLY READOUT</h4>
            <p style={{fontSize: 18}}>
              {!hasEntries && 'No data yet — your weekly readout will appear after you log sleep.'}
              {hasEntries && debt > 8 && <span className="accent-rose">⚠ Heavy sleep debt. </span>}
              {hasEntries && debt > 0 && debt <= 8 && <span className="accent-moon">Mild deficit — </span>}
              {hasEntries && debt === 0 && <span className="accent-cyan">On target. </span>}
              {hasEntries && <>You averaged <span className="accent-moon">{avg.toFixed(1)}h</span> per night.</>}
              {hasEntries && bestNight && worstNight && <> Best night: <span className="accent-cyan">{prettyDate(bestNight.date)} ({bestNight.hours}h)</span>. Worst: <span className="accent-rose">{prettyDate(worstNight.date)} ({worstNight.hours}h)</span>.</>}
            </p>
            <p style={{fontSize: 18, marginTop: 10}}>
              <span className={redAlert ? 'accent-rose' : 'accent-cyan'}>RECOMMENDATION: </span>{recommendation}
            </p>
          </div>
        </div>
      )}

      {tab === 'log' && (
        <div>
          <h3 style={{marginBottom: 12}}>LOG TONIGHT</h3>
          <div className="pixel-card">
            <div style={{marginBottom: 12}}>
              <div className="stat-label" style={{marginBottom: 6}}>DATE</div>
              <input className="pinput" type="date" value={entryDate} onChange={e => setEntryDate(e.target.value)} />
            </div>
            <div className="row" style={{marginBottom: 12, gap: 16}}>
              <div className="grow">
                <div className="stat-label" style={{marginBottom: 6}}>BEDTIME</div>
                <input className="pinput" type="time" value={bedtime} onChange={e => setBedtime(e.target.value)} />
              </div>
              <div className="grow">
                <div className="stat-label" style={{marginBottom: 6}}>WAKE</div>
                <input className="pinput" type="time" value={waketime} onChange={e => setWaketime(e.target.value)} />
              </div>
            </div>
            <div style={{marginBottom: 12}}>
              <div className="stat-label" style={{marginBottom: 6}}>QUALITY</div>
              <div style={{display: 'flex', gap: 6}}>
                {[1,2,3,4,5].map(n => (
                  <button key={n}
                    onClick={() => setQuality(n)}
                    className={`pbtn ${quality === n ? 'primary' : 'ghost'}`}
                    style={{flex: 1, padding: '12px 0'}}>
                    {'★'.repeat(n)}
                  </button>
                ))}
              </div>
            </div>
            <div style={{marginBottom: 12}}>
              <div className="stat-label" style={{marginBottom: 6}}>NOTES OPTIONAL</div>
              <textarea
                className="ptextarea"
                placeholder="Caffeine? Stress? Dream fragments?"
                value={notes}
                onChange={e => setNotes(e.target.value)}
                rows={2}
                style={{resize: 'vertical'}}
              />
            </div>
            <button className="pbtn primary" onClick={log} style={{width: '100%'}}>SAVE ENTRY</button>
          </div>

          <h3 style={{margin: '20px 0 12px'}}>RECENT NIGHTS</h3>
          {week.length === 0 && (
            <p className="muted" style={{fontSize: 18}}>No entries yet. Save a night above to build your history.</p>
          )}
          {week.slice().reverse().map((d, i) => (
            <div key={`${d.date}-${i}`} className="pixel-card" style={{display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginBottom: 8, padding: '10px 14px'}}>
              <div>
                <div style={{fontFamily: 'var(--font-pixel)', fontSize: 10, color: 'var(--moon)'}}>{prettyDate(d.date)}</div>
                <div className="muted" style={{fontSize: 16}}>{d.bedtime} → {d.wake} • {d.mood}</div>
                {d.notes && <div className="muted" style={{fontSize: 15, marginTop: 3, maxWidth: 420}}>{d.notes}</div>}
              </div>
              <div style={{textAlign: 'right'}}>
                <div style={{fontFamily: 'var(--font-pixel)', fontSize: 14, color: 'var(--ink)'}}>{d.hours}h</div>
                <div style={{color: 'var(--rose)', fontSize: 14}}>{'★'.repeat(d.quality)}</div>
              </div>
            </div>
          ))}
        </div>
      )}

      {tab === 'cycles' && (
        <div>
          <h3 style={{marginBottom: 8}}>CYCLE PREDICTION</h3>
          <p className="muted" style={{marginBottom: 14, fontSize: 18}}>
            One sleep cycle ≈ 90 min. Waking at the end of a cycle (light NREM-1) feels easier than mid-deep sleep. Plan your wake at one of the slots below.
          </p>

          <div className="pixel-card">
            <div className="stat-label" style={{marginBottom: 6}}>IF YOU FALL ASLEEP AT</div>
            <input className="pinput" type="time" value={bedtime} onChange={e => setBedtime(e.target.value)} style={{maxWidth: 200}} />

            <div style={{marginTop: 16}}>
              <div className="stat-label" style={{marginBottom: 8}}>SUGGESTED WAKE TIMES</div>
              <div className="cycle-slots" style={{display: 'grid', gridTemplateColumns: 'repeat(2,1fr)', gap: 8}}>
                {cycles.map(c => (
                  <div key={c.n} className="pixel-card" style={{margin: 0, textAlign: 'center', padding: '12px'}}>
                    <div style={{fontFamily: 'var(--font-pixel)', fontSize: 9, color: c.n === 5 ? 'var(--moon)' : 'var(--ink-dim)'}}>
                      {c.n} CYCLES {c.n === 5 ? '★ IDEAL' : ''}
                    </div>
                    <div style={{fontFamily: 'var(--font-pixel)', fontSize: 22, color: 'var(--ink)', marginTop: 8, textShadow: '2px 2px 0 var(--bg-0)'}}>
                      {c.time}
                    </div>
                    <div className="muted" style={{fontSize: 14, marginTop: 4}}>{(c.n * 1.5).toFixed(1)}h sleep</div>
                  </div>
                ))}
              </div>
            </div>
          </div>

          <div className="pixel-divider" />

          <h3 style={{marginBottom: 8}}>LAST NIGHT — HYPNOGRAM</h3>
          <Hypnogram />
        </div>
      )}

      {tab === 'dreams' && (
        <div>
          <h3 style={{marginBottom: 8}}>DREAM JOURNAL</h3>
          <p className="muted" style={{marginBottom: 14, fontSize: 18}}>
            Recall fades within ~10 minutes of waking. Jot a single image or feeling — that fragment unlocks the rest later.
          </p>

          <div className="pixel-card">
            <textarea
              className="ptextarea"
              placeholder="What did you dream about?"
              value={newDream}
              onChange={e => setNewDream(e.target.value)}
              rows={3}
              style={{resize: 'vertical'}}
            />
            <button className="pbtn primary" onClick={addDream} style={{marginTop: 10}}>+ ADD ENTRY</button>
          </div>

          <div style={{marginTop: 16}}>
            {dreams.length === 0 && (
              <p className="muted" style={{fontSize: 18}}>No dreams logged yet. Add your first entry above.</p>
            )}
            {dreams.map((d, i) => (
              <div key={i} className="dream-entry">
                <div className="dream-date">
                  {d.date} <span className={`tag ${d.tag === 'lucid' ? 'cyan' : d.tag === 'recurring' ? 'rose' : d.tag === 'vivid' ? 'moon' : ''}`} style={{marginLeft: 6}}>{d.tag.toUpperCase()}</span>
                </div>
                <div className="dream-text">"{d.text}"</div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

function PixelBlockChart({ entries }) {
  return (
    <div>
      <div className="pixel-block-chart">
        {entries.map((d, i) => {
          const tone = d.hours < 6 ? 'bad' : d.hours < 7 ? 'warn' : 'good';
          const blocks = Math.max(1, Math.round(d.hours * 2));
          return (
            <div key={`${d.date}-${i}`} className="pixel-block-column">
              <div className="pixel-block-stack" title={`${prettyDate(d.date)} · ${d.hours}h`}>
                {Array.from({length: blocks}).map((_, block) => (
                  <span key={block} className={`sleep-block ${tone}`} />
                ))}
              </div>
              <div className="pixel-block-hours">{d.hours}h</div>
            </div>
          );
        })}
      </div>
      <div className="chart-axis">
        {entries.map((d, i) => <span key={`${d.date}-axis-${i}`}>{d.day}</span>)}
      </div>
    </div>
  );
}

// Hypnogram - a typical night's sleep stage progression
function Hypnogram() {
  // y axis: 0=Awake, 1=REM, 2=N1, 3=N2, 4=N3 (deep)
  // typical: deep early, REM later & longer
  const stages = [0, 2, 3, 4, 4, 3, 2, 1, 2, 3, 4, 3, 2, 1, 2, 1, 2, 1, 1, 0];
  const labels = ['AWAKE', 'REM', 'N1', 'N2', 'N3'];
  const w = 480, h = 180, pad = 50;
  const stepX = (w - pad - 10) / (stages.length - 1);
  const rowH = (h - 40) / 4;

  const points = stages.map((s, i) => [pad + i * stepX, 10 + s * rowH]);
  const pathD = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p[0]} ${p[1]}`).join(' ');

  return (
    <div className="cycle-diagram" style={{height: 'auto', overflow: 'auto'}}>
      <svg viewBox={`0 0 ${w} ${h}`} width="100%" shapeRendering="crispEdges" style={{maxWidth: 600}}>
        {/* grid rows */}
        {labels.map((lbl, i) => (
          <g key={lbl}>
            <rect x={pad} y={10 + i * rowH} width={w - pad - 10} height="1" fill="#4b3f8a" opacity="0.4" />
            <text x={pad - 6} y={14 + i * rowH} textAnchor="end" fontFamily="VT323" fontSize="14" fill={i === 1 ? '#ff8fb8' : i === 4 ? '#7de2d1' : '#b8a8e0'}>{lbl}</text>
          </g>
        ))}
        {/* x ticks */}
        {[0, 90, 180, 270, 360, 450].map((m, i) => (
          <text key={m} x={pad + (m / 480) * (w - pad - 10)} y={h - 8} textAnchor="middle" fontFamily="VT323" fontSize="14" fill="#b8a8e0">
            {m === 0 ? '23:30' : `+${Math.floor(m/60)}h${m%60 ? (m%60) : ''}`}
          </text>
        ))}
        {/* stage line */}
        <path d={pathD} fill="none" stroke="#ffe8a3" strokeWidth="2" />
        {/* REM markers */}
        {points.map((p, i) => stages[i] === 1 && (
          <rect key={`r${i}`} x={p[0] - 1.5} y={p[1] - 1.5} width="3" height="3" fill="#ff8fb8" />
        ))}
        {/* deep markers */}
        {points.map((p, i) => stages[i] === 4 && (
          <rect key={`d${i}`} x={p[0] - 1.5} y={p[1] - 1.5} width="3" height="3" fill="#7de2d1" />
        ))}
      </svg>
      <div className="muted" style={{fontSize: 14, marginTop: 8, fontFamily: 'var(--font-mono)'}}>
        Deep sleep <span className="accent-cyan">■</span> dominates the first half. REM <span className="accent-rose">■</span> lengthens through the night — most vivid dreams happen in the final 2 hours.
      </div>
    </div>
  );
}

Object.assign(window, { TrackerWindow, Hypnogram, getSomniaSleepSummary });
