// page-waves.jsx — Bear Trap Wave Planner

const { useState: useStateW, useMemo: useMemoW, useCallback: useCallbackW, useEffect: useEffectW, useRef: useRefW } = React;

function btFreqTier(attended, total) {
  if (total === 0) return 'none';
  const r = attended / total;
  if (r >= 0.7) return 'high';
  if (r >= 0.4) return 'mid';
  if (r > 0)    return 'low';
  return 'none';
}

function WavesPage({ members, history, settings, distances, setDistance, notes, setNote, onToast, snapshotMeta }) {
  const now = new Date();

  // Wave state — persisted name + members per session
  const [waves, setWaves] = useStateW([
    { id: 'w1', name: 'Wave 1', members: [] },
    { id: 'w2', name: 'Wave 2', members: [] },
    { id: 'w3', name: 'Wave 3', members: [] },
  ]);

  // Saved BT strategies
  const [strategies, setStrategies] = useStateW(() => {
    try {
      const raw = localStorage.getItem('kingshot.strategies.v1');
      return raw ? JSON.parse(raw) : [];
    } catch { return []; }
  });
  const persistStrategies = (s) => {
    setStrategies(s);
    try { localStorage.setItem('kingshot.strategies.v1', JSON.stringify(s)); } catch {}
  };
  const saveStrategy = () => {
    const name = prompt('Strategy name?', `BT plan ${new Date().toLocaleDateString()}`);
    if (!name) return;
    const next = [...strategies, {
      id: `s-${Date.now()}`,
      name,
      savedAt: new Date().toISOString(),
      waves: waves.map(w => ({ name: w.name, members: [...w.members] })),
    }];
    persistStrategies(next);
    onToast(`Saved · ${name}`);
  };
  const loadStrategy = (s) => {
    setWaves(s.waves.map((w, i) => ({ id: `w-${Date.now()}-${i}`, name: w.name, members: [...w.members] })));
    onToast(`Loaded · ${s.name}`);
  };
  const deleteStrategy = (id) => {
    if (!confirm('Delete this strategy?')) return;
    persistStrategies(strategies.filter(s => s.id !== id));
  };

  const [sortKeys, setSortKeys] = useStateW([{ col: 'power', dir: 'desc' }]);
  const [search, setSearch] = useStateW('');
  const [freqFilter, setFreqFilter] = useStateW(new Set()); // empty = all
  const [assignedFilter, setAssignedFilter] = useStateW('all');
  const [confirm, setConfirm] = useStateW(null);

  const historyByMember = useMemoW(() => groupHistory(history), [history]);

  const augmented = useMemoW(() => {
    return members.map(m => {
      const h = historyByMember[m.id] || [];
      const act = computeActivity(m, h, settings, now);
      const manualDist = distances[m.id] !== undefined ? distances[m.id] : m.manual_distance;
      const marchSec = tilesToSeconds(manualDist, settings.marchSpeed);
      const btTier = btFreqTier(m.bt_attended || 0, m.bt_total || 10);
      const btRate = m.bt_total ? (m.bt_attended / m.bt_total) : 0;
      return {
        ...m,
        activity_level: act.level,
        manual_distance: manualDist,
        march_sec: marchSec,
        bt_tier: btTier,
        bt_rate: btRate,
      };
    });
  }, [members, historyByMember, settings, distances, Math.floor(now.getTime() / 60000)]);

  const maxPower = useMemoW(() => Math.max(...augmented.map(m => m.power)), [augmented]);

  const filtered = useMemoW(() => {
    let r = augmented;
    if (search.trim()) {
      const q = search.trim().toLowerCase();
      r = r.filter(m => m.nickname.toLowerCase().includes(q) || (notes[m.id] || '').toLowerCase().includes(q));
    }
    if (freqFilter.size > 0) {
      r = r.filter(m => freqFilter.has(m.bt_tier));
    }
    if (assignedFilter !== 'all') {
      const assignedIds = new Set(waves.flatMap(w => w.members));
      if (assignedFilter === 'assigned')   r = r.filter(m => assignedIds.has(m.id));
      if (assignedFilter === 'unassigned') r = r.filter(m => !assignedIds.has(m.id));
    }
    const sorted = [...r];
    sorted.sort((a, b) => {
      for (const { col, dir } of sortKeys) {
        let av = a[col], bv = b[col];
        if (col === 'last_login') { av = new Date(av).getTime(); bv = new Date(bv).getTime(); }
        if (col === 'bt_tier') {
          const order = { high: 0, mid: 1, low: 2, none: 3 };
          av = order[av] ?? 4; bv = order[bv] ?? 4;
        }
        if (av == null) av = -Infinity;
        if (bv == null) bv = -Infinity;
        if (av < bv) return dir === 'asc' ? -1 : 1;
        if (av > bv) return dir === 'asc' ?  1 : -1;
      }
      return 0;
    });
    return sorted;
  }, [augmented, search, freqFilter, assignedFilter, sortKeys, waves, notes]);

  const findWaveOf = useCallbackW((memberId) => {
    for (const w of waves) if (w.members.includes(memberId)) return w.id;
    return null;
  }, [waves]);

  const toggleWave = useCallbackW((memberId, waveId, altKey = false) => {
    const currentWave = findWaveOf(memberId);
    if (currentWave === waveId) {
      setWaves(ws => ws.map(w => w.id === waveId ? { ...w, members: w.members.filter(id => id !== memberId) } : w));
      return;
    }
    if (currentWave && currentWave !== waveId) {
      if (altKey) {
        setWaves(ws => ws.map(w => {
          if (w.id === currentWave) return { ...w, members: w.members.filter(id => id !== memberId) };
          if (w.id === waveId)      return { ...w, members: [...w.members, memberId] };
          return w;
        }));
      } else {
        setConfirm({ memberId, fromWave: currentWave, toWave: waveId });
      }
      return;
    }
    setWaves(ws => ws.map(w => w.id === waveId ? { ...w, members: [...w.members, memberId] } : w));
  }, [findWaveOf]);

  const confirmMove = useCallbackW(() => {
    if (!confirm) return;
    const { memberId, fromWave, toWave } = confirm;
    setWaves(ws => ws.map(w => {
      if (w.id === fromWave) return { ...w, members: w.members.filter(id => id !== memberId) };
      if (w.id === toWave)   return { ...w, members: [...w.members, memberId] };
      return w;
    }));
    setConfirm(null);
  }, [confirm]);

  const addWave = () => {
    if (waves.length >= 10) { onToast('Max 10 waves'); return; }
    const n = waves.length + 1;
    setWaves(ws => [...ws, { id: `w${Date.now()}`, name: `Wave ${n}`, members: [] }]);
  };
  const removeWave = (id) => setWaves(ws => ws.filter(w => w.id !== id));
  const renameWave = (id, name) =>
    setWaves(ws => ws.map(w => w.id === id ? { ...w, name: name || `Wave ${ws.indexOf(w) + 1}` } : w));
  const removeFromWave = (waveId, memberId) =>
    setWaves(ws => ws.map(w => w.id === waveId ? { ...w, members: w.members.filter(id => id !== memberId) } : w));
  const clearWave = (id) => setWaves(ws => ws.map(w => w.id === id ? { ...w, members: [] } : w));

  const buildExport = useCallbackW(() => {
    const dateStr = new Date().toISOString().slice(0, 10);
    const timeStr = formatServerTime(new Date(), settings.tzOffsetHrs || 0);
    let out = `🐻 BEAR TRAP — ${dateStr} ${timeStr} SVR\n\n`;
    const memberById = Object.fromEntries(augmented.map(m => [m.id, m]));
    let totalCount = 0;
    let grandTotal = 0;
    waves.forEach(w => {
      const mems = w.members.map(id => memberById[id]).filter(Boolean);
      const totalPower = mems.reduce((s, m) => s + m.power, 0);
      totalCount += mems.length;
      grandTotal += totalPower;
      out += `${w.name} (${mems.length} members · ${formatPower(totalPower)})\n`;
      if (mems.length === 0) {
        out += `  (empty)\n\n`;
      } else {
        mems.forEach(m => {
          const sec = m.march_sec != null ? formatMarchTime(m.march_sec) : '—';
          out += `  ${m.nickname.padEnd(12)} ${formatPower(m.power).padStart(8)}   march ${sec}\n`;
        });
        out += '\n';
      }
    });
    out += `Total: ${totalCount} members across ${waves.length} waves · Combined ${formatPower(grandTotal)}`;
    return out;
  }, [waves, augmented, settings.tzOffsetHrs]);

  const handleExport = async () => {
    const text = buildExport();
    await copyText(text);
    const empties = waves.filter(w => w.members.length === 0).length;
    if (empties > 0) onToast(`Copied — but ${empties} wave${empties > 1 ? 's are' : ' is'} empty`);
    else onToast(`Copied — ${waves.reduce((s, w) => s + w.members.length, 0)} members across ${waves.length} waves`);
  };

  const handleCopyOne = async (w) => {
    const memberById = Object.fromEntries(augmented.map(m => [m.id, m]));
    const mems = w.members.map(id => memberById[id]).filter(Boolean);
    const totalPower = mems.reduce((s, m) => s + m.power, 0);
    let out = `${w.name} (${mems.length} members · ${formatPower(totalPower)})\n`;
    mems.forEach(m => {
      const sec = m.march_sec != null ? formatMarchTime(m.march_sec) : '—';
      out += `  ${m.nickname.padEnd(12)} ${formatPower(m.power).padStart(8)}  ${sec}\n`;
    });
    await copyText(out);
    onToast(`Copied ${w.name}`);
  };

  const handleSort = (col) => {
    setSortKeys(prev => {
      const existing = prev.find(s => s.col === col);
      if (existing) {
        if (existing.dir === 'desc') return prev.map(s => s.col === col ? { ...s, dir: 'asc' } : s);
        return prev.filter(s => s.col !== col);
      }
      return [{ col, dir: 'desc' }, ...prev].slice(0, 3);
    });
  };

  const sortInd = (col) => {
    const idx = sortKeys.findIndex(s => s.col === col);
    if (idx === -1) return null;
    return <span className="sort-ind">{idx + 1}{sortKeys[idx].dir === 'desc' ? '↓' : '↑'}</span>;
  };

  const toggleFreqFilter = (tier) => {
    setFreqFilter(prev => {
      const n = new Set(prev);
      if (n.has(tier)) n.delete(tier); else n.add(tier);
      return n;
    });
  };

  const memberById = useMemoW(() => Object.fromEntries(augmented.map(m => [m.id, m])), [augmented]);
  const confirmMemberName = confirm ? memberById[confirm.memberId]?.nickname : '';
  const confirmFromName = confirm ? (waves.find(w => w.id === confirm.fromWave)?.name) : '';
  const confirmToName = confirm ? (waves.find(w => w.id === confirm.toWave)?.name) : '';

  const snapAgeH = (now.getTime() - new Date(snapshotMeta.last_sync).getTime()) / 3600000;
  const stale = snapAgeH > 36;

  // Total assigned for save-button disabled state
  const totalAssigned = waves.reduce((s, w) => s + w.members.length, 0);

  return (
    <div className="page">
      {stale && (
        <div className="banner">
          Snapshot is {Math.round(snapAgeH)}h old. Power numbers may be outdated.
        </div>
      )}

      {/* Strategies bar */}
      <div className="strat-bar">
        <span className="lbl">Saved strategies</span>
        {strategies.length === 0 ? (
          <span className="muted" style={{ fontSize: 11, fontFamily: 'var(--font-mono)' }}>none yet</span>
        ) : (
          strategies.map(s => (
            <span key={s.id} className="strat-pill" onClick={() => loadStrategy(s)}>
              {s.name}
              <span className="muted" style={{ fontSize: 9 }}>{s.waves.reduce((n, w) => n + w.members.length, 0)}m</span>
              <button className="x" onClick={(e) => { e.stopPropagation(); deleteStrategy(s.id); }}>×</button>
            </span>
          ))
        )}
        <span style={{ flex: 1 }}></span>
        <button className="btn ghost" onClick={saveStrategy} disabled={totalAssigned === 0}>
          + Save current
        </button>
      </div>

      <div className="waves-layout">
        {/* LEFT — Pool */}
        <div className="pool">
          <div className="pool-toolbar">
            <div className="searchbox">
              <input
                placeholder="Search nick or notes…"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
              />
            </div>
            {[
              { id: 'high', l: 'High freq' },
              { id: 'mid',  l: 'Mid freq' },
              { id: 'low',  l: 'Low' },
              { id: 'none', l: 'Never' },
            ].map(({ id, l }) => (
              <span
                key={id}
                className="chip"
                data-level={id === 'high' ? 'active' : id === 'mid' ? 'normal' : id === 'low' ? 'dormant' : 'lost'}
                data-on={freqFilter.has(id)}
                onClick={() => toggleFreqFilter(id)}
              >
                <span className="dot"></span>
                {l}
              </span>
            ))}
            <span style={{ flex: 1 }}></span>
            <span
              className="chip"
              data-on={assignedFilter === 'unassigned'}
              onClick={() => setAssignedFilter(assignedFilter === 'unassigned' ? 'all' : 'unassigned')}
            >Unassigned</span>
            <span
              className="chip"
              data-on={assignedFilter === 'assigned'}
              onClick={() => setAssignedFilter(assignedFilter === 'assigned' ? 'all' : 'assigned')}
            >Assigned</span>
          </div>
          <div style={{ overflow: 'auto', maxHeight: 'calc(100vh - 240px)' }}>
            <table className="tbl">
              <thead>
                <tr>
                  <th className="no-sort" style={{ width: waves.length * 24 + 24 }}>
                    {waves.map((w, i) => (
                      <span key={w.id} style={{
                        display: 'inline-block', width: 22, textAlign: 'center',
                        fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-3)',
                      }}>W{i + 1}</span>
                    ))}
                  </th>
                  <th onClick={() => handleSort('nickname')}>Nick {sortInd('nickname')}</th>
                  <th className="right" onClick={() => handleSort('power')}>PWR {sortInd('power')}</th>
                  <th onClick={() => handleSort('last_login')}>Login {sortInd('last_login')}</th>
                  <th onClick={() => handleSort('bt_tier')}>BT Freq {sortInd('bt_tier')}</th>
                  <th className="right" onClick={() => handleSort('march_sec')}>March {sortInd('march_sec')}</th>
                  <th className="no-sort">Hero notes</th>
                </tr>
              </thead>
              <tbody>
                {filtered.length === 0 ? (
                  <tr><td colSpan="7" style={{ padding: 24, textAlign: 'center', color: 'var(--fg-3)' }}>
                    No matches.
                  </td></tr>
                ) : filtered.map(m => {
                  const currentWave = findWaveOf(m.id);
                  return (
                    <tr key={m.id}>
                      <td>
                        <span className="wcheck-cell">
                          {waves.map(w => (
                            <span
                              key={w.id}
                              className="wbox"
                              data-on={currentWave === w.id}
                              onClick={(e) => toggleWave(m.id, w.id, e.altKey)}
                              title={`Toggle ${w.name} (Alt+click to skip confirm)`}
                            >{currentWave === w.id ? '✓' : ''}</span>
                          ))}
                        </span>
                      </td>
                      <td><span className="nick">{m.nickname}</span></td>
                      <td className="right num">
                        <span className="fl-cell">
                          <span className="fl-bar"><i style={{ width: `${(m.power / maxPower) * 100}%` }}></i></span>
                          <span>{formatPower(m.power)}</span>
                        </span>
                      </td>
                      <td className="num" title={m.last_login ? new Date(m.last_login).toUTCString() : 'never'}>
                        {m.last_login ? formatRelativePast(m.last_login, now) : <span className="muted">never</span>}
                      </td>
                      <td>
                        <span className="btfreq" data-tier={m.bt_tier} title={`${m.bt_attended || 0} of last ${m.bt_total || 10} Bear Traps`}>
                          {m.bt_attended || 0}/{m.bt_total || 10}
                          <span className="btfreq-bar"><i style={{ width: `${m.bt_rate * 100}%` }}></i></span>
                        </span>
                      </td>
                      <td className="right num" title={m.manual_distance != null ? `${m.manual_distance} tiles @ ${settings.marchSpeed} t/s` : ''}>
                        <InlineEdit
                          value={m.manual_distance}
                          onChange={(v) => setDistance(m.id, v)}
                          numeric
                          placeholder="—"
                        />
                        {m.march_sec != null && (
                          <div style={{ fontSize: 9, color: 'var(--fg-4)', marginTop: -2 }}>
                            {formatMarchTime(m.march_sec)}
                          </div>
                        )}
                      </td>
                      <td className="notes-cell">
                        <InlineNotes
                          value={notes[m.id] || ''}
                          onChange={(v) => setNote(m.id, v)}
                        />
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>

        {/* RIGHT — Wave summary */}
        <div className="wave-summary">
          {waves.map((w, i) => {
            const mems = w.members.map(id => memberById[id]).filter(Boolean);
            const totalPower = mems.reduce((s, m) => s + m.power, 0);
            const totalSec = mems.reduce((s, m) => s + (m.march_sec || 0), 0);
            const longestSec = mems.reduce((mx, m) => Math.max(mx, m.march_sec || 0), 0);
            return (
              <div key={w.id} className="wave-card">
                <div className="wave-card-hd">
                  <span className="badge">W{i + 1}</span>
                  <span
                    className="wname"
                    contentEditable
                    suppressContentEditableWarning
                    onBlur={(e) => renameWave(w.id, e.currentTarget.innerText.trim())}
                    onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); e.currentTarget.blur(); } }}
                  >{w.name}</span>
                  <span className="stats">
                    <b>{mems.length}</b> mem
                    <span className="muted">·</span>
                    <b>{formatPower(totalPower)}</b>
                  </span>
                </div>
                {mems.length > 0 && longestSec > 0 && (
                  <div style={{
                    padding: '6px 12px', fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)',
                    background: 'var(--bg)', borderBottom: '1px solid var(--border-soft)',
                  }}>
                    Slowest march: <span style={{ color: 'var(--fg)' }}>{formatMarchTime(longestSec)}</span>
                  </div>
                )}
                <div className={`wave-members ${mems.length === 0 ? 'empty-state' : ''}`}>
                  {mems.length === 0 ? 'No members assigned' : mems.map(m => (
                    <div key={m.id} className="wave-member">
                      <span className="n">
                        {m.nickname}
                        {notes[m.id] && (
                          <span title={notes[m.id]} style={{ color: 'var(--accent)', marginLeft: 5, fontSize: 9 }}>★</span>
                        )}
                      </span>
                      <span className="fl">{formatPower(m.power)} · {m.march_sec != null ? formatMarchTime(m.march_sec) : '—'}</span>
                      <button className="x" onClick={() => removeFromWave(w.id, m.id)}>×</button>
                    </div>
                  ))}
                </div>
                <div className="wave-card-ft">
                  <button className="btn ghost" onClick={() => handleCopyOne(w)} disabled={mems.length === 0}>Copy this</button>
                  <button className="btn ghost" onClick={() => clearWave(w.id)} disabled={mems.length === 0}>Clear</button>
                  <span style={{ flex: 1 }}></span>
                  <button className="btn ghost" onClick={() => removeWave(w.id)} disabled={waves.length <= 1}>Remove</button>
                </div>
              </div>
            );
          })}

          <button className="add-wave" onClick={addWave}>+ ADD WAVE</button>

          <div className="export-btn-wrap">
            <button className="btn primary" style={{ width: '100%', justifyContent: 'center', padding: '10px' }} onClick={handleExport}>
              EXPORT ALL → DISCORD
            </button>
          </div>
        </div>
      </div>

      <ConfirmDialog
        open={!!confirm}
        message={confirm ? <>Move <b>{confirmMemberName}</b> from {confirmFromName} to {confirmToName}?<br/><span className="muted" style={{ fontSize: 11 }}>Hold Alt while clicking to skip this prompt.</span></> : ''}
        onCancel={() => setConfirm(null)}
        onConfirm={confirmMove}
        confirmLabel="Move"
      />
    </div>
  );
}

// Inline editor for hero notes (free-text per member)
function InlineNotes({ value, onChange }) {
  const handleBlur = (e) => { onChange(e.currentTarget.innerText.trim()); };
  const handleKey = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); e.currentTarget.blur(); }
    if (e.key === 'Escape') {
      e.preventDefault();
      e.currentTarget.innerText = value || '';
      e.currentTarget.blur();
    }
  };
  return (
    <span
      className={`notes-edit ${value ? '' : 'empty'}`}
      contentEditable
      suppressContentEditableWarning
      onBlur={handleBlur}
      onKeyDown={handleKey}
      title={value || 'Click to add note'}
    >{value || 'add note…'}</span>
  );
}

Object.assign(window, { WavesPage });
