/* global React, Icon, IconBtn, db */
/* Flashcard study session.
 * Loads due cards (+ optional new-card overflow up to the session-length tweak),
 * shuffles them, shows a prompt → reveal → rate flow, and writes FSRS updates
 * to the DB after each rating.
 */
const { useState, useEffect, useMemo, useCallback, useRef } = React;

const KEY_BINDINGS = {
  '1-4':  { again: ['1'], hard: ['2'], good: ['3'], easy: ['4'], reveal: [' ', 'Enter'] },
  'asdf': { again: ['a', 'A'], hard: ['s', 'S'], good: ['d', 'D'], easy: ['f', 'F'], reveal: [' ', 'Enter'] },
  'hjkl': { again: ['h', 'H'], hard: ['j', 'J'], good: ['k', 'K'], easy: ['l', 'L'], reveal: [' ', 'Enter'] },
};

const RATINGS = [
  { id: 1, key: 'again', label: 'Again', cls: 'r-again' },
  { id: 2, key: 'hard',  label: 'Hard',  cls: 'r-hard' },
  { id: 3, key: 'good',  label: 'Good',  cls: 'r-good' },
  { id: 4, key: 'easy',  label: 'Easy',  cls: 'r-easy' },
];

function FlashcardStudy({ collection, cards, prefs, onExit }) {
  const { isDue, fsrsReview, fsrsPreviewInterval, fieldPreview } = window.flashcards;
  const keymap = KEY_BINDINGS[prefs.keyboardLayout] || KEY_BINDINGS['1-4'];

  // Build the queue. 'due' mode = due cards + new cards (up to session-length limit).
  // 'all' mode = every card in the collection, shuffled — lets the user re-review
  // even when nothing is due.
  const buildQueue = useCallback((studyMode) => {
    const limit = prefs.sessionLength === -1 ? Infinity : prefs.sessionLength;
    let pool = [];
    if (studyMode === 'all') {
      pool = [...cards];
    } else {
      const due = cards.filter(c => isDue(c) && c.fsrs?.state !== 'new');
      const newCards = cards.filter(c => !c.fsrs || c.fsrs.state === 'new');
      let di = 0, ni = 0;
      while (pool.length < limit && (di < due.length || ni < newCards.length)) {
        if (di < due.length) pool.push(due[di++]);
        if (pool.length >= limit) break;
        if (ni < newCards.length) pool.push(newCards[ni++]);
      }
    }
    if (pool.length > limit) pool = pool.slice(0, limit);
    for (let i = pool.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [pool[i], pool[j]] = [pool[j], pool[i]];
    }
    return pool;
  // cards/prefs are captured at first mount intentionally
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const [queue, setQueue] = useState(() => buildQueue('due'));
  const [idx, setIdx] = useState(0);
  const [revealed, setRevealed] = useState(false);
  const [sessionStart] = useState(() => Date.now());
  const [ratings, setRatings] = useState({ again: 0, hard: 0, good: 0, easy: 0 });
  const [transition, setTransition] = useState(null); // 'leave' | 'enter' | null (for non-flip animations)

  const card = queue[idx] || null;
  const done = idx >= queue.length;

  // Reset reveal state when card changes
  useEffect(() => { setRevealed(false); }, [idx]);

  // Update lastStudiedAt on entering
  useEffect(() => {
    if (queue.length > 0) {
      db.flashcardCollections.put({ ...collection, lastStudiedAt: Date.now() });
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const advance = useCallback(async (rating) => {
    if (!card) return;
    // Compute new FSRS state
    const nextFsrs = fsrsReview(card.fsrs, rating, Date.now());
    await db.flashcardCards.put({ ...card, fsrs: nextFsrs });

    setRatings(prev => ({ ...prev, [RATINGS.find(r => r.id === rating).key]: prev[RATINGS.find(r => r.id === rating).key] + 1 }));

    // "Again" puts the card back near the end of the current queue
    if (rating === 1) {
      setQueue(prev => {
        const next = [...prev];
        const moved = next.splice(idx, 1)[0];
        const insertAt = Math.min(next.length, idx + 4);
        next.splice(insertAt, 0, moved);
        return next;
      });
      // Stay at same idx — the next-up card has shifted in
      animateNext(false);
    } else {
      animateNext(true);
    }
  }, [card, idx, fsrsReview]);

  // Animate transition based on tweaks
  const animateNext = (advanceIdx) => {
    const anim = prefs.flipAnimation;
    if (anim === 'none' || anim === 'flip') {
      // Flip: just unflip and advance
      if (advanceIdx) setIdx(i => i + 1);
      setRevealed(false);
    } else {
      setTransition('leave');
      setTimeout(() => {
        if (advanceIdx) setIdx(i => i + 1);
        setRevealed(false);
        setTransition('enter');
        setTimeout(() => setTransition(null), 30);
      }, 200);
    }
  };

  // Keyboard handlers
  useEffect(() => {
    const onKey = (e) => {
      if (e.target?.tagName === 'INPUT' || e.target?.tagName === 'TEXTAREA') return;
      if (e.key === 'Escape') { e.preventDefault(); onExit(); return; }
      if (!revealed) {
        if (keymap.reveal.includes(e.key)) { e.preventDefault(); setRevealed(true); }
        return;
      }
      for (const r of RATINGS) {
        if (keymap[r.key].includes(e.key)) { e.preventDefault(); advance(r.id); return; }
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [revealed, advance, keymap, onExit]);

  const restartWithAll = useCallback(() => {
    setQueue(buildQueue('all'));
    setIdx(0);
    setRevealed(false);
    setRatings({ again: 0, hard: 0, good: 0, easy: 0 });
  }, [buildQueue]);

  if (queue.length === 0) {
    return (
      <div className="fc-study">
        <div className="fc-study-done">
          <div className="big"><Icon name="check_circle" /></div>
          <h2>Nothing due right now</h2>
          <p>{cards.length === 0
            ? 'This collection is empty — add cards before starting a session.'
            : `All ${cards.length} card${cards.length === 1 ? ' is' : 's are'} scheduled for later. You can still re-review them if you want extra practice.`}</p>
          <div className="row">
            {cards.length > 0 && (
              <button className="lh-btn primary" onClick={restartWithAll}>
                <Icon name="replay" />Study all anyway
              </button>
            )}
            <button className="lh-btn ghost" onClick={onExit}>
              <Icon name="arrow_back" />Back to collection
            </button>
          </div>
        </div>
      </div>
    );
  }

  if (done) {
    const total = ratings.again + ratings.hard + ratings.good + ratings.easy;
    const accuracy = total > 0 ? Math.round(((ratings.good + ratings.easy) / total) * 100) : 0;
    const minutes = Math.max(1, Math.round((Date.now() - sessionStart) / 60000));
    return (
      <div className="fc-study">
        <div className="fc-study-done">
          <div className="big"><Icon name="celebration" /></div>
          <h2>Session complete</h2>
          <p>You reviewed {total} card{total === 1 ? '' : 's'} in {minutes} minute{minutes === 1 ? '' : 's'} · accuracy {accuracy}%.</p>
          <div className="fc-study-summary">
            <div className="cell r-again"><div className="v">{ratings.again}</div><div className="l">Again</div></div>
            <div className="cell r-hard"><div className="v">{ratings.hard}</div><div className="l">Hard</div></div>
            <div className="cell r-good"><div className="v">{ratings.good}</div><div className="l">Good</div></div>
            <div className="cell r-easy"><div className="v">{ratings.easy}</div><div className="l">Easy</div></div>
          </div>
          <div className="row">
            <button className="lh-btn ghost" onClick={restartWithAll} title="Reshuffle every card in this collection and go again">
              <Icon name="replay" />Study all again
            </button>
            <button className="lh-btn primary" onClick={onExit}>
              <Icon name="check" />Back to collection
            </button>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="fc-study">
      {/* Top bar */}
      <div className="fc-study-bar">
        <button className="fc-detail-back" onClick={onExit} style={{ marginBottom: 0 }}>
          <Icon name="close" />Exit
        </button>
        <div className="fc-study-progress">
          <div style={{ width: `${(idx / queue.length) * 100}%` }} />
        </div>
        <div className="fc-study-meta">
          <b>{idx + 1}</b> / {queue.length}
        </div>
      </div>

      {/* Card */}
      <div className="fc-card-stage">
        <CardSurface
          card={card}
          collection={collection}
          revealed={revealed}
          animation={prefs.flipAnimation}
          transition={transition}
          fieldPreview={fieldPreview}
        />

        {!revealed && (
          <button className="fc-reveal-btn" onClick={() => setRevealed(true)}>
            <Icon name="visibility" />Show answer
            <kbd>{keymap.reveal[0] === ' ' ? 'space' : keymap.reveal[0]}</kbd>
          </button>
        )}

        {revealed && (
          <div className="fc-rating">
            {RATINGS.map(r => (
              <button
                key={r.id}
                className={`fc-rate-btn ${r.cls}`}
                onClick={() => advance(r.id)}
                title={`Rate as ${r.label}`}
              >
                <div className="label">{r.label}</div>
                <div className="interval">{fsrsPreviewInterval(card.fsrs, r.id)}</div>
                <div className="kbd-hint">{keymap[r.key][0]}</div>
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

window.FlashcardStudy = FlashcardStudy;

// ---------------------------------------------------------------
// CardSurface — renders prompt and (when revealed) answer.
// Wrapper changes per flip animation tweak.
// ---------------------------------------------------------------
function CardSurface({ card, collection, revealed, animation, transition, fieldPreview }) {
  const promptF = collection.schema.find(f => f.id === collection.promptField);
  const answerFs = collection.schema.filter(f => collection.answerFields.includes(f.id));
  const promptVal = card.fields?.[collection.promptField];

  const FrontFace = (
    <div className="fc-card">
      <div className="fc-card-prompt-label">Prompt · {promptF?.name || 'Front'}</div>
      <RenderValue value={promptVal} type={promptF?.type} className="fc-card-prompt" big />
      <div style={{ flex: 1 }}></div>
      <div style={{ color: 'var(--text-faint)', fontSize: 11, textAlign: 'center' }}>
        Recall the answer, then reveal.
      </div>
    </div>
  );

  const BackFace = (
    <div className="fc-card is-back">
      <div className="fc-card-prompt-label">Prompt · {promptF?.name || 'Front'}</div>
      <RenderValue value={promptVal} type={promptF?.type} className="fc-card-prompt" big />
      <div className="fc-card-divider"></div>
      <div className="fc-card-answer-label">Answer</div>
      <div className="fc-card-answer">
        {answerFs.map(f => {
          const v = card.fields?.[f.id];
          if (v == null || v === '' || (Array.isArray(v) && v.length === 0)) return null;
          return (
            <div key={f.id} className="fc-card-answer-field">
              <div className="label">{f.name}</div>
              <RenderValue value={v} type={f.type} className={`value ${f.type === 'long' ? 'is-long' : ''}`} />
            </div>
          );
        })}
      </div>
    </div>
  );

  if (animation === 'flip') {
    return (
      <div className="fc-flip-wrap">
        <div className={`fc-flip ${revealed ? 'is-revealed' : ''}`}>
          {FrontFace}
          {BackFace}
        </div>
      </div>
    );
  }

  if (animation === 'slide') {
    const cls = transition === 'leave' ? 'is-out' : transition === 'enter' ? 'is-in' : '';
    return (
      <div className="fc-slide-wrap">
        <div className={`fc-slide-card ${cls}`}>
          {revealed ? BackFace : FrontFace}
        </div>
      </div>
    );
  }

  // fade & none
  return (
    <div className="fc-fade-wrap">
      <div className="fc-fade-card" style={{ opacity: transition === 'leave' ? 0 : 1 }}>
        {revealed ? BackFace : FrontFace}
      </div>
    </div>
  );
}

function RenderValue({ value, type, className = '', big = false }) {
  if (value == null || value === '') return <div className={className} style={{ color: 'var(--text-faint)' }}>—</div>;
  if (type === 'image') {
    return <div className={className}><img src={value} alt="" style={{ maxHeight: big ? 200 : 160, maxWidth: '100%', borderRadius: 10 }} /></div>;
  }
  if (type === 'audio') {
    return <div className={className}><audio controls src={value} /></div>;
  }
  if (type === 'tags') {
    return (
      <div className={className} style={{ display: 'flex', flexWrap: 'wrap', gap: 6, justifyContent: big ? 'center' : 'flex-start' }}>
        {(Array.isArray(value) ? value : [value]).map((t, i) => (
          <span key={i} className="fc-tag-chip">{t}</span>
        ))}
      </div>
    );
  }
  if (type === 'date') {
    const n = Number(value);
    const txt = Number.isFinite(n) ? new Date(n).toLocaleDateString() : String(value);
    return <div className={className}>{txt}</div>;
  }
  if (type === 'long') {
    return <div className={className} style={{ whiteSpace: 'pre-wrap' }}>{value}</div>;
  }
  return <div className={className}>{value}</div>;
}
