// Main app — route management, ambient sound, journal storage.

const { useState: useSA, useEffect: useEA, useRef: useRA } = React;

function App() {
  // routes: home | spreads | reading | library | journal | about
  const [route, setRoute] = useSA('home');
  const [activeSpread, setActiveSpread] = useSA(null);
  const [voice, setVoice] = useLocal('tarot.voice', VOICES[0]);
  const [soundOn, setSoundOn] = useLocal('tarot.sound', false);
  const [openEntry, setOpenEntry] = useSA(null);
  const [showSettings, setShowSettings] = useSA(false);

  // Journal + auth (cloud-aware, with localStorage fallback)
  const { journal, addReading, deleteReading, user, cloudReady } = useJournal();

  // Scroll top on route change
  useEA(() => {
    window.scrollTo({top: 0, behavior: 'smooth'});
  }, [route]);

  // Ambient audio
  const audioRef = useRA(null);
  useEA(() => {
    if (!audioRef.current) {
      // build a simple drone via WebAudio if available
    }
  }, []);

  useEA(() => {
    // simple drone with WebAudio when sound is on
    let ctx, oscs = [], gain;
    if (soundOn) {
      try {
        ctx = new (window.AudioContext || window.webkitAudioContext)();
        gain = ctx.createGain();
        gain.gain.value = 0.06;
        gain.connect(ctx.destination);
        const freqs = [110, 164.81, 220, 329.63]; // A2, E3, A3, E4 — drone fifths
        freqs.forEach((f, i) => {
          const o = ctx.createOscillator();
          o.type = i === 0 ? 'sine' : 'triangle';
          o.frequency.value = f;
          const g = ctx.createGain();
          g.gain.value = i === 0 ? 1 : 0.3;
          o.connect(g); g.connect(gain);
          // gentle LFO
          const lfo = ctx.createOscillator();
          const lfoG = ctx.createGain();
          lfo.frequency.value = 0.1 + i * 0.07;
          lfoG.gain.value = 0.5;
          lfo.connect(lfoG); lfoG.connect(o.frequency);
          o.start(); lfo.start();
          oscs.push(o, lfo);
        });
      } catch(e) {}
    }
    return () => {
      try { oscs.forEach(o => o.stop()); ctx && ctx.close(); } catch(e) {}
    };
  }, [soundOn]);

  const handleRoute = (r) => {
    setRoute(r);
    if (r === 'spreads') setActiveSpread(null);
  };

  const handleStartReading = (spread) => {
    setActiveSpread(spread);
    setRoute('reading');
  };

  const handleCompleteReading = (entry) => {
    if (entry) {
      addReading(entry);
    }
    setActiveSpread(null);
    setRoute(entry ? 'journal' : 'spreads');
  };

  return (
    <div className="app">
      <Nav route={route} onRoute={handleRoute} soundOn={soundOn} onSoundToggle={() => setSoundOn(!soundOn)}
           onOpenSettings={() => setShowSettings(true)}/>
      <main style={{flex:1}}>
        {route === 'home' &&    <LandingScreen onBegin={() => handleRoute('spreads')} onRoute={handleRoute}/>}
        {route === 'spreads' && <SpreadsScreen onChooseSpread={handleStartReading} voice={voice} onChooseVoice={setVoice}/>}
        {route === 'reading' && activeSpread &&
          <ReadingScreen spread={activeSpread} voice={voice}
                         onComplete={handleCompleteReading}
                         onCancel={() => setRoute('spreads')}/>}
        {route === 'library' && <LibraryScreen/>}
        {route === 'journal' && <JournalScreen journal={journal} onOpen={setOpenEntry} onRoute={handleRoute}
                                                onDelete={deleteReading}/>}
        {route === 'about' &&   <AboutScreen/>}
      </main>
      <Footer/>

      {openEntry && <JournalEntryModal entry={openEntry} onClose={() => setOpenEntry(null)}
                                       onDelete={(id) => { deleteReading(id); setOpenEntry(null); }}/>}
      <SettingsPanel open={showSettings} onClose={() => setShowSettings(false)} user={user}/>
    </div>
  );
}

