// Card of the Day — one card, held for the calendar day.
// Shows what the card is, where it came from, and how to carry it.

const { useState: useST, useEffect: useET, useMemo: useMT } = React;

// ────────────────────────────────────────────────────────────────
// Static practice — used when no completion route is reachable.
// Composed from the card's own meaning so it never reads as boilerplate.
// ────────────────────────────────────────────────────────────────
const SUIT_PRACTICE = {
  wands:     'Watch where your energy actually goes today, as opposed to where you intend it to go.',
  cups:      'Notice what you feel before you decide what to do about it.',
  swords:    'Notice the moment you are about to be right at someone. That is the moment this card is about.',
  pentacles: 'Attend to something material today — a body, a bill, a repair. The slow work counts as work.',
  major:     'This card asks for the whole of your attention, not a corner of it.',
};

function fallbackPractice(card, reversed) {
  const meaning = (reversed ? card.reversed : card.upright).replace(/\.$/, '').toLowerCase();
  const lead = meaning.split(',')[0].trim();
  const stem = SUIT_PRACTICE[card.suitKey === 'major' ? 'major' : card.suitKey];
  const turn = reversed
    ? `Reversed, it arrives as a question rather than an answer: where is ${lead} asking for your attention today?`
    : `Upright, it names the qualities to keep near you: ${meaning}.`;
  return [
    `${card.name} is your card today. ${turn}`,
    stem,
    'Return to this page tonight and ask what it was actually about. The card is a lens, not an instruction — the day supplies the meaning.',
  ].join('\n\n');
}

// ────────────────────────────────────────────────────────────────
// Prompt for the hosted completion, in the deck's established voice.
// ────────────────────────────────────────────────────────────────
function buildPracticePrompt(card, reversed, voice) {
  const orientation = reversed ? 'reversed' : 'upright';
  return `You are ${voice?.name || 'a tarot reader'}, ${voice?.epithet || 'a reader of the cards'}.
${voice?.promptTone || ''}

This is the Veiled Tarot — a deck drawn in the visual key of the Black diaspora's futures and pasts at once:
obsidian skin and gold filigree, cities raised on starlight, ankhs that double as circuit-glyphs, crowns cut
from a metal older than empire. The figures are kin — ancestors, sovereigns, navigators, builders. Let that
world be the air the reader breathes: ancestral memory as a kind of technology, time as a spiral rather than
a line, the questioner as a builder of worlds and never a supplicant. Never name any of this, and never use
the word "Afrofuturist" or any variant. Do not perform an accent or dialect.

Today's single card is ${card.name}, drawn ${orientation}.
Its ${orientation} meaning: ${reversed ? card.reversed : card.upright}
The card in brief: ${card.long}

Write the reader a short practice for carrying this card through one ordinary day. Three short paragraphs:

1. What this card is asking of them today, in plain terms.
2. One concrete thing to actually watch for — a situation, a reaction, a moment likely to occur in a normal
   day at work or at home. Be specific enough to be recognisable.
3. A single closing line to hold onto.

Speak directly to them as "you". Stay in character. No markdown, no headings, no lists, no preamble — begin
with the practice itself. Do not restate the card's name in the first sentence.`;
}

// ────────────────────────────────────────────────────────────────
// Screen
// ────────────────────────────────────────────────────────────────
// The day's practice is cached per date + reader, so returning to the page
// during the day shows the same words and costs nothing to display again.
function practiceCacheKey(key, card, reversed, voice) {
  return `tarot.today.${key}.${card.id}.${reversed ? 'r' : 'u'}.${voice?.id || 'none'}`;
}
function readCachedPractice(k) {
  try { return localStorage.getItem(k) || null; } catch { return null; }
}
function writeCachedPractice(k, text) {
  try {
    // Drop yesterday's entries so this can't grow without bound.
    for (let i = localStorage.length - 1; i >= 0; i--) {
      const key = localStorage.key(i);
      if (key && key.startsWith('tarot.today.') && key !== k) localStorage.removeItem(key);
    }
    localStorage.setItem(k, text);
  } catch {}
}

