// DSA Problem SRS / Rebuild view

const DSA_SRS_DEFAULT_SETTINGS = {
  dailyCap: 4,
  targetMinutes: 60,
  overflowPolicy: 'carry',
  normalIntervals: [0, 3, 7, 21],
  hardIntervals: [0, 1, 3, 7, 14],
};

function dsaSrsTodayString() {
  return fmtDate(nowInIST());
}

function dsaSrsAddDays(dateText, days) {
  const [year, month, day] = String(dateText || dsaSrsTodayString()).split('-').map(Number);
  const date = new Date(year, month - 1, day);
  date.setDate(date.getDate() + Number(days || 0));
  return fmtDate(date);
}

function dsaSrsTomorrowString() {
  return dsaSrsAddDays(dsaSrsTodayString(), 1);
}

function dsaSrsNormalizeText(value) {
  return String(value || '')
    .trim()
    .toLowerCase()
    .replace(/['"`]/g, '')
    .replace(/&/g, 'and')
    .replace(/[^a-z0-9]+/g, ' ')
    .replace(/\s+/g, ' ')
    .trim();
}

function dsaSrsKey(topic, title) {
  return `${dsaSrsNormalizeText(topic)}::${dsaSrsNormalizeText(title)}`;
}

function dsaSrsTopicByNum(num) {
  return (window.PLAN_DATA?.dsa || []).find(t => String(t.num) === String(num));
}

function dsaSrsAliases(topicNum, topic) {
  const byNum = {
    '1': ['basics'],
    '2': ['sorting'],
    '3': ['arrays'],
    '4': ['binary search'],
    '5': ['strings basic', 'strings'],
    '6': ['linked list'],
    '7': ['recursion'],
    '8': ['bit manipulation', 'bit'],
    '9': ['stack', 'queue', 'queues'],
    '10': ['sliding window', 'two pointer'],
    '11': ['heap', 'heaps'],
    '12': ['greedy'],
    '13': ['binary trees'],
    '14': ['bst'],
    '15': ['graph', 'graphs'],
    '16': ['dp', 'dynamic programming'],
    '17': ['trie', 'tries'],
    '18': ['strings advanced'],
  };
  const fromTopic = dsaSrsNormalizeText(topic)
    .split(' ')
    .filter(word => word.length > 3)
    .slice(0, 3)
    .join(' ');
  return [...(byNum[String(topicNum)] || []), fromTopic].filter(Boolean);
}

function dsaSrsInferScheduledDate(topicNum, topic) {
  return dsaSrsTomorrowString();
}

function dsaSrsParseLine(line, delimiter) {
  const cells = [];
  let cell = '';
  let quoted = false;
  for (let i = 0; i < line.length; i += 1) {
    const char = line[i];
    const next = line[i + 1];
    if (char === '"' && next === '"') {
      cell += '"';
      i += 1;
    } else if (char === '"') {
      quoted = !quoted;
    } else if (char === delimiter && !quoted) {
      cells.push(cell.trim());
      cell = '';
    } else {
      cell += char;
    }
  }
  cells.push(cell.trim());
  return cells;
}

function dsaSrsParseCsv(text) {
  const lines = String(text || '')
    .split(/\r?\n/)
    .map(line => line.trim())
    .filter(Boolean);
  if (!lines.length) return [];
  const delimiter = lines[0].includes('\t') ? '\t' : ',';
  const first = dsaSrsParseLine(lines[0], delimiter);
  const headerLike = first.some(cell => /title|problem|topic|difficulty|scheduled|url/i.test(cell));
  const headers = headerLike
    ? first.map(cell => dsaSrsNormalizeText(cell).replace(/\s+/g, '_'))
    : ['topic_num', 'topic', 'title', 'difficulty', 'url', 'scheduled_date', 'order_index'];
  const body = headerLike ? lines.slice(1) : lines;
  return body.map((line, index) => {
    const cells = dsaSrsParseLine(line, delimiter);
    const row = {};
    headers.forEach((header, i) => { row[header] = cells[i] || ''; });
    const topicNum = row.topic_num || row.topicnum || row.num || '';
    const topicFromNum = dsaSrsTopicByNum(topicNum)?.topic || '';
    const topic = row.topic || topicFromNum;
    const title = row.title || row.problem || row.problem_name || row.name || '';
    if (!title) return null;
    const scheduledDate = row.scheduled_date || row.scheduleddate || row.date || '';
    return {
      topicNum,
      topic: topic || 'Mixed DSA',
      title,
      difficulty: row.difficulty || '',
      url: row.url || row.link || '',
      scheduledDate,
      orderIndex: Number(row.order_index || row.order || index) || index,
    };
  }).filter(Boolean);
}

function dsaSrsSortProblems(problems) {
  return [...(problems || [])].sort((a, b) => {
    const ad = a.dueDate || a.scheduledDate || '9999-12-31';
    const bd = b.dueDate || b.scheduledDate || '9999-12-31';
    if (ad !== bd) return ad.localeCompare(bd);
    const ao = Number(a.orderIndex || 0);
    const bo = Number(b.orderIndex || 0);
    if (ao !== bo) return ao - bo;
    return String(a.title || '').localeCompare(String(b.title || ''));
  });
}

function dsaSrsGroupByDate(problems) {
  const groups = {};
  dsaSrsSortProblems(problems).forEach(problem => {
    const date = problem.scheduledDate || 'Unscheduled';
    if (!groups[date]) groups[date] = [];
    groups[date].push(problem);
  });
  return groups;
}

function dsaSrsCodeRecommended(problem) {
  return dsaSrsProblemPath(problem) !== 'normal' || !problem.attemptCount || Number(problem.stage || 0) >= 2;
}

function dsaSrsProblemPath(problem) {
  const difficulty = dsaSrsNormalizeText(problem?.difficulty || '');
  return difficulty.includes('easy') ? 'normal' : 'hard';
}

function dsaSrsPathLabel(path) {
  return path === 'normal' ? 'normal path' : 'spaced path';
}

function DsaSrsPill({ children, tone = '' }) {
  return <span className={`pill ${tone}`}>{children}</span>;
}

function DsaSrsTabs({ tab, setTab }) {
  const tabs = [
    ['today', 'Today'],
    ['roadmap', 'Roadmap'],
    ['bank', 'Problem Bank'],
    ['import', 'Import'],
    ['settings', 'Settings'],
  ];
  return (
    <div className="dsa-srs-tabs">
      {tabs.map(([id, label]) => (
        <button key={id} className={`btn ${tab === id ? 'primary' : ''}`} onClick={() => setTab(id)}>
          {label}
        </button>
      ))}
    </div>
  );
}

function useDsaSrsData() {
  const [snapshot, setSnapshot] = React.useState({
    settings: DSA_SRS_DEFAULT_SETTINGS,
    problems: [],
    attempts: [],
    loading: true,
    error: '',
  });

  const applySnapshot = React.useCallback((data) => {
    setSnapshot({
      settings: { ...DSA_SRS_DEFAULT_SETTINGS, ...(data.settings || {}) },
      problems: Array.isArray(data.problems) ? data.problems : [],
      attempts: Array.isArray(data.attempts) ? data.attempts : [],
      loading: false,
      error: '',
    });
  }, []);

  const load = React.useCallback(async ({ silent = false } = {}) => {
    if (!silent) setSnapshot(prev => ({ ...prev, loading: true, error: '' }));
    try {
      const response = await fetch('/api/dsa-srs/state', { credentials: 'include' });
      const data = await response.json();
      if (!response.ok || data.error) throw new Error(data.error || 'Could not load DSA SRS.');
      applySnapshot(data);
    } catch (error) {
      setSnapshot(prev => ({ ...prev, loading: false, error: error.message || String(error) }));
    }
  }, [applySnapshot]);

  const post = React.useCallback(async (path, body, options = {}) => {
    setSnapshot(prev => ({ ...prev, error: '' }));
    const response = await fetch(path, {
      method: options.method || 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body || {}),
    });
    const data = await response.json();
    if (!response.ok || data.error) throw new Error(data.error || 'DSA SRS request failed.');
    applySnapshot(data);
    return data;
  }, [applySnapshot]);

  React.useEffect(() => { load(); }, [load]);

  return { snapshot, setSnapshot: applySnapshot, load, post };
}

function DsaSrsReviewCard({ problem, onAttempt }) {
  const [recallText, setRecallText] = React.useState('');
  const [notes, setNotes] = React.useState('');
  const [codeDone, setCodeDone] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const recommended = dsaSrsCodeRecommended(problem);

  async function submit() {
    setSaving(true);
    try {
      await onAttempt(problem.id, {
        recallText,
        notes,
        codeDone,
        mode: 'recall_then_code',
        reviewDate: dsaSrsTodayString(),
      });
      setRecallText('');
      setNotes('');
      setCodeDone(false);
    } catch (error) {
      alert(error.message || String(error));
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="card dsa-srs-review-card">
      <div className="dsa-srs-review-head">
        <div style={{minWidth:0}}>
          <div className="dsa-srs-pill-row">
            <DsaSrsPill tone="accent">{problem.topic}</DsaSrsPill>
            <DsaSrsPill>{problem.difficulty || 'unrated'}</DsaSrsPill>
            <DsaSrsPill>due {problem.dueDate || problem.scheduledDate || 'today'}</DsaSrsPill>
            <DsaSrsPill>{dsaSrsPathLabel(problem.path || dsaSrsProblemPath(problem))} step {(problem.stage || 0) + 1}</DsaSrsPill>
            {recommended && <DsaSrsPill tone="warn">code check</DsaSrsPill>}
          </div>
          <h3 className="dsa-srs-problem-title">
            {problem.url ? <a href={problem.url} target="_blank" rel="noreferrer">{problem.title}</a> : problem.title}
          </h3>
        </div>
        <div className="mono muted dsa-srs-attempt-count">{problem.attemptCount || 0} attempts</div>
      </div>

      <div className="dsa-srs-mission">
        <div className="kicker" style={{margin:0}}>Recall mission</div>
        <div className="muted">
          Identify the pattern trigger, invariant, template shape, edge cases, and complexity before coding.
        </div>
      </div>

      <textarea
        className="textarea"
        value={recallText}
        onChange={e => setRecallText(e.target.value)}
        placeholder="Write the pattern, invariant, edge cases, and rough code template from memory."
        style={{minHeight:'110px'}}
      />
      <div className="dsa-srs-review-grid">
        <label className="dsa-srs-checkline">
          <input type="checkbox" checked={codeDone} onChange={e => setCodeDone(e.target.checked)} />
          <span>{recommended ? 'I coded this review' : 'I also coded it'}</span>
        </label>
        <input
          className="input"
          value={notes}
          onChange={e => setNotes(e.target.value)}
          placeholder="Optional miss: e.g. parent pointer, off-by-one, recurrence state..."
        />
      </div>

      <div className="dsa-srs-complete-row">
        <button className="btn primary" disabled={saving} onClick={submit}>
          {saving ? 'Saving...' : 'Complete review'}
        </button>
        <div className="mono muted" style={{fontSize:'11px'}}>
          Next due follows {dsaSrsPathLabel(problem.path || dsaSrsProblemPath(problem))}.
        </div>
      </div>
    </div>
  );
}

function DsaSrsTodayTab({ problems, settings, onAttempt, setTab }) {
  const today = dsaSrsTodayString();
  const due = dsaSrsSortProblems(problems.filter(p => p.status !== 'deleted' && p.dueDate && p.dueDate <= today));
  const upcoming = dsaSrsSortProblems(problems.filter(p => p.scheduledDate && p.scheduledDate > today));
  const cap = Number(settings.dailyCap || 4);
  const queue = due.slice(0, cap);

  return (
    <div className="col">
      <div className="card">
        <div className="dsa-srs-summary-grid">
          <Stat label="Due now" value={<CountUp to={due.length} />} sub={`${Math.min(due.length, cap)} in today's deck`} accent />
          <Stat label="Imported" value={<CountUp to={problems.length} />} sub="exact problem bank" />
          <Stat label="Upcoming" value={<CountUp to={upcoming.length} />} sub="locked by schedule date" />
          <Stat label="Daily cap" value={<CountUp to={cap} />} sub={`${settings.targetMinutes || 60} min target`} />
        </div>
      </div>

      {!problems.length && (
        <div className="card" style={{textAlign:'center', padding:'46px'}}>
          <div className="card-title">Import your exact problem list.</div>
          <p className="muted" style={{margin:'10px auto 18px', maxWidth:'560px'}}>
            The rebuild system stays empty until you paste the actual DSA problems you want tracked.
          </p>
          <button className="btn primary" onClick={() => setTab('import')}>Open Import</button>
        </div>
      )}

      {!!problems.length && !queue.length && (
        <div className="card" style={{textAlign:'center', padding:'46px'}}>
          <div className="card-title">No problem reviews due right now.</div>
          <p className="muted" style={{marginTop:'10px'}}>Upcoming problems unlock by scheduled topic date.</p>
        </div>
      )}

      {queue.map(problem => (
        <DsaSrsReviewCard key={problem.id} problem={problem} onAttempt={onAttempt} />
      ))}

      {due.length > cap && (
        <div className="card" style={{borderColor:'var(--warn)'}}>
          <div className="card-title">{due.length - cap} reviews remain in backlog.</div>
          <p className="muted" style={{marginTop:'8px'}}>
            They stay saved in D1 and roll forward. The calendar is not rewritten.
          </p>
        </div>
      )}
    </div>
  );
}

function DsaSrsRoadmapTab({ problems, attempts }) {
  const today = dsaSrsTodayString();
  const groups = dsaSrsGroupByDate(problems);
  const dates = Object.keys(groups).sort();
  return (
    <div className="col">
      {dates.length === 0 && (
        <div className="card" style={{textAlign:'center', padding:'46px'}}>
          <div className="card-title">No roadmap yet.</div>
          <p className="muted" style={{marginTop:'10px'}}>Import problems to group them by scheduled topic day.</p>
        </div>
      )}
      {dates.map(date => {
        const list = groups[date];
        const due = list.filter(p => p.dueDate && p.dueDate <= today).length;
        const reviewed = list.filter(p => p.attemptCount > 0).length;
        const first = list[0] || {};
        return (
          <div key={date} className="card dsa-srs-roadmap-day">
            <div className="dsa-srs-roadmap-head">
              <div>
                <div className="kicker">{date === 'Unscheduled' ? 'Unscheduled' : `${date} ${date <= today ? '- active' : '- upcoming'}`}</div>
                <div className="card-title">{first.topic || 'Mixed DSA'}</div>
              </div>
              <div className="dsa-srs-pill-row">
                <DsaSrsPill tone={due ? 'warn' : ''}>{due} due</DsaSrsPill>
                <DsaSrsPill>{reviewed}/{list.length} reviewed</DsaSrsPill>
              </div>
            </div>
            <Bar value={reviewed} total={Math.max(1, list.length)} />
            <div className="dsa-srs-mini-list">
              {list.slice(0, 8).map(problem => (
                <div key={problem.id} className="dsa-srs-mini-row">
                  <span className="mono muted">{problem.difficulty || 'DSA'}</span>
                  <span>{problem.title}</span>
                  <span className="mono muted">due {problem.dueDate || '-'}</span>
                </div>
              ))}
              {list.length > 8 && <div className="mono muted">+ {list.length - 8} more</div>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function DsaSrsBankTab({ problems, post, applySnapshot }) {
  const [query, setQuery] = React.useState('');
  const [filter, setFilter] = React.useState('all');
  const [draft, setDraft] = React.useState({ topicNum: '', topic: '', title: '', difficulty: '', url: '', scheduledDate: '' });
  const [saving, setSaving] = React.useState(false);
  const today = dsaSrsTodayString();
  const filtered = dsaSrsSortProblems(problems).filter(problem => {
    const haystack = `${problem.topic} ${problem.title} ${problem.difficulty}`.toLowerCase();
    if (query && !haystack.includes(query.toLowerCase())) return false;
    if (filter === 'due') return problem.dueDate && problem.dueDate <= today;
    if (filter === 'upcoming') return problem.scheduledDate && problem.scheduledDate > today;
    if (filter === 'spaced') return (problem.path || dsaSrsProblemPath(problem)) !== 'normal';
    return true;
  });

  async function addProblem(e) {
    e.preventDefault();
    if (!draft.title.trim()) return;
    setSaving(true);
    try {
      const topicFromNum = dsaSrsTopicByNum(draft.topicNum)?.topic || '';
      const topic = draft.topic.trim() || topicFromNum || 'Mixed DSA';
      const scheduledDate = draft.scheduledDate || dsaSrsInferScheduledDate(draft.topicNum, topic);
      await post('/api/dsa-srs/problem', {
        problem: { ...draft, topic, scheduledDate },
        scheduleStartDate: dsaSrsTomorrowString(),
      });
      setDraft({ topicNum: '', topic: '', title: '', difficulty: '', url: '', scheduledDate: '' });
    } catch (error) {
      alert(error.message || String(error));
    } finally {
      setSaving(false);
    }
  }

  async function deleteProblem(problem) {
    if (!confirm(`Delete "${problem.title}" and its SRS attempts from D1?`)) return;
    try {
      const response = await fetch(`/api/dsa-srs/problem?id=${encodeURIComponent(problem.id)}`, {
        method: 'DELETE',
        credentials: 'include',
      });
      const data = await response.json();
      if (!response.ok || data.error) throw new Error(data.error || 'Delete failed.');
      applySnapshot(data);
    } catch (error) {
      alert(error.message || String(error));
    }
  }

  return (
    <div className="col">
      <form className="card dsa-srs-add-grid" onSubmit={addProblem}>
        <div>
          <div className="kicker">Add one problem</div>
          <input
            className="input"
            value={draft.topicNum}
            onChange={e => setDraft(d => ({ ...d, topicNum: e.target.value }))}
            placeholder="Topic #"
          />
        </div>
        <div>
          <div className="kicker">&nbsp;</div>
          <input
            className="input"
            value={draft.title}
            onChange={e => setDraft(d => ({ ...d, title: e.target.value }))}
            placeholder="Problem title"
          />
        </div>
        <div>
          <div className="kicker">&nbsp;</div>
          <input
            className="input"
            value={draft.difficulty}
            onChange={e => setDraft(d => ({ ...d, difficulty: e.target.value }))}
            placeholder="Difficulty"
          />
        </div>
        <div>
          <div className="kicker">&nbsp;</div>
          <button className="btn primary" disabled={saving || !draft.title.trim()}>
            {saving ? 'Adding...' : 'Add'}
          </button>
        </div>
      </form>

      <div className="card">
        <div className="dsa-srs-bank-toolbar">
          <input className="input" value={query} onChange={e => setQuery(e.target.value)} placeholder="Search topic, problem, difficulty..." />
          <select className="select" value={filter} onChange={e => setFilter(e.target.value)}>
            <option value="all">All problems</option>
            <option value="due">Due now</option>
            <option value="upcoming">Upcoming</option>
            <option value="spaced">Medium / Hard path</option>
          </select>
        </div>
        <div className="kicker" style={{marginTop:'16px'}}>{filtered.length} problems</div>
        <div className="dsa-srs-bank-list">
          {filtered.map(problem => (
            <div key={problem.id} className="dsa-srs-bank-row">
              <div style={{minWidth:0}}>
                <div className="dsa-srs-pill-row">
                  <DsaSrsPill>{problem.topic}</DsaSrsPill>
                  <DsaSrsPill>{problem.difficulty || 'unrated'}</DsaSrsPill>
                  <DsaSrsPill>due {problem.dueDate || '-'}</DsaSrsPill>
                </div>
                <div className="dsa-srs-bank-title">{problem.title}</div>
              </div>
              <div className="mono muted">{problem.attemptCount || 0}x</div>
              <button className="btn ghost" style={{color:'var(--rose)'}} onClick={() => deleteProblem(problem)}>Delete</button>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function DsaSrsImportTab({ problems, post }) {
  const [text, setText] = React.useState('');
  const [preview, setPreview] = React.useState([]);
  const [replace, setReplace] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const existingKeys = React.useMemo(() => new Set(problems.map(p => dsaSrsKey(p.topic, p.title))), [problems]);
  const duplicateCount = preview.filter(p => existingKeys.has(dsaSrsKey(p.topic, p.title))).length;

  function buildPreview() {
    setPreview(dsaSrsParseCsv(text));
  }

  async function importPreview() {
    if (!preview.length) return;
    if (replace && !confirm('Replace the entire DSA problem bank and delete its attempts?')) return;
    setSaving(true);
    try {
      await post('/api/dsa-srs/import', {
        problems: preview,
        replace,
        scheduleStartDate: dsaSrsTomorrowString(),
      });
      setText('');
      setPreview([]);
      setReplace(false);
    } catch (error) {
      alert(error.message || String(error));
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="col">
      <div className="card">
        <div className="card-h">
          <div>
            <div className="kicker">Exact problem import</div>
            <div className="card-title">Paste CSV or tab-separated rows.</div>
          </div>
          <DsaSrsPill>{problems.length} saved</DsaSrsPill>
        </div>
        <textarea
          className="textarea"
          value={text}
          onChange={e => setText(e.target.value)}
          placeholder={'topic_num,topic,title,difficulty,url,scheduled_date,order_index\n13,Binary Trees,All nodes at K distance,Hard,https://...,,1'}
          style={{minHeight:'180px', fontFamily:'var(--mono)', fontSize:'12px'}}
        />
        <div className="dsa-srs-import-actions">
          <button className="btn" onClick={buildPreview} disabled={!text.trim()}>Preview</button>
          <label className="dsa-srs-checkline">
            <input type="checkbox" checked={replace} onChange={e => setReplace(e.target.checked)} />
            <span>Replace existing bank</span>
          </label>
          <button className="btn primary" onClick={importPreview} disabled={!preview.length || saving}>
            {saving ? 'Importing...' : `Import ${preview.length || ''}`}
          </button>
        </div>
        <p className="muted" style={{marginTop:'12px'}}>
          Leave `scheduled_date` blank for the normal flow: this topic starts from tomorrow ({dsaSrsTomorrowString()}) and spreads by the daily cap.
        </p>
      </div>

      {!!preview.length && (
        <div className="card">
          <div className="card-h">
            <div>
              <div className="kicker">Preview</div>
              <div className="card-title">{preview.length} rows ready</div>
            </div>
            <div className="dsa-srs-pill-row">
              <DsaSrsPill tone={duplicateCount ? 'warn' : ''}>{duplicateCount} existing</DsaSrsPill>
            </div>
          </div>
          <div className="dsa-srs-preview-list">
            {preview.slice(0, 12).map((problem, index) => (
              <div key={`${problem.title}_${index}`} className="dsa-srs-mini-row">
                <span className="mono muted">{problem.topicNum || '-'}</span>
                <span>{problem.topic}</span>
                <span>{problem.title}</span>
                <span className="mono muted">{problem.scheduledDate || `auto from ${dsaSrsTomorrowString()}`}</span>
              </div>
            ))}
            {preview.length > 12 && <div className="mono muted">+ {preview.length - 12} more rows</div>}
          </div>
        </div>
      )}
    </div>
  );
}

function DsaSrsSettingsTab({ settings, post }) {
  const [draft, setDraft] = React.useState(() => ({ ...DSA_SRS_DEFAULT_SETTINGS, ...settings }));
  const [saving, setSaving] = React.useState(false);

  React.useEffect(() => {
    setDraft({ ...DSA_SRS_DEFAULT_SETTINGS, ...settings });
  }, [settings]);

  async function saveSettings(e) {
    e.preventDefault();
    setSaving(true);
    try {
      await post('/api/dsa-srs/problem', { action: 'settings', settings: draft });
    } catch (error) {
      alert(error.message || String(error));
    } finally {
      setSaving(false);
    }
  }

  return (
    <form className="card dsa-srs-settings-grid" onSubmit={saveSettings}>
      <div>
        <div className="kicker">Daily cap</div>
        <input
          className="input"
          type="number"
          min="1"
          max="12"
          value={draft.dailyCap}
          onChange={e => setDraft(d => ({ ...d, dailyCap: e.target.value }))}
        />
      </div>
      <div>
        <div className="kicker">Target minutes</div>
        <input
          className="input"
          type="number"
          min="15"
          max="180"
          value={draft.targetMinutes}
          onChange={e => setDraft(d => ({ ...d, targetMinutes: e.target.value }))}
        />
      </div>
      <div>
        <div className="kicker">Normal path</div>
        <input className="input" value={(draft.normalIntervals || []).join('/')} readOnly />
      </div>
      <div>
        <div className="kicker">Medium/Hard path</div>
        <input className="input" value={(draft.hardIntervals || []).join('/')} readOnly />
      </div>
      <div className="dsa-srs-settings-copy">
        <div className="card-title">Overflow carries beyond the sprint.</div>
        <p className="muted" style={{marginTop:'8px'}}>
          This keeps the original calendar intact while the problem SRS continues until recall and coding fluency return.
        </p>
      </div>
      <button className="btn primary" disabled={saving}>{saving ? 'Saving...' : 'Save settings'}</button>
    </form>
  );
}

function DSARebuildView() {
  const [tab, setTab] = React.useState('today');
  const { snapshot, setSnapshot: applySnapshot, load, post } = useDsaSrsData();
  const { settings, problems, attempts, loading, error } = snapshot;

  async function saveAttempt(problemId, attempt) {
    await post('/api/dsa-srs/attempt', { problemId, attempt });
  }

  const today = dsaSrsTodayString();
  const dueCount = problems.filter(p => p.dueDate && p.dueDate <= today).length;
  const reviewedCount = problems.filter(p => p.attemptCount > 0).length;

  return (
    <div className="fade-in">
      <div className="section-h dsa-srs-hero">
        <div>
          <div className="kicker">DSA Rebuild - problem SRS - exact bank</div>
          <h1 className="h-title">Recall, <em>code</em>, repeat.</h1>
        </div>
        <div className="dsa-srs-hero-stats">
          <Stat label="Due" value={<CountUp to={dueCount} />} sub={`${settings.dailyCap || 4} today cap`} accent />
          <Stat label="Reviewed" value={<CountUp to={reviewedCount} />} sub={`of ${problems.length}`} />
        </div>
      </div>

      <DsaSrsTabs tab={tab} setTab={setTab} />

      {error && (
        <div className="card" style={{borderColor:'var(--rose)', color:'var(--rose)', marginBottom:'18px'}}>
          <div className="kicker" style={{color:'var(--rose)'}}>DSA SRS error</div>
          {error}
        </div>
      )}

      {loading ? (
        <div className="card" style={{textAlign:'center', padding:'46px'}}>
          <div className="card-title">Loading problem SRS...</div>
        </div>
      ) : (
        <>
          {tab === 'today' && <DsaSrsTodayTab problems={problems} settings={settings} onAttempt={saveAttempt} setTab={setTab} />}
          {tab === 'roadmap' && <DsaSrsRoadmapTab problems={problems} attempts={attempts} />}
          {tab === 'bank' && <DsaSrsBankTab problems={problems} post={post} applySnapshot={applySnapshot} />}
          {tab === 'import' && <DsaSrsImportTab problems={problems} post={post} />}
          {tab === 'settings' && <DsaSrsSettingsTab settings={settings} post={post} />}
        </>
      )}
    </div>
  );
}

function DsaSrsTodayPanel({ onOpen }) {
  const [snapshot, setSnapshot] = React.useState({
    settings: DSA_SRS_DEFAULT_SETTINGS,
    problems: [],
    loading: true,
    error: '',
  });

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      try {
        const response = await fetch('/api/dsa-srs/state', { credentials: 'include' });
        const data = await response.json();
        if (cancelled) return;
        if (!response.ok || data.error) throw new Error(data.error || 'Could not load DSA SRS.');
        setSnapshot({
          settings: { ...DSA_SRS_DEFAULT_SETTINGS, ...(data.settings || {}) },
          problems: Array.isArray(data.problems) ? data.problems : [],
          loading: false,
          error: '',
        });
      } catch (error) {
        if (!cancelled) setSnapshot(prev => ({ ...prev, loading: false, error: error.message || String(error) }));
      }
    }
    load();
    return () => { cancelled = true; };
  }, []);

  if (snapshot.loading || snapshot.error || !snapshot.problems.length) return null;
  const today = dsaSrsTodayString();
  const due = dsaSrsSortProblems(snapshot.problems.filter(p => p.dueDate && p.dueDate <= today));
  if (!due.length) return null;
  const cap = Number(snapshot.settings.dailyCap || 4);

  return (
    <div className="card" style={{marginBottom:'18px', borderColor:'var(--accent)'}}>
      <div className="card-h">
        <div>
          <div className="kicker">DSA Problem SRS</div>
          <div className="card-title">{due.length} reviews due</div>
        </div>
        <button className="btn primary" onClick={onOpen}>Start deck</button>
      </div>
      <div className="dsa-srs-today-mini">
        {due.slice(0, cap).map(problem => (
          <div key={problem.id} className="dsa-srs-mini-row">
            <span className="mono muted">{problem.topic}</span>
            <span>{problem.title}</span>
            <span className="mono muted">{dsaSrsPathLabel(problem.path || dsaSrsProblemPath(problem))}</span>
          </div>
        ))}
        {due.length > cap && <div className="mono muted">+ {due.length - cap} more due, carried forward safely</div>}
      </div>
    </div>
  );
}

window.DSARebuildView = DSARebuildView;
window.DsaSrsTodayPanel = DsaSrsTodayPanel;
