/* ============================================================
   page-monthly.jsx — Summary: heatmap + scoreboard + progress + violations
   ============================================================ */

/* Status color mapping for heatmap cells */
function hmColor(status) {
  if (status === 'present') return 'var(--ok)';
  if (status === 'late')    return 'var(--warn)';
  if (status === 'absent')  return 'var(--err)';
  if (status === 'pto')     return 'var(--brand)';
  if (status === 'sick')    return '#a855f7';
  if (status === 'off_day' || status === 'weekend') return 'var(--bg-elev-2)';
  return 'var(--bg-elev-3)'; // no-data
}

function Lgnd({ c, l, outline }) {
  return (
    <span style={{ display:'inline-flex', alignItems:'center', gap: 4 }}>
      <span style={{ width: 10, height: 10, borderRadius: 2, background: c, border: outline ? '1px dashed var(--line)' : 'none' }} />
      {l}
    </span>
  );
}

/* ── Heatmap section ── */
/* ── Calendar Edit modal (Admin Edit Phase 3) ──
   One inline overlay reused for: (1) "what would you like to do" picker,
   (2) add company holiday, (3) add PTO for user, (4) remove holiday.
*/
function CalendarEditModal({ open, ctx, onClose, onSaved, toast, meRole, users }) {
  const [mode, setMode] = useState('pick'); // 'pick' | 'holiday' | 'pto' | 'remove'
  const [name, setName] = useState('');
  const [userId, setUserId] = useState('');
  const [ptoType, setPtoType] = useState('vacation');
  const [endDate, setEndDate] = useState('');
  const [reason, setReason] = useState('');
  const [busy, setBusy] = useState(false);

  useEffect(() => {
    if (!open) return;
    setBusy(false);
    setName('');
    setReason('');
    setEndDate(ctx?.date || '');
    setPtoType('vacation');
    if (ctx?.userId) setUserId(String(ctx.userId));
    // Auto-route: if cell already has a holiday, jump to remove confirm.
    if (ctx?.holiday) setMode('remove');
    else if (ctx?.userId) setMode('pto');
    else setMode('pick');
  }, [open, ctx]);

  if (!open) return null;
  const isAdmin = (meRole || '').toLowerCase() === 'admin';
  const date = ctx?.date || '';

  const close = () => { if (!busy) onClose(); };
  const showUndo = (token, label) => {
    if (token && typeof window.showUndoToast === 'function') {
      window.showUndoToast({ token, label, onUndone: onSaved });
    }
  };

  const submitHoliday = async () => {
    if (!name.trim()) { toast.push({ msg: (window.appT||(s=>s))('Holiday name required'), kind: 'err' }); return; }
    setBusy(true);
    try {
      const r = await fetch('/api/company-holidays', {
        method: 'POST', credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ date, name: name.trim() }),
      });
      const j = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(j.detail || `HTTP ${r.status}`);
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تمت إضافة العطلة "${name.trim()}" في ${date}` : `Holiday "${name.trim()}" added on ${date}`, kind: 'ok' });
      showUndo(j.undo_token, (window.appLang&&window.appLang()==='ar') ? `تمت إضافة عطلة في ${date}` : `Holiday added on ${date}`);
      onSaved();
      onClose();
    } catch(e) { toast.push({ msg: (window.appT||(s=>s))('Add holiday failed: ') + e.message, kind: 'err' }); }
    finally { setBusy(false); }
  };

  const submitRemoveHoliday = async () => {
    if (!ctx?.holiday?.id) return;
    setBusy(true);
    try {
      const r = await fetch(`/api/company-holidays/${ctx.holiday.id}`, {
        method: 'DELETE', credentials: 'same-origin',
      });
      const j = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(j.detail || `HTTP ${r.status}`);
      toast.push({ msg: (window.appT||(s=>s))('Holiday removed'), kind: 'ok' });
      showUndo(j.undo_token, (window.appLang&&window.appLang()==='ar') ? `تمت إزالة العطلة من ${date}` : `Holiday removed from ${date}`);
      onSaved();
      onClose();
    } catch(e) { toast.push({ msg: (window.appT||(s=>s))('Remove holiday failed: ') + e.message, kind: 'err' }); }
    finally { setBusy(false); }
  };

  const submitPto = async () => {
    if (!userId) { toast.push({ msg: (window.appT||(s=>s))('Pick a user'), kind: 'err' }); return; }
    if (!endDate || endDate < date) { toast.push({ msg: (window.appT||(s=>s))('End date must be ≥ start'), kind: 'err' }); return; }
    setBusy(true);
    try {
      const r = await fetch('/api/pto', {
        method: 'POST', credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          user_id: parseInt(userId, 10),
          pto_type: ptoType,
          start_date: date,
          end_date: endDate,
          reason: reason.trim() || null,
          approved: true,
        }),
      });
      const j = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(j.detail || `HTTP ${r.status}`);
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تمت إضافة إجازة للمستخدم ${userId}` : `PTO added for user ${userId}`, kind: 'ok' });
      showUndo(j.undo_token, (window.appLang&&window.appLang()==='ar') ? `تمت إضافة إجازة (${ptoType}) في ${date}` : `PTO (${ptoType}) added on ${date}`);
      onSaved();
      onClose();
    } catch(e) { toast.push({ msg: (window.appT||(s=>s))('Add PTO failed: ') + e.message, kind: 'err' }); }
    finally { setBusy(false); }
  };

  const overlay = {
    position:'fixed', inset:0, background:'rgba(0,0,0,.55)', zIndex:9000,
    display:'flex', alignItems:'center', justifyContent:'center', padding:20,
  };
  const card = {
    background:'var(--bg-elev-1)', border:'1px solid var(--line)', borderRadius:'var(--r-md)',
    padding:18, minWidth:340, maxWidth:480, color:'var(--text)',
    boxShadow:'0 8px 32px rgba(0,0,0,.4)',
  };
  const inputStyle = { width:'100%', padding:'6px 8px', background:'var(--bg-elev-2)', color:'var(--text)', border:'1px solid var(--line)', borderRadius:4, fontSize:13 };
  const btn = (kind) => ({ padding:'6px 12px', borderRadius:4, border:'1px solid var(--line)', cursor:'pointer', fontSize:12, fontWeight:600, background: kind==='primary' ? 'var(--brand)' : 'transparent', color: kind==='primary' ? '#fff' : 'var(--text)' });

  return (
    <div style={overlay} onClick={close}>
      <div style={card} onClick={e => e.stopPropagation()}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:12 }}>
          <strong>{mode === 'remove' ? (window.appT||(s=>s))('Remove holiday') : mode === 'holiday' ? (window.appT||(s=>s))('Add company holiday') : mode === 'pto' ? (window.appT||(s=>s))('Add PTO') : (window.appT||(s=>s))('Edit calendar')}</strong>
          <span className="muted" style={{ fontSize:11, fontFamily:'var(--font-mono)' }}>{date}</span>
        </div>

        {mode === 'pick' && (
          <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
            {isAdmin && (
              <button style={btn()} onClick={() => setMode('holiday')}>{(window.appT||(s=>s))('Add company holiday')}</button>
            )}
            <button style={btn()} onClick={() => setMode('pto')}>{(window.appT||(s=>s))('Add PTO for a user…')}</button>
            {!isAdmin && <div className="muted" style={{ fontSize:11 }}>{(window.appT||(s=>s))('Only admins can add company holidays.')}</div>}
          </div>
        )}

        {mode === 'holiday' && (
          <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
            <label style={{ fontSize:12 }}>{(window.appT||(s=>s))('Name')}
              <input style={inputStyle} placeholder={(window.appT||(s=>s))('e.g. Labor Day')} value={name} onChange={e => setName(e.target.value)} autoFocus />
            </label>
            <div style={{ display:'flex', justifyContent:'flex-end', gap:8 }}>
              <button style={btn()} onClick={close} disabled={busy}>{(window.appT||(s=>s))('Cancel')}</button>
              <button style={btn('primary')} onClick={submitHoliday} disabled={busy}>{busy ? (window.appT||(s=>s))('Saving…') : (window.appT||(s=>s))('Add holiday')}</button>
            </div>
          </div>
        )}

        {mode === 'remove' && (
          <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
            <div>{(window.appT||(s=>s))('Remove holiday')} <strong>{ctx?.holiday?.name}</strong> {(window.appT||(s=>s))('on')} <span className="mono">{date}</span>?</div>
            {!isAdmin && <div className="muted" style={{ fontSize:11 }}>{(window.appT||(s=>s))('Only admins can remove company holidays.')}</div>}
            <div style={{ display:'flex', justifyContent:'flex-end', gap:8 }}>
              <button style={btn()} onClick={close} disabled={busy}>{(window.appT||(s=>s))('Cancel')}</button>
              <button style={btn('primary')} onClick={submitRemoveHoliday} disabled={busy || !isAdmin}>{busy ? (window.appT||(s=>s))('Removing…') : (window.appT||(s=>s))('Remove')}</button>
            </div>
          </div>
        )}

        {mode === 'pto' && (
          <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
            <label style={{ fontSize:12 }}>{(window.appT||(s=>s))('User')}
              <select style={inputStyle} value={userId} onChange={e => setUserId(e.target.value)}>
                <option value="">{(window.appT||(s=>s))('— pick —')}</option>
                {users.map(u => <option key={u.id} value={u.id}>{u.display_name || u.matrix_id}</option>)}
              </select>
            </label>
            <label style={{ fontSize:12 }}>{(window.appT||(s=>s))('Type')}
              <select style={inputStyle} value={ptoType} onChange={e => setPtoType(e.target.value)}>
                <option value="vacation">{(window.appT||(s=>s))('Vacation')}</option>
                <option value="pto">{(window.appT||(s=>s))('PTO')}</option>
                <option value="sick">{(window.appT||(s=>s))('Sick')}</option>
                <option value="personal">{(window.appT||(s=>s))('Personal')}</option>
                <option value="half_day">{(window.appT||(s=>s))('Half day')}</option>
                <option value="holiday">{(window.appT||(s=>s))('Holiday')}</option>
              </select>
            </label>
            <label style={{ fontSize:12 }}>{(window.appT||(s=>s))('End date')}
              <input type="date" style={inputStyle} value={endDate} min={date} onChange={e => setEndDate(e.target.value)} />
            </label>
            <label style={{ fontSize:12 }}>{(window.appT||(s=>s))('Reason (optional)')}
              <input style={inputStyle} value={reason} onChange={e => setReason(e.target.value)} />
            </label>
            <div style={{ display:'flex', justifyContent:'flex-end', gap:8 }}>
              <button style={btn()} onClick={close} disabled={busy}>{(window.appT||(s=>s))('Cancel')}</button>
              <button style={btn('primary')} onClick={submitPto} disabled={busy}>{busy ? (window.appT||(s=>s))('Saving…') : (window.appT||(s=>s))('Add PTO')}</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function SummaryHeatmap({ month, search }) {
  const [rows, setRows]     = useState([]);
  const [loading, setLoading] = useState(false);
  const [holidays, setHolidays] = useState([]); // [{id, date, name}]
  const [users, setUsers] = useState([]);
  const [me, setMe] = useState(null);
  const [editCtx, setEditCtx] = useState(null); // {date, userId?, holiday?} | null
  const [span, setSpan] = useState(1); // #23: 1 / 3 / 6 / 12-month window
  const editMode = (typeof window.useEditMode === 'function') ? window.useEditMode() : false;
  const toast = useToast();

  const fetchData = async (m) => {
    setLoading(true);
    try {
      const r = await fetch(`/api/summary/heatmap?month=${m}&months=${span}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const data = await r.json();
      setRows(Array.isArray(data) ? data : []);
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Heatmap fetch failed: ') + e.message, kind: 'err' });
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  const fetchHolidays = async (m) => {
    try {
      const [y, mo] = m.split('-').map(Number);
      const last = new Date(y, mo, 0).getDate();
      const from = `${m}-01`;
      const to = `${m}-${String(last).padStart(2, '0')}`;
      const r = await fetch(`/api/company-holidays?from=${from}&to=${to}`, { credentials: 'same-origin' });
      if (!r.ok) { setHolidays([]); return; }
      const data = await r.json();
      setHolidays(Array.isArray(data) ? data : []);
    } catch { setHolidays([]); }
  };

  const fetchUsers = async () => {
    try {
      const r = await fetch('/api/employees', { credentials: 'same-origin' });
      if (!r.ok) return;
      const data = await r.json();
      setUsers(Array.isArray(data) ? data : []);
    } catch {}
  };

  const fetchMe = async () => {
    try {
      const r = await fetch('/api/auth/me', { credentials: 'same-origin' });
      if (r.ok) setMe(await r.json());
    } catch {}
  };

  useEffect(() => { fetchData(month); fetchHolidays(month); }, [month, span]);
  useEffect(() => { fetchUsers(); fetchMe(); }, []);

  const holidayByDate = {};
  for (const h of holidays) holidayByDate[h.date] = h;

  const handleCellClick = (cellDate, userId) => {
    if (!editMode) return;
    const ho = holidayByDate[cellDate] || null;
    setEditCtx({ date: cellDate, userId, holiday: ho });
  };

  const filteredRows = search
    ? rows.filter(r => (r.display_name || '').toLowerCase().includes(search.toLowerCase()))
    : rows;

  if (loading) {
    return <div className="muted" style={{ padding: 20, fontSize: 13 }}>{(window.appT||(s=>s))('Loading heatmap…')}</div>;
  }

  if (!filteredRows.length) {
    return <Empty icon={<Icon name="chart" size={24}/>} title={(window.appT||(s=>s))('No heatmap data')} subtitle={search ? (window.appT||(s=>s))('No matching employees.') : (window.appT||(s=>s))('No attendance data for this month.')} />;
  }

  // Per-user calendar grid. For each user, build a 7-col × N-row month layout.
  // Days before 1st (filler) align by weekday-of-first-day.
  const DOW = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
  const multi = span > 1;          // multi-month: compact cells, hide day numbers
  const cellH = multi ? 13 : 30;
  return (
    <div>
      <SectionHeader
        title={(window.appT||(s=>s))('Attendance calendar — per user')}
          tip={(window.appT||(s=>s))('Heatmap of every employee × every day over the selected window (1/3/6/12 months). Color encodes status: green on-time, yellow late, red absent, blue PTO, hatched holiday, grey off-day.')}
        sub={(window.appLang&&window.appLang()==='ar') ? `${span === 1 ? month : `${span} أشهر تنتهي في ${month}`} · اختر نافذة لاكتشاف الأنماط طويلة المدى` : `${span === 1 ? month : `${span} months ending ${month}`} · pick a window to spot longer-term patterns`}
        right={
          <div style={{ display:'flex', gap: 10, fontSize: 11.5, color:'var(--text-2)', alignItems:'center', flexWrap:'wrap' }}>
            <select className="sel" value={span} onChange={e => setSpan(Number(e.target.value))}
              title={(window.appT||(s=>s))('Heatmap window')}
              style={{ fontSize: 11.5, padding: '2px 6px' }}>
              <option value={1}>{(window.appT||(s=>s))('1 month')}</option>
              <option value={3}>{(window.appT||(s=>s))('3 months')}</option>
              <option value={6}>{(window.appT||(s=>s))('6 months')}</option>
              <option value={12}>{(window.appT||(s=>s))('1 year')}</option>
            </select>
            <Lgnd c="var(--ok)"       l={(window.appT||(s=>s))('present')} />
            <Lgnd c="var(--warn)"     l={(window.appT||(s=>s))('late')} />
            <Lgnd c="var(--err)"      l={(window.appT||(s=>s))('absent')} />
            <Lgnd c="var(--brand)"    l={(window.appT||(s=>s))('pto')} />
            <Lgnd c="#a855f7"         l={(window.appT||(s=>s))('sick')} />
            <Lgnd c="var(--bg-elev-2)" l={(window.appT||(s=>s))('off-day')} outline />
          </div>
        }
      />
      <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))', gap: 12, marginTop: 12 }}>
        {filteredRows.map(row => {
          const totalHrs = row.days.reduce((s, d) => s + (d.hours || 0), 0);
          const present = row.days.filter(d => d.status === 'present').length;
          const late    = row.days.filter(d => d.status === 'late').length;
          const absent  = row.days.filter(d => d.status === 'absent').length;
          const firstDate = row.days[0]?.date;
          const firstDow = firstDate ? new Date(firstDate + 'T00:00:00').getDay() : 0;
          const cells = [];
          for (let i = 0; i < firstDow; i++) cells.push(null);
          for (const d of row.days) cells.push(d);
          // pad to multiple of 7
          while (cells.length % 7 !== 0) cells.push(null);
          return (
            <div key={row.user_id} style={{ background:'var(--bg-elev-2)', border:'1px solid var(--line)', borderRadius:'var(--r-md)', padding: 12 }}>
              <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom: 8 }}>
                <strong style={{ fontSize: 13 }}>{row.display_name}</strong>
                <span className="mono" style={{ fontSize: 11, color:'var(--text-2)' }}>{totalHrs.toFixed(0)}h</span>
              </div>
              <div style={{ display:'grid', gridTemplateColumns:'repeat(7, 1fr)', gap: 3, marginBottom: 6 }}>
                {DOW.map(d => (
                  <div key={d} style={{ fontSize: 9, color:'var(--text-3)', textAlign:'center', fontFamily:'var(--font-mono)' }}>{d.charAt(0)}</div>
                ))}
                {cells.map((d, i) => {
                  if (!d) return <div key={i} />;
                  const exceptions = (d.exceptions || []).join(', ');
                  const dayNum = parseInt(d.date.slice(8), 10);
                  const ho = holidayByDate[d.date];
                  const tip = `${d.date} · ${d.status}${d.hours ? ` · ${d.hours.toFixed(1)}h` : ''}${exceptions ? ` · ${exceptions}` : ''}${ho ? ` · 🎌 ${ho.name}` : ''}${editMode ? ((window.appLang&&window.appLang()==='ar') ? ' · انقر للتعديل' : ' · click to edit') : ''}`;
                  const bg = hmColor(d.status);
                  const isOff = d.status === 'off_day' || d.status === 'weekend';
                  const isAbsent = d.status === 'absent';
                  return (
                    <div key={i} title={tip}
                      onClick={editMode ? () => handleCellClick(d.date, row.user_id) : undefined}
                      style={{
                        height: cellH, borderRadius: 4,
                        background: bg, opacity: isOff ? 0.35 : 1,
                        display:'flex', alignItems:'center', justifyContent:'center',
                        fontSize: 10, fontFamily:'var(--font-mono)',
                        color: isAbsent ? '#fff' : isOff ? 'var(--text-3)' : '#fff',
                        fontWeight: isAbsent ? 600 : 500,
                        cursor: editMode ? 'pointer' : 'help',
                        outline: editMode ? '1px dashed var(--brand)' : 'none',
                        outlineOffset: editMode ? -1 : 0,
                        position: 'relative',
                      }}>
                      {multi ? '' : dayNum}
                      {ho && !multi && (
                        <span title={ho.name} style={{ position:'absolute', top:1, right:2, fontSize:8, lineHeight:1 }}>🎌</span>
                      )}
                    </div>
                  );
                })}
              </div>
              <div style={{ display:'flex', justifyContent:'space-between', fontSize: 10.5, color:'var(--text-2)', marginTop: 4 }}>
                <span><span style={{color:'var(--ok)'}}>●</span> {present}p</span>
                <span><span style={{color:'var(--warn)'}}>●</span> {late}L</span>
                <span><span style={{color:'var(--err)'}}>●</span> {absent}a</span>
              </div>
            </div>
          );
        })}
      </div>
      <CalendarEditModal
        open={!!editCtx}
        ctx={editCtx}
        onClose={() => setEditCtx(null)}
        onSaved={() => { fetchHolidays(month); fetchData(month); }}
        toast={toast}
        meRole={me?.org_role}
        users={users}
      />
    </div>
  );
}

/* ── Scoreboard section ── */
function SummaryScoreboard({ period, search, refreshTick }) {
  const [rows, setRows]     = useState([]);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  const fetchData = async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({ period });
      if (search) params.set('search', search);
      const r = await fetch(`/api/summary/scoreboard?${params}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const data = await r.json();
      setRows(Array.isArray(data) ? data : []);
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Scoreboard fetch failed: ') + e.message, kind: 'err' });
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { fetchData(); }, [period, search, refreshTick]);

  const { sorted, sort, click } = useSortable(rows, { key: 'total_hours', dir: 'desc' });

  if (loading) return <div className="muted" style={{ padding: 12, fontSize: 13 }}>{(window.appT||(s=>s))('Loading scoreboard…')}</div>;
  if (!sorted.length) return <Empty icon={<Icon name="chart" size={24}/>} title={(window.appT||(s=>s))('No scoreboard data')} subtitle={(window.appT||(s=>s))('No activity in this period.')} />;

  return (
    <table className="t">
      <thead>
        <tr>
          <SortHead sort={sort} sortKey="display_name" click={click} label={(window.appT||(s=>s))('Person')} />
          <SortHead sort={sort} sortKey="days_present"  click={click} label={(window.appT||(s=>s))('Present')} align="right" />
          <SortHead sort={sort} sortKey="days_late"     click={click} label={(window.appT||(s=>s))('Late')}    align="right" />
          <SortHead sort={sort} sortKey="days_absent"   click={click} label={(window.appT||(s=>s))('Absent')}  align="right" />
          <SortHead sort={sort} sortKey="total_hours"   click={click} label={(window.appT||(s=>s))('Hours')}   align="right" />
          <SortHead sort={sort} sortKey="violations"    click={click} label={(window.appT||(s=>s))('Strikes')} align="right" />
          <SortHead sort={sort} sortKey="compliance_pct" click={click} label={(window.appT||(s=>s))('Compliance')} align="right" />
        </tr>
      </thead>
      <tbody>
        {sorted.map(row => (
          <tr key={row.user_id}>
            <td>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{row.display_name}</div>
              {row.team && <div className="muted" style={{ fontSize: 11 }}>{row.team}</div>}
            </td>
            <td className="num">{row.days_present}</td>
            <td className="num" style={{ color: row.days_late > 0 ? 'var(--warn)' : undefined }}>{row.days_late}</td>
            <td className="num" style={{ color: row.days_absent > 0 ? 'var(--err)' : undefined }}>{row.days_absent}</td>
            <td className="num">{(row.total_hours || 0).toFixed(1)}h</td>
            <td className="num" style={{ color: row.violations > 2 ? 'var(--err)' : row.violations > 0 ? 'var(--warn)' : undefined }}>
              {row.violations}
            </td>
            <td className="num">
              <span style={{ color: (row.compliance_pct || 0) >= 90 ? 'var(--ok)' : (row.compliance_pct || 0) >= 70 ? 'var(--warn)' : 'var(--err)' }}>
                {(row.compliance_pct || 0).toFixed(0)}%
              </span>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

/* ── Made progress section ── */
function SummaryProgress({ period, search, refreshTick }) {
  const [rows, setRows]       = useState([]);
  const [loading, setLoading] = useState(false);
  const [notifying, setNotifying] = useState({});
  const toast = useToast();

  const fetchData = async () => {
    setLoading(true);
    try {
      // Progress endpoint only accepts week|month (not 6_months)
      const safePeriod = period === '6_months' ? 'month' : period;
      const params = new URLSearchParams({ period: safePeriod });
      if (search) params.set('search', search);
      const r = await fetch(`/api/summary/progress?${params}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const data = await r.json();
      setRows(Array.isArray(data) ? data : []);
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Progress fetch failed: ') + e.message, kind: 'err' });
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { fetchData(); }, [period, search, refreshTick]);

  const notifyAdmin = async (userId) => {
    setNotifying(n => ({ ...n, [userId]: true }));
    try {
      const r = await fetch(`/api/summary/no-progress/notify-admin?user_id=${userId}`, {
        method: 'POST',
        credentials: 'same-origin',
      });
      if (!r.ok) throw new Error(`${r.status}`);
      toast.push({ msg: (window.appT||(s=>s))('Admin notified'), kind: 'ok' });
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Notify failed: ') + e.message, kind: 'err' });
    } finally {
      setNotifying(n => ({ ...n, [userId]: false }));
    }
  };

  if (loading) return <div className="muted" style={{ padding: 12, fontSize: 13 }}>{(window.appT||(s=>s))('Loading…')}</div>;
  if (!rows.length) return <Empty icon={<Icon name="check" size={24}/>} title={(window.appT||(s=>s))('No no-progress flags')} subtitle={(window.appT||(s=>s))('All employees have made progress in this period.')} />;

  // Empty state — never leave the section blank. If the team is hitting
  // every standup with substantive progress (no scores <2), show a friendly
  // confirmation panel instead of an empty table.
  if (!loading && rows.length === 0) {
    return (
      <div style={{
        padding: '24px 18px',
        border: '1px dashed var(--line)',
        borderRadius: 'var(--r-md)',
        background: 'var(--bg)',
        color: 'var(--text-2)',
        textAlign: 'center',
        fontSize: 13,
      }}>
        <div style={{
          fontSize: 22, color: 'var(--ok)', marginBottom: 6, lineHeight: 1,
        }}>✓</div>
        <div style={{ fontWeight: 600, color: 'var(--text)', marginBottom: 4 }}>
          {(window.appT||(s=>s))('No no-progress flags for this period')}
        </div>
        <div style={{ fontSize: 12 }}>
          {(window.appT||(s=>s))('Every signed-in standup in the selected window scored progress ≥ 2.')}
        </div>
      </div>
    );
  }

  return (
    <table className="t">
      <thead>
        <tr>
          <th>{(window.appT||(s=>s))('Person')}</th>
          <th>{(window.appT||(s=>s))('Most recent attendance')}</th>
          <th>{(window.appT||(s=>s))('Previous attendance')}</th>
          <th>{(window.appT||(s=>s))('Sign-in range')}</th>
          <th style={{ textAlign:'right' }}>{(window.appT||(s=>s))('Action')}</th>
        </tr>
      </thead>
      <tbody>
        {rows.map(row => {
          const s0 = (row.last_standups || [])[0];
          const s1 = (row.last_standups || [])[1];
          return (
          <tr key={row.user_id}>
            <td>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{row.display_name}</div>
              {row.team && <div className="muted" style={{ fontSize: 11 }}>{(window.appLang&&window.appLang()==='ar') ? `${row.team} · ${row.no_progress_days} يوم بتقدم منخفض` : `${row.team} · ${row.no_progress_days} low-progress day${row.no_progress_days !== 1 ? 's' : ''}`}</div>}
            </td>
            <td style={{ fontSize: 12, maxWidth: 220 }}>
              {s0 ? <><span className="mono muted" style={{ fontSize: 10 }}>{s0.date}</span><br/>{s0.today_text || <span className="muted">—</span>}</> : <span className="muted">—</span>}
            </td>
            <td style={{ fontSize: 12, color:'var(--text-2)', maxWidth: 220 }}>
              {s1 ? <><span className="mono muted" style={{ fontSize: 10 }}>{s1.date}</span><br/>{s1.today_text || <span className="muted">—</span>}</> : <span className="muted">—</span>}
            </td>
            <td className="mono muted" style={{ fontSize: 11 }}>
              <div>{(window.appT||(s=>s))('Latest:')} {row.most_recent_signin ? new Date(row.most_recent_signin).toLocaleString([], { month:'short', day:'numeric', hour:'2-digit', minute:'2-digit' }) : '—'}</div>
              <div>{(window.appT||(s=>s))('Oldest:')} {row.least_recent_signin ? new Date(row.least_recent_signin).toLocaleString([], { month:'short', day:'numeric', hour:'2-digit', minute:'2-digit' }) : '—'}</div>
            </td>
            <td style={{ textAlign:'right' }}>
              <button
                className="btn btn-ghost"
                disabled={!!notifying[row.user_id]}
                onClick={() => notifyAdmin(row.user_id)}
              >
                <Icon name="alert" size={12}/> {notifying[row.user_id] ? (window.appT||(s=>s))('Sending…') : (window.appT||(s=>s))('Notify admin')}
              </button>
            </td>
          </tr>
          );
        })}
      </tbody>
    </table>
  );
}

/* ── Tiny safe markdown renderer for the AI accomplishment summaries.
   Handles **bold**, *italic*, _italic_, ### / ## / # headings, - bullets,
   and line breaks. Escapes HTML first to avoid injection. ── */
function _renderMd(md) {
  if (!md) return '';
  const esc = String(md)
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  const lines = esc.split(/\r?\n/);
  const out = [];
  let inList = false;
  for (const raw of lines) {
    const line = raw;
    if (/^### /.test(line)) {
      if (inList) { out.push('</ul>'); inList = false; }
      out.push('<h4 style="margin:8px 0 4px">' + line.replace(/^### /, '') + '</h4>');
    } else if (/^## /.test(line)) {
      if (inList) { out.push('</ul>'); inList = false; }
      out.push('<h3 style="margin:10px 0 6px">' + line.replace(/^## /, '') + '</h3>');
    } else if (/^# /.test(line)) {
      if (inList) { out.push('</ul>'); inList = false; }
      out.push('<h2 style="margin:12px 0 8px">' + line.replace(/^# /, '') + '</h2>');
    } else if (/^[-*] /.test(line)) {
      if (!inList) { out.push('<ul style="margin:4px 0 4px 18px">'); inList = true; }
      out.push('<li>' + line.replace(/^[-*] /, '') + '</li>');
    } else if (line.trim() === '') {
      if (inList) { out.push('</ul>'); inList = false; }
      out.push('<br/>');
    } else {
      if (inList) { out.push('</ul>'); inList = false; }
      out.push('<p style="margin:4px 0">' + line + '</p>');
    }
  }
  if (inList) out.push('</ul>');
  let html = out.join('');
  html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
  html = html.replace(/(?<!\w)_([^_\n]+)_(?!\w)/g, '<em>$1</em>');
  html = html.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, '<em>$1</em>');
  return html;
}

/* ── Single AI accomplishment card with "Send to user" button ── */
function AccomplishmentAiCard({ u, days }) {
  const [sending, setSending] = useState(false);
  const [sentAt, setSentAt]   = useState(null);
  const toast = useToast();

  const sendToUser = async () => {
    if (!confirm((window.appLang&&window.appLang()==='ar') ? `إرسال هذا الملخص بالذكاء الاصطناعي كرسالة مباشرة عبر Matrix إلى ${u.display_name}؟` : `Send this AI summary as a Matrix DM to ${u.display_name}?`)) return;
    setSending(true);
    try {
      const r = await fetch(`/api/reports/accomplishments-ai/send-to-user/${u.user_id}?days=${days}`, {
        method: 'POST', credentials: 'same-origin',
      });
      if (!r.ok) {
        const body = await r.json().catch(() => null);
        const detail = body?.detail || `${r.status}`;
        throw new Error(typeof detail === 'string' ? detail : JSON.stringify(detail));
      }
      setSentAt(new Date());
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تم إرسال رسالة مباشرة إلى ${u.display_name}` : `DM sent to ${u.display_name}`, kind: 'ok' });
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Send failed: ') + e.message, kind: 'err' });
    } finally {
      setSending(false);
    }
  };

  return (
    <div style={{ background:'var(--bg-elev-2)', border:'1px solid var(--line)', borderRadius:'var(--r-md)', padding: 16 }}>
      <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom: 10, gap: 8, flexWrap:'wrap' }}>
        <div style={{ display:'flex', alignItems:'baseline', gap: 10, minWidth: 0 }}>
          <strong style={{ fontSize: 14 }}>{u.display_name}</strong>
          <span className="mono muted" style={{ fontSize: 11 }}>
            {(window.appLang&&window.appLang()==='ar') ? `${u.by_day.length} يوم · ${u.by_day.filter(d=>d.kinds && d.kinds.includes('signin')).length} تسجيل دخول` : `${u.by_day.length} day${u.by_day.length===1?'':'s'} · ${u.by_day.filter(d=>d.kinds && d.kinds.includes('signin')).length} sign-in(s)`}
          </span>
        </div>
        <div style={{ display:'flex', gap: 6, alignItems:'center' }}>
          {sentAt && (
            <span className="muted mono" style={{ fontSize: 10 }}>
              ✓ {(window.appT||(s=>s))('sent')} {sentAt.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}
            </span>
          )}
          <button className="btn btn-pri" onClick={sendToUser} disabled={sending || !u.ai_summary || u.by_day.length === 0}
            title={u.by_day.length === 0 ? (window.appT||(s=>s))('No sign-in activity to send') : ((window.appLang&&window.appLang()==='ar') ? `إرسال الملخص بالذكاء الاصطناعي كرسالة مباشرة إلى ${u.display_name}` : `Send AI summary as DM to ${u.display_name}`)}
            style={{ fontSize: 12 }}>
            <Icon name="msg" size={12}/> {sending ? (window.appT||(s=>s))('Sending…') : (window.appT||(s=>s))('Send to user')}
          </button>
        </div>
      </div>
      <div className="ai-summary" style={{ fontSize: 13, lineHeight: 1.55, color:'var(--text)' }}
        dangerouslySetInnerHTML={{ __html: _renderMd(u.ai_summary) }} />
      {u.by_day.length > 0 && (
        <details style={{ marginTop: 10, fontSize: 11.5 }}>
          <summary className="muted" style={{ cursor:'pointer' }}>{(window.appLang&&window.appLang()==='ar') ? `عرض التفصيل اليومي الخام (${u.by_day.length})` : `View raw daily breakdown (${u.by_day.length})`}</summary>
          <div style={{ display:'flex', flexDirection:'column', gap: 6, marginTop: 8 }}>
            {u.by_day.map(d => (
              <div key={d.date} style={{ borderLeft:'2px solid var(--line)', paddingLeft: 10 }}>
                <div className="mono muted" style={{ fontSize: 10 }}>{d.date}</div>
                {d.today && <div><span className="muted">{(window.appT||(s=>s))('Today:')}</span> {d.today}</div>}
                {d.yesterday && <div><span className="muted">{(window.appT||(s=>s))('Yesterday:')}</span> {d.yesterday}</div>}
                {d.blocker && <div style={{ color:'var(--err)' }}><span className="muted" style={{ color:'var(--text-2)' }}>{(window.appT||(s=>s))('Blocker:')}</span> {d.blocker}</div>}
              </div>
            ))}
          </div>
        </details>
      )}
    </div>
  );
}

/* ── Daily accomplishments section (item #6/#9) — Daily + AI multi-day ── */
function SummaryAccomplishments({ search, refreshTick }) {
  const [data, setData]     = useState({users: [], date: ''});
  const [aiData, setAiData] = useState({users: [], range_start: '', range_end: ''});
  const [loading, setLoading] = useState(false);
  const [aiLoading, setAiLoading] = useState(false);
  const [sending, setSending] = useState(false);
  const [day, setDay]       = useState(() => new Date().toISOString().slice(0,10));
  const [aiDays, setAiDays] = useState(7);
  const [view, setView]     = useState('daily'); // daily | ai
  const [me, setMe]         = useState(null);
  const toast = useToast();
  const editMode = (typeof window.useEditMode === 'function') ? window.useEditMode() : false;
  const _EditableCell = window.EditableCell;

  useEffect(() => {
    let alive = true;
    fetch('/api/auth/me', { credentials: 'same-origin' })
      .then(r => r.ok ? r.json() : null)
      .then(j => { if (alive) setMe(j); })
      .catch(() => {});
    return () => { alive = false; };
  }, []);

  const _patchHours = (u) => async (newValue) => {
    const trimmed = (newValue == null ? '' : String(newValue)).trim();
    let hours;
    if (trimmed === '' || trimmed.toLowerCase() === 'null' || trimmed === '—') {
      hours = null;
    } else {
      const n = parseFloat(trimmed.replace(/h$/i, ''));
      if (isNaN(n) || n < 0 || n > 24) {
        toast.push({ msg: (window.appT||(s=>s))('Hours must be 0-24, or empty to clear'), kind: 'err' });
        throw new Error('bad input');
      }
      hours = n;
    }
    const r = await fetch(
      `/api/daily-attendance/${u.user_id}/${day}/hours`,
      {
        method: 'PATCH',
        credentials: 'same-origin',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ hours }),
      }
    );
    if (!r.ok) {
      const txt = await r.text();
      toast.push({ msg: `Edit failed: ${txt}`, kind: 'err' });
      throw new Error(`HTTP ${r.status}`);
    }
    const j = await r.json();
    if (j.undo_token && typeof window.showUndoToast === 'function') {
      window.showUndoToast({
        token: j.undo_token,
        label: (window.appLang&&window.appLang()==='ar') ? `${u.display_name}: تم ${hours == null ? 'مسح' : 'تجاوز'} الساعات.` : `${u.display_name}: hours ${hours == null ? 'cleared' : 'overridden'}.`,
        onUndone: fetchData,
      });
    }
    fetchData();
  };

  const _canEditU = (u) => {
    if (!_EditableCell || !me) return false;
    const role = (me.org_role || '').toLowerCase();
    if (role === 'admin') return true;
    if (role === 'manager' && (me.team || '') === (u.team || '')) return true;
    return false;
  };

  const fetchData = async () => {
    setLoading(true);
    try {
      const r = await fetch(`/api/reports/daily-accomplishments?on=${day}`, { credentials:'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const j = await r.json();
      setData(j);
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Accomplishments fetch failed: ') + e.message, kind: 'err' });
      setData({users: [], date: day});
    } finally { setLoading(false); }
  };

  const fetchAi = async () => {
    setAiLoading(true);
    try {
      const r = await fetch(`/api/reports/accomplishments-ai?days=${aiDays}`, { credentials:'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const j = await r.json();
      setAiData(j);
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تم إنشاء ملخص بالذكاء الاصطناعي لـ ${j.users.length} مستخدم` : `AI summary generated for ${j.users.length} users`, kind: 'ok' });
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('AI summary failed: ') + e.message, kind: 'err' });
    } finally { setAiLoading(false); }
  };

  const sendDigest = async () => {
    setSending(true);
    try {
      const r = await fetch(`/api/reports/daily-accomplishments/send?on=${day}`, {
        method: 'POST', credentials: 'same-origin',
      });
      if (!r.ok) {
        const body = await r.json().catch(() => null);
        throw new Error(body?.detail || `${r.status}`);
      }
      const j = await r.json();
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تم إرسال الملخص كرسالة مباشرة إلى ${j.sent_to} مشرف` : `Digest DMed to ${j.sent_to} admin(s)`, kind: 'ok' });
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Send failed: ') + e.message, kind: 'err' });
    } finally { setSending(false); }
  };

  useEffect(() => { fetchData(); }, [day, refreshTick]);

  const filtered = search
    ? data.users.filter(u => (u.display_name || '').toLowerCase().includes(search.toLowerCase()))
    : data.users;

  if (loading) return <div className="muted" style={{ padding: 12, fontSize: 13 }}>{(window.appT||(s=>s))('Loading…')}</div>;

  const made    = filtered.filter(u => u.progress_score === 2).length;
  const partial = filtered.filter(u => u.progress_score === 1).length;
  const none    = filtered.filter(u => u.progress_score === 0).length;
  const blocked = filtered.filter(u => u.had_blocker).length;
  const noSignin = filtered.filter(u => !u.signed_in).length;

  const flagPill = (u) => {
    if (u.progress_score === 2) return <Badge kind="ok" dot>{(window.appT||(s=>s))('made progress')}</Badge>;
    if (u.progress_score === 1) return <Badge kind="warn" dot>{(window.appT||(s=>s))('partial')}</Badge>;
    if (u.progress_score === 0) return <Badge kind="err" dot>{(window.appT||(s=>s))('no progress')}</Badge>;
    return <Badge kind="mute">{(window.appT||(s=>s))('unscored')}</Badge>;
  };

  return (
    <div>
      <div style={{ display:'flex', gap: 12, alignItems:'center', flexWrap:'wrap', marginBottom: 12 }}>
        <Segmented value={view} onChange={setView} options={[
          { value:'daily', label:(window.appT||(s=>s))('Daily') },
          { value:'ai',    label:(window.appT||(s=>s))('AI summary (multi-day)') },
        ]} />
        {view === 'daily' && (
          <>
            <input type="date" className="inp" value={day} max={new Date().toISOString().slice(0,10)}
              onChange={e => setDay(e.target.value)} style={{ width: 150, fontSize: 12, padding:'4px 8px' }} />
            <div style={{ display:'grid', gridTemplateColumns:'repeat(5, minmax(90px,1fr))', gap: 8, flex: 1 }}>
              <div className="mini-stat"><div className="lbl">{(window.appT||(s=>s))('Made')}</div><div className="val mono">{made}</div></div>
              <div className="mini-stat"><div className="lbl">{(window.appT||(s=>s))('Partial')}</div><div className="val mono">{partial}</div></div>
              <div className="mini-stat"><div className="lbl">{(window.appT||(s=>s))('No progress')}</div><div className="val mono">{none}</div></div>
              <div className="mini-stat"><div className="lbl">{(window.appT||(s=>s))('Blocked')}</div><div className="val mono">{blocked}</div></div>
              <div className="mini-stat"><div className="lbl">{(window.appT||(s=>s))('No sign-in')}</div><div className="val mono">{noSignin}</div></div>
            </div>
            <button className="btn btn-pri" style={{ marginLeft:'auto' }} onClick={sendDigest} disabled={sending}>
              <Icon name="msg" size={12}/> {sending ? (window.appT||(s=>s))('Sending…') : (window.appT||(s=>s))('DM digest to admins')}
            </button>
          </>
        )}
        {view === 'ai' && (
          <>
            <select className="sel" value={aiDays} onChange={e => setAiDays(parseInt(e.target.value))}
              style={{ width: 110, fontSize: 12, padding:'4px 8px' }}>
              <option value={1}>{(window.appT||(s=>s))('Today')}</option>
              <option value={3}>{(window.appT||(s=>s))('Last 3 days')}</option>
              <option value={7}>{(window.appT||(s=>s))('Last 7 days')}</option>
              <option value={14}>{(window.appT||(s=>s))('Last 14 days')}</option>
              <option value={30}>{(window.appT||(s=>s))('Last 30 days')}</option>
            </select>
            <button className="btn btn-pri" style={{ marginLeft:'auto' }} onClick={fetchAi} disabled={aiLoading}>
              <Icon name="ai" size={12}/> {aiLoading ? (window.appT||(s=>s))('Generating…') : (window.appT||(s=>s))('Generate AI summary')}
            </button>
          </>
        )}
      </div>

      {view === 'ai' ? (
        aiData.users.length === 0 && !aiLoading ? (
          <Empty icon={<Icon name="ai" size={24}/>} title={(window.appT||(s=>s))('No AI summary yet')} subtitle={(window.appT||(s=>s))("Click 'Generate AI summary' to compile sign-in messages into a narrative.")} />
        ) : (
          <div style={{ display:'flex', flexDirection:'column', gap: 12 }}>
            <div className="muted" style={{ fontSize: 12 }}>
              {(window.appT||(s=>s))('Range:')} <span className="mono">{aiData.range_start}</span> → <span className="mono">{aiData.range_end}</span>
              {aiData.users.length > 0 && ((window.appLang&&window.appLang()==='ar') ? ` · ${aiData.users.length} موظف` : ` · ${aiData.users.length} employee(s)`)}
            </div>
            {(search ? aiData.users.filter(u => (u.display_name || '').toLowerCase().includes(search.toLowerCase())) : aiData.users).map(u => (
              <AccomplishmentAiCard key={u.user_id} u={u} days={aiDays} />
            ))}
          </div>
        )
      ) : filtered.length === 0 ? (
        <Empty icon={<Icon name="check" size={24}/>} title={(window.appT||(s=>s))('No data')} subtitle={(window.appT||(s=>s))('No employees have signed in for this date yet.')} />
      ) : (
        <div style={{ display:'flex', flexDirection:'column', gap: 8 }}>
          {filtered.map(u => (
            <div key={u.user_id} style={{ background:'var(--bg-elev-2)', border:'1px solid var(--line)', borderRadius:'var(--r-md)', padding: 12 }}>
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom: 6, gap: 8, flexWrap:'wrap' }}>
              <strong style={{ fontSize: 13 }}>{u.display_name}</strong>
              <div style={{ display:'flex', gap: 6, alignItems:'center', flexWrap:'wrap' }}>
                  {flagPill(u)}
                  {u.had_blocker && <Badge kind="err">{(window.appT||(s=>s))('blocker')}</Badge>}
                  {u.was_late && <Badge kind="warn">{(window.appT||(s=>s))('late')}</Badge>}
                  {!u.signed_in && <Badge kind="mute">{(window.appT||(s=>s))('no sign-in')}</Badge>}
                  {u.signed_in && (editMode && _canEditU(u) ? (
                    <span className="mono muted" style={{ fontSize: 11 }}>
                      <_EditableCell
                        kind="text"
                        value={u.hours_worked != null ? u.hours_worked.toFixed(1) : ''}
                        formatter={() => `${(u.hours_worked || 0).toFixed(1)}h`}
                        onSave={_patchHours(u)}
                        placeholder="0.0"
                      />
                    </span>
                  ) : (
                    <span className="mono muted" style={{ fontSize: 11 }}>{u.hours_worked.toFixed(1)}h</span>
                  ))}
                  {u.last_signin_at && <span className="mono muted" style={{ fontSize: 11 }}>{(window.appLang&&window.appLang()==='ar') ? `آخر تسجيل دخول ${new Date(u.last_signin_at).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}` : `last sign-in ${new Date(u.last_signin_at).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}`}</span>}
              </div>
            </div>
              {u.today_text && (
                <div style={{ fontSize: 12, marginBottom: 4, whiteSpace:'pre-line' }}>
                  <span className="muted">{(window.appT||(s=>s))('Today: ')}</span>{u.today_text}
                </div>
              )}
              {u.yesterday_text && (
                <div style={{ fontSize: 12, marginBottom: 4, whiteSpace:'pre-line' }}>
                  <span className="muted">{(window.appT||(s=>s))('Yesterday: ')}</span>{u.yesterday_text}
                </div>
              )}
              {u.had_blocker && u.blocker_text && (
                <div style={{ fontSize: 12, marginBottom: 4, color:'var(--err)', whiteSpace:'pre-line' }}>
                  <span className="muted" style={{ color:'var(--text-2)' }}>{(window.appT||(s=>s))('Blocker: ')}</span>{u.blocker_text}
                </div>
              )}
              {u.progress_reasoning && (
                <div style={{ fontSize: 11, color:'var(--text-3)', fontStyle:'italic' }}>
                  {(window.appT||(s=>s))('Bot reasoning:')} {u.progress_reasoning}
                </div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ── Violations section ── */
function SummaryViolations({ period, search, refreshTick }) {
  const [rows, setRows]     = useState([]);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  const fetchData = async () => {
    setLoading(true);
    try {
      const params = new URLSearchParams({ period });
      if (search) params.set('search', search);
      const r = await fetch(`/api/summary/violations?${params}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const data = await r.json();
      setRows(Array.isArray(data) ? data : []);
    } catch(e) {
      toast.push({ msg: (window.appT||(s=>s))('Violations fetch failed: ') + e.message, kind: 'err' });
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { fetchData(); }, [period, search, refreshTick]);

  const { sorted, sort, click } = useSortable(rows, { key: 'violation_count', dir: 'desc' });

  if (loading) return <div className="muted" style={{ padding: 12, fontSize: 13 }}>{(window.appT||(s=>s))('Loading violations…')}</div>;
  if (!sorted.length) return <Empty icon={<Icon name="check" size={24}/>} title={(window.appT||(s=>s))('No violations')} subtitle={(window.appT||(s=>s))('No format violations in this period.')} />;

  return (
    <table className="t">
      <thead>
        <tr>
          <SortHead sort={sort} sortKey="display_name"   click={click} label={(window.appT||(s=>s))('Person')} />
          <SortHead sort={sort} sortKey="violation_count" click={click} label={(window.appT||(s=>s))('Total violations')} align="right" />
          <SortHead sort={sort} sortKey="strikes_left" click={click} label={(window.appT||(s=>s))('Strikes left')} align="right" />
          <SortHead sort={sort} sortKey="last_violation"  click={click} label={(window.appT||(s=>s))('Last violation')}    align="right" />
        </tr>
      </thead>
      <tbody>
        {sorted.map(row => (
          <tr key={row.user_id}>
            <td>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{row.display_name}</div>
              {row.team && <div className="muted" style={{ fontSize: 11 }}>{row.team}</div>}
            </td>
            <td className="num" style={{ color: row.violation_count >= 3 ? 'var(--err)' : row.violation_count > 0 ? 'var(--warn)' : undefined }}>
              {row.violation_count}
            </td>
            <td className="num mono" style={{ color: (row.strikes_left || 0) <= 1 ? 'var(--err)' : 'var(--text-2)' }}>
              {row.strikes_left ?? '—'}
            </td>
            <td className="num muted" style={{ fontSize: 12 }}>
              {row.last_violation
                ? new Date(row.last_violation).toLocaleDateString([], { month:'short', day:'numeric', year:'numeric' })
                : '—'}
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

/* ── Main MonthlyPage ── */
function MonthlyPage({ live }) {
  const [month, setMonth]       = useState(() => new Date().toISOString().slice(0,7));
  const [period, setPeriod]     = useState('week');
  const [search, setSearch]     = useState('');
  const [refreshTick, setRefreshTick] = useState(0);
  const [exporting, setExporting] = useState('');
  const toast = useToast();

  const handleRefresh = () => {
    setRefreshTick(t => t + 1);
    try {
      window.dispatchEvent(new CustomEvent('status-data-refresh-requested'));
      if (typeof window.STATUS_REFRESH === 'function') window.STATUS_REFRESH();
    } catch (e) {}
    toast.push({ msg: (window.appT||(s=>s))('Refresh complete'), kind: 'ok' });
  };

  const handleExport = async (fmt) => {
    setExporting(fmt);
    try {
      const r = await fetch(`/api/summary/export?format=${fmt}&period=${period}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const blob = await r.blob();
      const url  = URL.createObjectURL(blob);
      const a    = document.createElement('a');
      a.href     = url;
      a.download = `summary-${period}.${fmt}`;
      a.click();
      URL.revokeObjectURL(url);
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `تم تنزيل تصدير ${fmt.toUpperCase()}` : `${fmt.toUpperCase()} export downloaded`, kind: 'ok' });
    } catch(e) {
      toast.push({ msg: (window.appLang&&window.appLang()==='ar') ? `فشل التصدير: ${e.message}` : `Export failed: ${e.message}`, kind: 'err' });
    } finally {
      setExporting('');
    }
  };

  return (
    <div className="page">
      <PageHeader
        title={(window.appT||(s=>s))('Summary')}
        meta={(window.appT||(s=>s))('Attendance heatmap, scoreboard, progress, and violations')}
        right={
          <div style={{ display:'flex', gap: 8 }}>
            <Refresh onClick={handleRefresh} loading={false} />
            <button className="btn btn-ghost" onClick={() => handleExport('xlsx')} disabled={!!exporting}>
              <Icon name="download" size={14}/> {exporting === 'xlsx' ? (window.appT||(s=>s))('Exporting…') : 'XLSX'}
            </button>
            <button className="btn btn-pri" onClick={() => handleExport('pdf')} disabled={!!exporting}>
              <Icon name="download" size={14}/> {exporting === 'pdf' ? (window.appT||(s=>s))('Exporting…') : 'PDF'}
            </button>
          </div>
        }
      />

      {/* Controls row */}
      <div style={{ display:'flex', gap: 12, marginBottom: 16, flexWrap:'wrap', alignItems:'center' }}>
        <SearchInput
          value={search}
          onChange={setSearch}
          placeholder={(window.appT||(s=>s))('Filter employees…')}
          style={{ width: 220 }}
        />
        <Segmented
          value={period}
          onChange={setPeriod}
          options={[
            { value:'day',      label:(window.appT||(s=>s))('Day') },
            { value:'week',     label:(window.appT||(s=>s))('Week') },
            { value:'month',    label:(window.appT||(s=>s))('Month') },
            { value:'quarter',  label:(window.appT||(s=>s))('Quarter') },
            { value:'6_months', label:(window.appT||(s=>s))('6 months') },
            { value:'year',     label:(window.appT||(s=>s))('Year') },
          ]}
        />
        <div style={{ display:'flex', alignItems:'center', gap: 8, marginLeft:'auto' }}>
          <span className="muted" style={{ fontSize: 12 }}>{(window.appT||(s=>s))('Heatmap month:')}</span>
          <input
            type="month"
            value={month}
            onChange={e => setMonth(e.target.value)}
            className="inp"
            style={{ width: 140, fontSize: 12, padding:'4px 8px' }}
            max={new Date().toISOString().slice(0,7)}
          />
        </div>
      </div>

      {/* Heatmap */}
      <div className="card" style={{ marginBottom: 16 }}>
        <SummaryHeatmap month={month} search={search} />
      </div>

      {/* Scoreboard */}
      <div className="card" style={{ marginBottom: 16 }}>
        <SectionHeader title={(window.appT||(s=>s))('Scoreboard')}
          tip={(window.appT||(s=>s))('Per-user month summary: hours, days present, late, attendance %. Drives the per-employee monthly DM.')} sub={(window.appLang&&window.appLang()==='ar') ? `الفترة: ${period}` : `Period: ${period}`} />
        <SummaryScoreboard period={period} search={search} refreshTick={refreshTick} />
      </div>

      {/* Daily accomplishments — items #6/#9 */}
      <div className="card" style={{ marginBottom: 16 }}>
        <SectionHeader title={(window.appT||(s=>s))('Daily accomplishments')}
          tip={(window.appT||(s=>s))("AI-summarized 'what got done' per day per user, derived from yesterday/today fields of every sign-in in the month.")} sub={(window.appT||(s=>s))('Per-user summary parsed from sign-in messages, with progress flags + blockers')} />
        <SummaryAccomplishments search={search} refreshTick={refreshTick} />
      </div>

      {/* No-progress flags */}
      <div className="card" style={{ marginBottom: 16 }}>
        <SectionHeader title={(window.appT||(s=>s))('No-progress flags')}
          tip={(window.appT||(s=>s))("Days where the bot's progress score was 0 (today text was vague or copy-pasted from yesterday). Manager attention candidates.")} sub={(window.appT||(s=>s))('Employees whose today-line repeated from yesterday')} />
        <SummaryProgress period={period} search={search} refreshTick={refreshTick} />
      </div>

      {/* Violations — split into attendance/format report (item #8) */}
      <div className="card">
        <SectionHeader title={(window.appT||(s=>s))('Format violations (attendance report)')}
          tip={(window.appT||(s=>s))('Every format-strike event in the month with the original message body. Strikes ≥3 trigger the admin report.')} sub={(window.appLang&&window.appLang()==='ar') ? `الفترة: ${period} · منفصلة عن الإنجازات` : `Period: ${period} · separate from accomplishments`} />
        <SummaryViolations period={period} search={search} refreshTick={refreshTick} />
      </div>
    </div>
  );
}

window.MonthlyPage = MonthlyPage;

window._renderMd = _renderMd;
