function RebuildReviewCard({ topic, onComplete }) {
  const [artifactText, setArtifactText] = React.useState('');
  const [notes, setNotes] = React.useState('');
  const stage = Math.min(REBUILD_INTERVALS.length - 1, Number(topic.stage || 0));
  const mission = ['D0', 'D1', 'D3', 'D7', 'D14', 'D30', 'D60', 'D120'][stage] || `D${stage}`;

  function complete(rating) {
    onComplete(topic, rating, { artifactText, notes, reviewDate: fmtDate(nowInIST()) });
    setArtifactText('');
    setNotes('');
  }

  return (
    <div className="rebuild-card">
      <div className="between">
        <div className="stack">
          <div className="row">
            <Pill tone={categoryTone(topic.category)}>{categoryLabel(topic.category)}</Pill>
            <Pill>{mission}</Pill>
            {topic.weak && <Pill tone="weak">weak</Pill>}
          </div>
          <h2>{topic.title}</h2>
          <p className="copy">{topic.artifactPrompt}</p>
        </div>
        <div className="muted mono" style={{ textAlign: 'right' }}>
          Due {formatShortDate(topic.dueDate)}<br />
          {Number(topic.attemptCount || 0)} attempts
        </div>
      </div>

      <div className="panel stack" style={{ padding: 12 }}>
        <h3>Recall Prompts</h3>
        <ol className="question-list">
          {(topic.questions || []).map(question => (
            <li key={question.id}>
              <span>{question.prompt}</span>
              {question.expectedEvidence?.length ? (
                <div className="row" style={{ marginTop: 6 }}>
                  {question.expectedEvidence.slice(0, 4).map(item => <Pill key={item}>{item}</Pill>)}
                </div>
              ) : null}
            </li>
          ))}
        </ol>
      </div>

      <label className="stack">
        <span className="kicker">Artifact From Memory</span>
        <textarea className="textarea" value={artifactText} onChange={event => setArtifactText(event.target.value)} placeholder="Write the answer, code sketch, diagram notes, or explanation without opening notes first." />
      </label>
      <label className="stack">
        <span className="kicker">Gaps / Notes</span>
        <textarea className="textarea" value={notes} onChange={event => setNotes(event.target.value)} placeholder="What was shaky? What exact thing should come back sooner?" />
      </label>
      <div className="row">
        <button className="btn primary" onClick={() => complete('strong')}>Strong</button>
        <button className="btn warn" onClick={() => complete('shaky')}>Shaky</button>
        <button className="btn" onClick={() => complete('weak')}>Weak</button>
      </div>
    </div>
  );
}