// Journal entry detail
function JournalEntryModal({ entry, onClose, onDelete }) {
  const [playing, setPlaying] = useSA(false);
  const voice = VOICES.find(v => v.id === entry.voiceId);
  const close = () => { TTS.stopVoice(); setPlaying(false); onClose(); };
  useEA(() => {
    const h = (e) => { if (e.key === 'Escape') close(); };
    window.addEventListener('keydown', h);
    return () => { window.removeEventListener('keydown', h); TTS.stopVoice(); };
  }, []);
  const cardLookup = Object.fromEntries(TAROT_DECK.map(c => [c.id, c]));
  const drawCards = entry.draws.map(d => ({ ...cardLookup[d.cardId], reversed: d.reversed }));
  const spread = ALL_SPREADS.find(s => s.id === entry.spreadId) || ALL_SPREADS[0];
  const positions = spread.positions;
  const d = new Date(entry.timestamp);

  const handlePlay = async () => {
    if (playing) { TTS.stopVoice(); setPlaying(false); return; }
    if (!entry.synthesis) return;
    setPlaying(true);
    try {
      await TTS.speakVoice(entry.synthesis, voice);
    } catch (err) {
      console.warn('Voice playback failed:', err);
      alert('The reader could not speak: ' + err.message + '\n\nCheck your ElevenLabs API key in Voice Settings.');
    } finally {
      setPlaying(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={close}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{gridTemplateColumns:'1fr', maxWidth:'1100px'}}>
        <button className="modal-close" onClick={close}>×</button>
        <div style={{textAlign:'center'}}>
          <span className="eyebrow">{entry.spreadName}</span>
          <h2 style={{marginTop:'0.8rem', fontStyle:'italic', fontFamily:'var(--font-serif)', fontWeight:300, textTransform:'none', letterSpacing:'0.02em'}}>
            "{entry.question}"
          </h2>
          <p className="muted" style={{marginTop:'0.4rem', fontSize:'0.85rem'}}>
            {d.toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' })} · Read by {entry.voiceName}
          </p>
        </div>
        <Divider glyph="mark"/>
        <div className={`spread-${spread.layout}`}
             style={{margin:'1rem 0', ...(spread.layout === 'row' ? {'--cols': spread.count} : {})}}>
          {positions.map((pos, i) => (
            <div key={pos.id} className="slot">
              <div className="pos-num">· {String(i + 1).padStart(2, '0')} ·</div>
              <TarotCard card={drawCards[i]} flipped reversed={drawCards[i]?.reversed} size={spread.cardSize || ''}/>
              <div className="pos-name">{pos.name}</div>
            </div>
          ))}
        </div>
        <Divider glyph="sigil-mark"/>
        <div className="synth-block" style={{marginTop:'1rem'}}>
          <PanelCorners/>
          <span className="eyebrow">The Reading</span>
          <div className="synth-text" style={{marginTop:'1rem'}}>
            {(entry.synthesis || '').split(/\n\n+/).filter(Boolean).map((p, i) => <p key={i}>{p}</p>)}
          </div>
          {entry.synthesis && (
            <div className="audio-controls">
              <button className="play-pill" onClick={handlePlay}>
                <Sigil name={playing ? 'pause' : 'play'}/>
                {playing ? 'Stop' : 'Hear it again'}
              </button>
              <span className="muted" style={{fontSize:'0.85rem', fontStyle:'italic'}}>
                {playing ? `${entry.voiceName} is reading\u2026` :
                 TTS.hasElevenVoice(voice) ? `Voice: ${entry.voiceName}` :
                 voice?.voiceId ? `${entry.voiceName} \u00b7 add API key in Settings` :
                 `${entry.voiceName} \u00b7 browser voice`}
              </span>
            </div>
          )}
        </div>
        <div style={{display:'flex', gap:'1rem', justifyContent:'center', marginTop:'2rem'}}>
          <button className="btn ghost small" onClick={() => onDelete(entry.id)}>Discard Reading</button>
          <button className="btn primary small" onClick={close}>Close</button>
        </div>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);

// ────────────────────────────────────────────────────────────────
// useJournal — cloud-aware journal hook.
// Reads from Supabase when configured + signed in; otherwise localStorage.
// Writes go to both when possible (cloud + local cache).
// ────────────────────────────────────────────────────────────────
function useJournal() {
  const [local, setLocal] = useLocal('tarot.journal', []);
  const [cloud, setCloud] = useSA(null);
  const [user, setUser]   = useSA(null);
  const [cloudReady, setCloudReady] = useSA(false);
  const cloudEnabled = !!(window.Cloud && window.Cloud.enabled);

  // Auth subscription
  useEA(() => {
    if (!cloudEnabled) return;
    let cancelled = false;
    window.Cloud.getUser().then(u => { if (!cancelled) setUser(u); });
    const off = window.Cloud.onAuthChange(setUser);
    return () => { cancelled = true; off && off(); };
  }, []);

  // Fetch readings whenever the user changes
  useEA(() => {
    if (!cloudEnabled) return;
    if (!user) { setCloud(null); setCloudReady(false); return; }
    let cancelled = false;
    window.Cloud.fetchReadings().then(rows => {
      if (cancelled) return;
      setCloud(rows || []);
      setCloudReady(true);
    });
    return () => { cancelled = true; };
  }, [user]);

  const useCloud = cloudEnabled && !!user && cloudReady;
  const journal  = useCloud ? (cloud || []) : local;

  const addReading = async (entry) => {
    // Always cache to local so a sign-out doesn't lose recent entries
    setLocal(prev => [entry, ...prev]);
    if (useCloud) {
      const ok = await window.Cloud.saveReading(entry);
      if (ok) setCloud(prev => [entry, ...(prev || [])]);
    }
  };

  const deleteReading = async (id) => {
    setLocal(prev => prev.filter(e => e.id !== id));
    if (useCloud) {
      await window.Cloud.deleteReading(id);
      setCloud(prev => (prev || []).filter(e => e.id !== id));
    }
  };

  return { journal, addReading, deleteReading, user, cloudReady };
}