function TodayScreen({ voice, onRoute }) {
  const [now, setNow] = useST(() => new Date());
  const { card, reversed } = useMT(() => dailyDraw(now), [dayKey(now)]);

  const [revealed, setRevealed] = useST(false);
  const [practice, setPractice] = useST(null);
  const [loading, setLoading]   = useST(false);

  const history = useMT(() => cardHistory(card), [card && card.id]);
  const meaning = reversed ? card.reversed : card.upright;

  // Roll over to the new card at midnight without a manual refresh.
  useET(() => {
    const t = setTimeout(() => setNow(new Date()), msUntilTomorrow(now) + 1000);
    return () => clearTimeout(t);
  }, [dayKey(now)]);

  // A new day means a new card — clear what belonged to the old one.
  useET(() => {
    setRevealed(false);
    setPractice(null);
    setLoading(false);
  }, [card && card.id, reversed]);

  // Fetch the practice once the card is turned over.
  useET(() => {
    if (!revealed || practice || loading) return;

    const cacheKey = practiceCacheKey(dayKey(now), card, reversed, voice);
    const cached = readCachedPractice(cacheKey);
    if (cached) { setPractice(cached); return; }

    setLoading(true);

    const prompt = buildPracticePrompt(card, reversed, voice);
    const onResolve = (text) => {
      const t = (text || '').trim();
      if (t) writeCachedPractice(cacheKey, t);   // only cache a real generation
      setPractice(t || fallbackPractice(card, reversed));
      setLoading(false);
    };
    const onFallback = () => {
      setPractice(fallbackPractice(card, reversed));
      setLoading(false);
    };

    if (typeof window.claude?.complete === 'function') {
      window.claude.complete(prompt).then(onResolve).catch(onFallback);
    } else if (window.VEILED_CONFIG?.ttsProxyUrl) {
      fetch(window.VEILED_CONFIG.ttsProxyUrl + '/complete', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ prompt }),
      })
        .then(r => r.ok ? r.json() : Promise.reject(new Error('proxy ' + r.status)))
        .then(d => onResolve(d.text || ''))
        .catch(onFallback);
    } else {
      onFallback();
    }
  }, [revealed]);

  const dateLabel = now.toLocaleDateString(undefined,
    { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });

  return (
    <div className="container">
      <div className="center">
        <span className="eyebrow">Card of the Day</span>
        <h1 style={{marginTop:'1rem'}}>{dateLabel}</h1>
        <p className="muted" style={{marginTop:'0.6rem', fontStyle:'italic'}}>
          One card, drawn for today alone. It holds until midnight.
        </p>
      </div>

      <Divider glyph="mark"/>

      <div className="today-stage">
        <div className={`today-card ${revealed ? 'revealed' : ''}`}>
          <TarotCard card={card} flipped={revealed} reversed={reversed} size="lg"
                     interactive={!revealed}
                     onClick={() => !revealed && setRevealed(true)}/>
        </div>

        {!revealed && (
          <button className="btn primary" style={{marginTop:'2rem'}} onClick={() => setRevealed(true)}>
            Turn the Card <Sigil name="chevron-right"/>
          </button>
        )}
      </div>

      {revealed && (
        <div className="today-body">
          <div className="center">
            <span className="eyebrow">{card.suitKey === 'major' ? 'Major Arcana' : card.suit}</span>
            <h2 style={{marginTop:'0.6rem'}}>{card.name}</h2>
            {reversed && <p className="today-turn">Reversed</p>}
            <p className="today-meaning">{meaning}</p>
            <p style={{fontStyle:'italic', color:'var(--ash)', marginTop:'1.2rem'}}>{card.long}</p>
          </div>

          <Divider glyph="mark"/>

          <div className="panel">
            <PanelCorners/>
            <span className="eyebrow">The Card and Its History</span>
            {history.map((h, i) => (
              <div key={i} style={{marginTop: i === 0 ? '1.2rem' : '1.5rem'}}>
                <h4>{h.heading}</h4>
                <p style={{marginTop:'0.4rem'}}>{h.body}</p>
              </div>
            ))}
          </div>

          <div className="panel" style={{marginTop:'2rem'}}>
            <PanelCorners/>
            <span className="eyebrow">Carrying It Through the Day</span>
            {loading ? (
              <div className="center muted" style={{padding:'2rem 0', fontStyle:'italic'}}>
                <Sigil name="sigil-mark" className="back-sigil"
                       style={{width:48, height:48, color:'var(--gold)', opacity:0.6, animation:'spin 4s linear infinite'}}/>
                <p style={{marginTop:'1rem'}}>{voice?.name || 'The reader'} is considering the day…</p>
              </div>
            ) : (
              <div className="synth-text" style={{marginTop:'1.2rem'}}>
                {(practice || '').split(/\n\n+/).filter(Boolean).map((p, i) => <p key={i}>{p}</p>)}
              </div>
            )}
          </div>

          <div className="center" style={{display:'flex', gap:'1rem', justifyContent:'center',
                                          flexWrap:'wrap', marginTop:'2.5rem'}}>
            <button className="btn primary" onClick={() => onRoute('spreads')}>
              Begin a Full Reading <Sigil name="chevron-right"/>
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { TodayScreen, fallbackPractice, buildPracticePrompt, practiceCacheKey });