function RebuildView() {
  const { state, update, sync } = useStore();
  const TODAY = useToday();
  const today = fmtDate(TODAY);
  const [tab, setTab] = React.useState('today');
  const [query, setQuery] = React.useState('');
  const [category, setCategory] = React.useState('all');
  const [status, setStatus] = React.useState('active');
  const [notice, setNotice] = React.useState('');
  const topics = rebuildTopicsArray(state);
  const attempts = rebuildAttemptsArray(state).sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
  const due = rebuildDueTopics(state, today);
  const activeTopics = topics.filter(topic => topic.status !== 'archived');
  const completedTopics = topics.filter(topic => topic.status === 'completed');
  const weakTopics = activeTopics.filter(topic => topic.weak);
  const focusCount = Number(state.rebuild?.settings?.focusCount || 4);
  const focusTopics = due.slice(0, focusCount);
  const categories = ['all', ...new Set(topics.map(topic => topic.category).filter(Boolean))];

  async function syncBank() {
    const bank = { topics: window.PLAN_DATA.topics || [] };
    update(prev => syncBankIntoState(prev, bank));
    if (!sync.signedIn) {
      setNotice('Sign in first. Rebuild bank changes are stored only in the database.');
      return;
    }
    try {
      const response = await fetch('/api/rebuild/sync', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ bank }),
      });
      const data = await response.json();
      if (!response.ok || data.error) throw new Error(data.error || 'Rebuild API sync failed.');
      setNotice(`D1 bank synced: ${data.bankSync?.count || 0} topics.`);
    } catch (error) {
      setNotice(error.message || String(error));
    }
  }

  function completeTopic(topic, rating, payload) {
    update(prev => {
      let next = completeRebuildTopic(prev, topic.id, rating, payload);
      if (rating === 'weak') {
        const item = createPendingItem(`Redo Rebuild: ${topic.title}`, payload.reviewDate, {
          targetDate: addDays(payload.reviewDate, 1),
          type: 'REBUILD',
          priority: 'high',
          note: topic.artifactPrompt,
        });
        next = {
          ...next,
          pending: {
            ...(next.pending || {}),
            [item.id]: item,
          },
        };
      }
      return next;
    });
    if (sync.signedIn) {
      fetch('/api/rebuild/attempt', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          topicId: topic.id,
          rating,
          artifactText: payload.artifactText,
          notes: payload.notes,
          reviewDate: payload.reviewDate,
        }),
      }).catch(() => {});
    }
  }

  function patchTopic(id, patch) {
    update(prev => ({
      ...prev,
      rebuild: {
        ...prev.rebuild,
        topics: {
          ...(prev.rebuild?.topics || {}),
          [id]: {
            ...(prev.rebuild?.topics?.[id] || {}),
            ...patch,
          },
        },
      },
    }));
    if (sync.signedIn) {
      fetch('/api/rebuild/topic', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ topicId: id, ...patch }),
      }).catch(() => {});
    }
  }

  const library = topics.filter(topic => {
    const text = `${topic.title} ${topic.category} ${topic.artifactPrompt}`.toLowerCase();
    if (query && !text.includes(query.toLowerCase())) return false;
    if (category !== 'all' && topic.category !== category) return false;
    if (status !== 'all' && topic.status !== status) return false;
    return true;
  }).sort((a, b) => {
    if ((a.dueDate || '') !== (b.dueDate || '')) return String(a.dueDate || '9999-12-31').localeCompare(String(b.dueDate || '9999-12-31'));
    return String(a.title).localeCompare(String(b.title));
  });

  const roadmapGroups = activeTopics.reduce((groups, topic) => {
    const key = topic.dueDate || 'completed';
    if (!groups[key]) groups[key] = [];
    groups[key].push(topic);
    return groups;
  }, {});
  const roadmapDates = Object.keys(roadmapGroups).sort().slice(0, 45);

  return (
    <div className="page">
      <PageHead
        kicker="Concept Rebuild"
        title="Spaced repetition for real retention"
        subtitle="Every concept introduced in the curriculum becomes a D0/D1/D3/D7/D14/D30/D60/D120 recall card. Weak cards return tomorrow and enter Pending."
        actions={<button className="btn" onClick={syncBank}>Sync bank</button>}
      />

      <div className="grid four">
        <Stat value={due.length} label="Due today" tone={due.length ? 'amber' : 'accent'} />
        <Stat value={weakTopics.length} label="Weak active" tone={weakTopics.length ? 'rose' : 'accent'} />
        <Stat value={completedTopics.length} label="Completed" tone="accent" />
        <Stat value={attempts.length} label="Attempts logged" />
      </div>

      <div className="tabs">
        {[
          ['today', due.length ? `Today ${due.length}` : 'Today'],
          ['library', 'Library'],
          ['roadmap', 'Roadmap'],
          ['history', 'History'],
          ['settings', 'Settings'],
        ].map(([id, label]) => (
          <button key={id} className={`btn ${tab === id ? 'primary' : ''}`} onClick={() => setTab(id)}>{label}</button>
        ))}
      </div>
      {notice && <div className="panel sync-help">{notice}</div>}

      {tab === 'today' && (
        <div className="stack">
          {focusTopics.length ? focusTopics.map(topic => (
            <RebuildReviewCard key={topic.id} topic={topic} onComplete={completeTopic} />
          )) : (
            <EmptyState title="No cards due today" body="Use Library to preview topics, or trust the schedule to bring cards back when they are due." />
          )}
          {due.length > focusTopics.length && (
            <div className="panel stack">
              <h2>Still Due</h2>
              {due.slice(focusTopics.length).map(topic => (
                <div className="rebuild-row" key={topic.id}>
                  <div className="between">
                    <h3>{topic.title}</h3>
                    <Pill tone={categoryTone(topic.category)}>{categoryLabel(topic.category)}</Pill>
                  </div>
                  <p className="copy">{topic.artifactPrompt}</p>
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {tab === 'library' && (
        <div className="stack">
          <div className="panel stack">
            <div className="calendar-toolbar">
              <input className="input" value={query} onChange={event => setQuery(event.target.value)} placeholder="Search concept, category, artifact" />
              <select className="select" value={category} onChange={event => setCategory(event.target.value)}>
                {categories.map(item => <option key={item} value={item}>{item === 'all' ? 'All categories' : categoryLabel(item)}</option>)}
              </select>
              <select className="select" value={status} onChange={event => setStatus(event.target.value)}>
                <option value="active">Active</option>
                <option value="completed">Completed</option>
                <option value="archived">Archived</option>
                <option value="all">All status</option>
              </select>
              <button className="btn" onClick={() => { setQuery(''); setCategory('all'); setStatus('active'); }}>Clear</button>
            </div>
          </div>
          <div className="panel">
            {library.length ? library.map(topic => (
              <div className="rebuild-row" key={topic.id}>
                <div className="between">
                  <div className="stack">
                    <div className="row">
                      <Pill tone={categoryTone(topic.category)}>{categoryLabel(topic.category)}</Pill>
                      <Pill>{topic.priority}</Pill>
                      {topic.weak && <Pill tone="weak">weak</Pill>}
                    </div>
                    <h3>{topic.title}</h3>
                  </div>
                  <div className="muted mono" style={{ textAlign: 'right' }}>
                    {topic.status}<br />due {formatShortDate(topic.dueDate)}
                  </div>
                </div>
                <p className="copy">{topic.artifactPrompt}</p>
                <div className="row">
                  <button className="btn small" onClick={() => patchTopic(topic.id, { dueDate: today, status: 'active' })}>Due today</button>
                  <button className="btn small" onClick={() => patchTopic(topic.id, { weak: true, dueDate: addDays(today, 1), status: 'active' })}>Mark weak</button>
                  <button className="btn small ghost" onClick={() => patchTopic(topic.id, { status: topic.status === 'archived' ? 'active' : 'archived' })}>
                    {topic.status === 'archived' ? 'Unarchive' : 'Archive'}
                  </button>
                </div>
              </div>
            )) : (
              <EmptyState title="No topics match" body="The generated bank has 86 concepts across Python, API, Azure, GenAI, and enterprise repo habits." />
            )}
          </div>
        </div>
      )}

      {tab === 'roadmap' && (
        <div className="panel stack">
          <h2>Upcoming Rebuild Roadmap</h2>
          {roadmapDates.map(dateText => (
            <div className="rebuild-row" key={dateText}>
              <div className="between">
                <h3>{dateText === 'completed' ? 'Completed' : formatShortDate(dateText)}</h3>
                <Pill tone={dateText < today ? 'weak' : dateText === today ? 'genai' : ''}>{roadmapGroups[dateText].length} cards</Pill>
              </div>
              <div className="row">
                {roadmapGroups[dateText].slice(0, 8).map(topic => (
                  <Pill key={topic.id} tone={categoryTone(topic.category)}>{topic.title}</Pill>
                ))}
                {roadmapGroups[dateText].length > 8 && <span className="muted mono">+{roadmapGroups[dateText].length - 8} more</span>}
              </div>
            </div>
          ))}
        </div>
      )}

      {tab === 'history' && (
        <div className="panel">
          {attempts.length ? attempts.slice(0, 80).map(attempt => {
            const topic = state.rebuild.topics[attempt.topicId];
            return (
              <div className="rebuild-row" key={attempt.id}>
                <div className="between">
                  <h3>{topic?.title || attempt.topicId}</h3>
                  <div className="row">
                    <Pill tone={attempt.rating === 'weak' ? 'weak' : attempt.rating === 'shaky' ? 'genai' : 'done'}>{attempt.rating}</Pill>
                    <span className="muted mono">{attempt.reviewDate}</span>
                  </div>
                </div>
                {attempt.notes && <p className="copy">{attempt.notes}</p>}
              </div>
            );
          }) : (
            <EmptyState title="No attempts yet" body="Review a due card to start the retention history." />
          )}
        </div>
      )}

      {tab === 'settings' && (
        <div className="grid two">
          <div className="panel stack">
            <h2>Rebuild Settings</h2>
            <label className="stack">
              <span className="kicker">Daily Budget Minutes</span>
              <input className="input" type="number" min="10" max="120" value={state.rebuild.settings.dailyBudgetMinutes} onChange={event => update(prev => ({ ...prev, rebuild: { ...prev.rebuild, settings: { ...prev.rebuild.settings, dailyBudgetMinutes: Number(event.target.value) } } }))} />
            </label>
            <label className="stack">
              <span className="kicker">Focus Cards Per Day</span>
              <input className="input" type="number" min="1" max="10" value={state.rebuild.settings.focusCount} onChange={event => update(prev => ({ ...prev, rebuild: { ...prev.rebuild, settings: { ...prev.rebuild.settings, focusCount: Number(event.target.value) } } }))} />
            </label>
            <div className="sync-help">Bank: {state.rebuild.bankFingerprint || 'not synced'} - topics: {topics.length}</div>
          </div>
          <div className="panel stack">
            <h2>Official References</h2>
            {(window.PLAN_DATA.docs || []).map(doc => (
              <a className="card" key={doc.url} href={doc.url} target="_blank" rel="noreferrer">
                <div className="between">
                  <strong>{doc.label}</strong>
                  <Pill tone={categoryTone(doc.category)}>{categoryLabel(doc.category)}</Pill>
                </div>
              </a>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

window.RebuildView = RebuildView;
