/* ============================================================
   page-reports.jsx — Generate reports + admin digest + hours distribution
   ============================================================ */

/* Re-bind parseDetail — set by primitives.jsx */
const parseDetail = window.parseDetail || ((body, status) => (body && (body.detail || body.message)) || `HTTP ${status}`);

/* i18n helpers — Arabic via window.appT, falls back to identity.
   File-unique names (_rT/_rAr): other v2 bundles declare their own top-level
   `_T` in the shared in-browser-Babel global scope, so a bare `const _T` here
   would throw "already declared" and blank the page. */
const _rT = (s) => (window.appT || (x => x))(s);
const _rAr = () => (window.appLang && window.appLang() === 'ar');

/* ── Hours Distribution stacked bar chart (inline SVG) ── */
/* ── Per-user 30-day trends (sparklines + status donut) — #25 ── */
// B7: per-employee violations report with type filter
function PerEmployeeViolationsCard({ refreshTick }) {
  const D = window.STATUS_DATA || {};
  const employees = D.EMPLOYEES || [];
  const [userId, setUserId]   = useState(employees[0]?.id || null);
  const [period, setPeriod]   = useState('month');
  const [type, setType]       = useState('all');
  const [data, setData]       = useState(null);
  const [loading, setLoading] = useState(false);

  const load = async () => {
    if (!userId) return;
    setLoading(true);
    try {
      const r = await fetch(
        `/api/employees/${userId}/violations?period=${period}&type=${type}`,
        { credentials: 'include' }
      );
      if (r.ok) setData(await r.json());
    } catch (_) {}
    finally { setLoading(false); }
  };

  useEffect(() => { load(); }, [userId, period, type, refreshTick]);

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("Per-employee violations")}
        tip={_rT("Filter by user + period + violation kind (presence / late / absent / strike / missed_signoff / all). Shows counts and the event timeline so admins can drill into specific compliance issues per person.")}
        sub={_rT("Pick a user, then filter by type. Last update reflects the current period selection.")}
        right={<Refresh onClick={load} loading={loading} />}
      />
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12, alignItems: 'center' }}>
        <label style={{ fontSize: 12 }}>{_rT("User")}</label>
        <select className="sel" value={userId || ''} onChange={e => setUserId(Number(e.target.value))}
          style={{ minWidth: 160 }}>
          {employees.map(e => <option key={e.id} value={e.id}>{e.display_name}</option>)}
        </select>
        <label style={{ fontSize: 12 }}>{_rT("Period")}</label>
        <select className="sel" value={period} onChange={e => setPeriod(e.target.value)}>
          {['day','week','month','quarter','6_months','year','annual'].map(p =>
            <option key={p} value={p}>{p}</option>
          )}
        </select>
        <label style={{ fontSize: 12 }}>{_rT("Type")}</label>
        <select className="sel" value={type} onChange={e => setType(e.target.value)}>
          <option value="all">{_rT("All")}</option>
          <option value="presence">{_rT("Presence")}</option>
          <option value="late">{_rT("Late")}</option>
          <option value="absent">{_rT("Absent")}</option>
          <option value="missed_signoff">{_rT("Missed sign-off")}</option>
          <option value="strike">{_rT("Format strike")}</option>
        </select>
      </div>
      {!data ? (
        <div className="muted" style={{ padding: 16, fontSize: 13 }}>
          {loading ? _rT('Loading…') : _rT('Pick a user to see violations.')}
        </div>
      ) : (
        <>
          <div style={{ display: 'flex', gap: 12, marginBottom: 12, flexWrap: 'wrap' }}>
            {Object.entries(data.counts || {}).map(([k, v]) => (
              <div key={k} style={{
                padding: '6px 14px', background: 'var(--bg-elev-2)',
                border: '1px solid var(--line)', borderRadius: 8, fontSize: 12,
              }}>
                <span className="muted">{k.replace(/_/g, ' ')}: </span>
                <span className="mono" style={{ fontWeight: 600, color: v > 0 ? 'var(--err)' : 'var(--ok)' }}>{v}</span>
              </div>
            ))}
          </div>
          <table className="t" style={{ fontSize: 12 }}>
            <thead><tr><th>{_rT("When")}</th><th>{_rT("Kind")}</th><th>{_rT("Severity")}</th><th>{_rT("Detail")}</th></tr></thead>
            <tbody>
              {(data.events || []).length === 0 ? (
                <tr><td colSpan={4} className="muted" style={{ textAlign: 'center', padding: 16 }}>{_rT("No events for this filter.")}</td></tr>
              ) : (
                data.events.map((ev, i) => (
                  <tr key={i}>
                    <td className="mono" style={{ fontSize: 11 }}>{ev.when ? new Date(ev.when).toLocaleString() : '—'}</td>
                    <td>{ev.kind}</td>
                    <td><span className={`badge ${ev.severity === 'high' ? 'err' : ev.severity === 'medium' ? 'warn' : 'mute'}`}>{ev.severity}</span></td>
                    <td>{ev.detail}</td>
                  </tr>
                ))
              )}
            </tbody>
          </table>
        </>
      )}
    </div>
  );
}

function PerUserTrendsCard({ refreshTick }) {
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const reload = React.useCallback(async () => {
    setLoading(true);
    try {
      // Reuse the hours-distribution endpoint (per-user × per-day)
      const r = await fetch('/api/reports/hours-distribution?period=month', { credentials: 'same-origin' });
      if (r.ok) setRows(await r.json());
    } catch(_) {} finally { setLoading(false); }
  }, []);
  React.useEffect(() => { reload(); }, [reload, refreshTick]);

  if (loading) return null;
  if (!rows || rows.length === 0) return null;

  // For each user: extract daily hours array + compute totals
  const enriched = rows.map(u => {
    const days = Object.values(u.hours_by_day || {});
    const total = days.reduce((s, h) => s + (h || 0), 0);
    const present = days.filter(h => (h || 0) >= 1).length;
    const partial = days.filter(h => (h || 0) > 0 && (h || 0) < 1).length;
    const absent  = days.filter(h => (h || 0) === 0).length;
    return { ...u, days, total, present, partial, absent };
  });
  enriched.sort((a, b) => b.total - a.total);

  // Aggregate status mix across all users
  const totalPresent = enriched.reduce((s, u) => s + u.present, 0);
  const totalPartial = enriched.reduce((s, u) => s + u.partial, 0);
  const totalAbsent  = enriched.reduce((s, u) => s + u.absent, 0);
  const totalAll = totalPresent + totalPartial + totalAbsent || 1;
  const slices = [
    { value: totalPresent, label: _rT('Present'), color: 'var(--ok)' },
    { value: totalPartial, label: _rT('Partial'), color: 'var(--warn)' },
    { value: totalAbsent,  label: _rT('Absent'),  color: 'var(--err)' },
  ];

  // Inline donut (small)
  const SIZE = 130, R = SIZE/2 - 12, CX = SIZE/2, CY = SIZE/2;
  const C = 2 * Math.PI * R;
  let off = 0;

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("📈 Per-user trends — 30 day")}
          tip={_rT("30-day moving line for each employee — hours / attendance % / progress score. Click a legend item to isolate one user.")}
        sub={_rAr() ? `${enriched.length} موظف · الخط البياني = الساعات اليومية؛ الحلقة = توزيع الحالة الإجمالي` : `${enriched.length} employees · sparkline = daily hours; donut = aggregate status mix`}
      />
      <div style={{ display:'flex', gap:24, padding:'10px 14px 4px', alignItems:'center', flexWrap:'wrap' }}>
        <div style={{ display:'flex', flexDirection:'column', alignItems:'center' }}>
          <svg width={SIZE} height={SIZE}>
            <circle cx={CX} cy={CY} r={R} fill="none" stroke="var(--bg-elev-2)" strokeWidth={14}/>
            {slices.map((s, i) => {
              if (!s.value) return null;
              const len = (s.value / totalAll) * C;
              const node = (
                <circle key={i} cx={CX} cy={CY} r={R} fill="none" stroke={s.color} strokeWidth={14}
                  strokeDasharray={`${len} ${C - len}`} strokeDashoffset={-off}
                  transform={`rotate(-90 ${CX} ${CY})`}>
                  <title>{s.label}: {s.value} {_rT("day-slots")}</title>
                </circle>
              );
              off += len;
              return node;
            })}
            <text x={CX} y={CY-3} textAnchor="middle" fontSize="14" fill="var(--text)" fontWeight="600">
              {Math.round((totalPresent / totalAll) * 100)}%
            </text>
            <text x={CX} y={CY+12} textAnchor="middle" fontSize="9" fill="var(--text-2)">{_rT("present")}</text>
          </svg>
        </div>
        <div style={{ display:'flex', flexDirection:'column', gap:6, fontSize:12 }}>
          {slices.map(s => (
            <div key={s.label} style={{ display:'flex', alignItems:'center', gap:8 }}>
              <span style={{ width:10, height:10, borderRadius:'50%', background: s.color }}/>
              <strong style={{ width:60 }}>{s.label}</strong>
              <span className="num mono">{s.value}</span>
              <span className="muted" style={{ fontSize:11 }}>
                {totalAll > 0 ? Math.round((s.value/totalAll)*100) : 0}%
              </span>
            </div>
          ))}
        </div>
      </div>

      <div style={{ display:'grid', gridTemplateColumns:'1fr auto auto', gap:'4px 14px', padding:'10px 14px', alignItems:'center' }}>
        {enriched.map(u => (
          <React.Fragment key={u.user_id}>
            <div style={{ fontSize:13, display:'flex', flexDirection:'column' }}>
              <strong>{u.name}</strong>
              <span className="muted" style={{ fontSize:10 }}>
                {u.present}p · {u.partial}half · {u.absent}a
              </span>
            </div>
            <div style={{ minWidth:180 }}>
              <Sparkline data={u.days} w={180} h={32} color="var(--brand)" />
            </div>
            <div className="num mono" style={{ fontSize:13, fontWeight:600, textAlign:'right', minWidth:50 }}>
              {u.total.toFixed(1)}h
            </div>
          </React.Fragment>
        ))}
      </div>
    </div>
  );
}

function HoursDistributionChart({ period, refreshTick }) {
  // Independent dropdown so admins can scope the chart without touching
  // the page-wide 'period' that drives the report-generation form.
  const [localPeriod, setLocalPeriod] = useState(period || 'week');
  const [data, setData]     = useState([]);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  const fetchData = async (p) => {
    setLoading(true);
    try {
      const r = await fetch(`/api/reports/hours-distribution?period=${p}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const raw = await r.json();
      setData(Array.isArray(raw) ? raw : []);
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل جلب توزيع الساعات: ' : 'Hours distribution fetch failed: ') + e.message, kind: 'err' });
      setData([]);
    } finally {
      setLoading(false);
    }
  };

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

  // Render a tiny dropdown above the chart so callers can override the period.
  const PERIOD_OPTIONS = [
    { value: 'day',      label: _rT('Day') },
    { value: 'week',     label: _rT('Week') },
    { value: 'month',    label: _rT('Month') },
    { value: 'quarter',  label: _rT('Quarter') },
    { value: '6_months', label: _rT('Semi') },
    { value: 'annual',   label: _rT('Annual') },
  ];
  const periodControl = (
    <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:10 }}>
      <span className="muted" style={{ fontSize:12 }}>{_rT("Range:")}</span>
      <select
        className="inp"
        style={{ width: 140, padding:'4px 8px', fontSize:12 }}
        value={localPeriod}
        onChange={e => setLocalPeriod(e.target.value)}
      >
        {PERIOD_OPTIONS.map(o => (
          <option key={o.value} value={o.value}>{o.label}</option>
        ))}
      </select>
    </div>
  );

  if (loading) return <>{periodControl}<div className="muted" style={{ padding: 12, fontSize: 13 }}>{_rT("Loading…")}</div></>;
  if (!data.length) return <>{periodControl}<Empty icon={<Icon name="chart" size={24}/>} title={_rT("No hours data")} subtitle={_rT("No attendance hours logged for this period.")} /></>;

  const total = data.reduce((s, u) => s + (u.total || 0), 0);
  if (total === 0) return <>{periodControl}<Empty icon={<Icon name="chart" size={24}/>} title={_rT("No hours data")} subtitle={_rT("No attendance hours logged for this period.")} /></>;

  // Per-user pie of hours-share. Bigger users = bigger slices.
  const PALETTE = ['#3b82f6','#06b6d4','#8b5cf6','#f59e0b','#10b981','#f43f5e','#a3e635','#ec4899','#14b8a6','#eab308'];
  const SIZE = 220, R = SIZE/2 - 10, CX = SIZE/2, CY = SIZE/2;
  const C = 2 * Math.PI * R;
  let off = 0;
  const slices = data.map((u, i) => {
    const v = u.total || 0;
    if (!v) return null;
    const len = (v / total) * C;
    const node = (
      <circle key={i} cx={CX} cy={CY} r={R} fill="none" stroke={PALETTE[i % PALETTE.length]} strokeWidth={26}
        strokeDasharray={`${len} ${C - len}`} strokeDashoffset={-off}>
        <title>{`${u.name}: ${v.toFixed(1)}h (${Math.round(v/total*100)}%)`}</title>
      </circle>
    );
    off += len;
    return node;
  }).filter(Boolean);

  return (
    <>
      {periodControl}
      <div style={{ display:'flex', gap: 24, alignItems:'center', flexWrap:'wrap', padding:'12px 4px' }}>
      <svg width={SIZE} height={SIZE} viewBox={`0 0 ${SIZE} ${SIZE}`} style={{ flexShrink: 0 }}>
        <circle cx={CX} cy={CY} r={R} fill="none" stroke="var(--line)" strokeWidth={26} />
        {slices}
        <text x={CX} y={CY-2} textAnchor="middle" fill="var(--text)" fontSize={20} fontWeight={700} fontFamily="var(--font-mono)">{total.toFixed(0)}h</text>
        <text x={CX} y={CY+16} textAnchor="middle" fill="var(--text-3)" fontSize={10} fontFamily="var(--font-mono)">{_rT("total")}</text>
      </svg>
      <div style={{ flex: 1, minWidth: 220, display:'flex', flexDirection:'column', gap: 6 }}>
        {/* Sort a COPY for display; color by ORIGINAL index so legend swatches
            match the pie slices (the pie above maps PALETTE[i] over `data`).
            The old code sorted `data` in place during render, desyncing the
            colors and mutating shared state. */}
        {[...data].sort((a,b) => (b.total||0) - (a.total||0)).map((u, i) => {
          const v = u.total || 0;
          const pct = total ? Math.round(v/total*100) : 0;
          const color = PALETTE[data.indexOf(u) % PALETTE.length];
          return (
            <div key={u.user_id || i} style={{ display:'flex', alignItems:'center', gap: 10, fontSize: 12 }}>
              <span style={{ display:'inline-block', width: 10, height: 10, borderRadius: 2, background: color, flexShrink:0 }} />
              <strong style={{ flex:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{u.name}</strong>
              <span className="mono" style={{ color:'var(--text-2)', minWidth: 50, textAlign:'right' }}>{v.toFixed(1)}h</span>
              <span className="mono muted" style={{ minWidth: 36, textAlign:'right' }}>{pct}%</span>
            </div>
          );
        })}
      </div>
    </div>
    </>
  );
}

/* ── Admin weekly digest card ── */
function AdminDigestCard({ refreshTick }) {
  const [digest, setDigest]   = useState(null);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  const fetchDigest = async () => {
    setLoading(true);
    try {
      const r = await fetch('/api/reports/admin-weekly-digest', { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      const data = await r.json();
      setDigest(data);
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل جلب الملخص: ' : 'Digest fetch failed: ') + e.message, kind: 'err' });
      setDigest(null);
    } finally {
      setLoading(false);
    }
  };

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

  return (
    <div className="card">
      <SectionHeader
        title={_rT("Admin weekly digest")}
          tip={_rT("Manager DM fired Mondays 09:00 local. Per-team summary: attendance, blockers, outliers. Triggered by _job_manager_weekly_digest.")}
        sub={digest ? (_rAr() ? `أسبوع ${digest.week_start} · أُنشئ في ${new Date(digest.generated_at).toLocaleString()}` : `Week of ${digest.week_start} · generated ${new Date(digest.generated_at).toLocaleString()}`) : _rT('Latest summary')}
        right={<Refresh onClick={fetchDigest} loading={loading} label={_rT("Refetch latest")} />}
      />
      {loading && <div className="muted" style={{ padding: 12, fontSize: 13 }}>{_rT("Loading digest…")}</div>}
      {!loading && !digest && (
        <Empty icon={<Icon name="chart" size={24}/>} title={_rT("No digest available")} subtitle={_rT("Digest generates automatically each week.")} />
      )}
      {!loading && digest && (
        <div>
          <table className="t" style={{ marginTop: 8 }}>
            <thead>
              <tr>
                <th>{_rT("Person")}</th>
                <th>{_rT("Team")}</th>
                <th style={{ textAlign:'right' }}>{_rT("Days present")}</th>
                <th style={{ textAlign:'right' }}>{_rT("Days late")}</th>
                <th style={{ textAlign:'right' }}>{_rT("Total hours")}</th>
                <th style={{ textAlign:'right' }}>{_rT("Violations")}</th>
              </tr>
            </thead>
            <tbody>
              {(digest.users || []).map(u => (
                <tr key={u.user_id}>
                  <td style={{ fontWeight: 500, fontSize: 13 }}>{u.display_name}</td>
                  <td className="muted" style={{ fontSize: 12 }}>{u.team || '—'}</td>
                  <td className="num" style={{ textAlign:'right' }}>{u.days_present}</td>
                  <td className="num" style={{ textAlign:'right', color: u.days_late > 0 ? 'var(--warn)' : undefined }}>{u.days_late}</td>
                  <td className="num" style={{ textAlign:'right' }}>{(u.total_hours || 0).toFixed(1)}h</td>
                  <td className="num" style={{ textAlign:'right', color: u.violations >= 3 ? 'var(--err)' : u.violations > 0 ? 'var(--warn)' : undefined }}>{u.violations}</td>
                </tr>
              ))}
              {(!digest.users || digest.users.length === 0) && (
                <tr><td colSpan={6}><div className="muted" style={{ padding:'8px 0', fontSize: 12 }}>{_rT("No employee data in this digest.")}</div></td></tr>
              )}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* ── Generate report form ── */
function GenerateReportForm({ employees, period, setPeriod }) {
  const [selectedUser, setSelectedUser] = useState('all');
  const [fmt, setFmt]   = useState('pdf');
  const [sendDm, setSendDm] = useState(false);
  const [busy, setBusy] = useState(false);
  const toast = useToast();

  const handleGenerate = async () => {
    setBusy(true);
    try {
      if (sendDm) {
        // Send via DM
        if (selectedUser === 'all') {
          const r = await fetch(`/api/reports/send-to-all?period=${period}`, {
            method: 'POST', credentials: 'same-origin',
          });
          if (!r.ok) throw new Error(await r.text());
          const data = await r.json();
          toast.push({ msg: _rAr() ? `تم إرسال التقرير إلى ${data.sent_count || 'الكل'} مستخدم عبر الرسائل المباشرة` : `Report sent to ${data.sent_count || 'all'} users via DM`, kind: 'ok' });
        } else {
          const r = await fetch(`/api/reports/send-to-user/${selectedUser}?period=${period}`, {
            method: 'POST', credentials: 'same-origin',
          });
          if (!r.ok) throw new Error(await r.text());
          const emp = employees.find(e => String(e.id) === String(selectedUser));
          toast.push({ msg: _rAr() ? `تم إرسال التقرير إلى ${emp?.display_name || selectedUser}` : `Report DM'd to ${emp?.display_name || selectedUser}`, kind: 'ok' });
        }
      } else {
        // Download
        const userQ = selectedUser === 'all' ? '' : `&user_id=${encodeURIComponent(selectedUser)}`;
        const url = `/api/summary/export?format=${fmt}&period=${period}${userQ}`;
        const r = await fetch(url, { credentials: 'same-origin' });
        if (!r.ok) throw new Error(`${r.status}`);
        const blob = await r.blob();
        const link = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = link;
        const suffix = selectedUser === 'all' ? 'all' : (employees.find(e => String(e.id) === String(selectedUser))?.display_name || selectedUser);
        a.download = `report-${suffix}-${period}.${fmt}`;
        a.click();
        // Defer revoke — Safari aborts in-progress downloads if revoked synchronously.
        setTimeout(() => URL.revokeObjectURL(link), 60000);
        toast.push({ msg: _rAr() ? `تم تنزيل تقرير ${fmt.toUpperCase()}` : `${fmt.toUpperCase()} report downloaded`, kind: 'ok' });
      }
    } catch(e) {
      toast.push({ msg: _rAr() ? `فشل: ${e.message}` : `Failed: ${e.message}`, kind: 'err' });
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="card">
      <SectionHeader
        title={_rT("Generate report")}
        sub={_rT("Download or send via DM")}
        tip={_rT("Builds a PDF report scoped to the selected employee + range. The PDF includes: hours-per-day line chart, attendance donut, PTO breakdown, top contributors bar, per-employee table. 'Send via DM' delivers the PDF to the employee's persistent DM with the bot.")}
      />
      <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap: 16, marginTop: 12 }}>
        <div>
          <label className="login-label">{_rT("Employee")}</label>
          <select className="sel" value={selectedUser} onChange={e => setSelectedUser(e.target.value)} style={{ width:'100%' }}>
            <option value="all">{_rT("All employees")}</option>
            {employees.map(e => <option key={e.id} value={e.id}>{e.display_name}</option>)}
          </select>
        </div>
        <div>
          <label className="login-label">{_rT("Period")}</label>
          <select className="sel" value={period} onChange={e => setPeriod(e.target.value)} style={{ width:'100%' }}>
            <option value="day">{_rT("Daily")}</option>
            <option value="week">{_rT("Weekly")}</option>
            <option value="month">{_rT("Monthly")}</option>
            <option value="quarter">{_rT("Quarterly")}</option>
            <option value="6_months">{_rT("Semi-annual (6 months)")}</option>
            <option value="annual">{_rT("Annual")}</option>
          </select>
        </div>
        <div>
          <label className="login-label">{_rT("Format")}</label>
          <Segmented value={fmt} onChange={setFmt} options={[{ value:'pdf', label:'PDF' }, { value:'xlsx', label:'XLSX' }]} />
        </div>
        <div style={{ display:'flex', flexDirection:'column', justifyContent:'flex-end' }}>
          <label className="login-label" style={{ display:'flex', alignItems:'center', gap: 8, cursor:'pointer' }}>
            <input
              type="checkbox"
              checked={sendDm}
              onChange={e => setSendDm(e.target.checked)}
              style={{ accentColor:'var(--brand)' }}
            />
            {_rT("Send via K9 DM instead of download")}
          </label>
        </div>
      </div>
      <div style={{ marginTop: 16 }}>
        <button className="btn btn-pri" onClick={handleGenerate} disabled={busy}>
          <Icon name="download" size={13}/>
          {busy ? _rT('Processing…') : sendDm ? _rT('Send via DM') : _rT('Download report')}
        </button>
      </div>
    </div>
  );
}

/* ── Leaderboards section ── */
const LEADERBOARD_METRICS = [
  { value: 'progress',    label: 'Progress' },
  { value: 'attendance',  label: 'Attendance' },
  { value: 'blockers',    label: 'Blockers' },
  { value: 'hours_max',   label: 'Most hours' },
  { value: 'hours_min',   label: 'Fewest hours' },
  { value: 'absence',     label: 'Absences' },
];

const MEDALS = ['🥇', '🥈', '🥉'];

function LeaderboardsSection() {
  const [metric, setMetric]   = React.useState('progress');
  const [period, setPeriod]   = React.useState('week');
  const [rows, setRows]       = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const toast = useToast();

  const load = async (m, p) => {
    setLoading(true);
    try {
      const r = await fetch(`/api/leaderboard?metric=${m}&period=${p}&limit=10`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(`${r.status}`);
      setRows(await r.json());
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل جلب لوحة المتصدرين: ' : 'Leaderboard fetch failed: ') + e.message, kind: 'err' });
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { load(metric, period); }, [metric, period]);

  const isHours = metric === 'hours_max' || metric === 'hours_min';

  const formatValue = (v) => isHours ? `${Number(v).toFixed(1)}h` : String(v);

  return (
    <div className="card" style={{ marginBottom: 16 }}>
      <SectionHeader
        title={_rT("Leaderboards")}
        sub={_rT("Top 10 by metric and period")}
        tip={_rT("Same data as Today's Top 10 widget but with selectable period (week / month / quarter / 6 months / year / annual). Switch metric to compare attendance, hours, blockers, absences, or progress score across employees.")}
      />

      {/* Metric tabs */}
      <div style={{ display:'flex', gap: 6, flexWrap:'wrap', marginTop: 12, marginBottom: 12 }}>
        {LEADERBOARD_METRICS.map(m => (
          <button
            key={m.value}
            className={metric === m.value ? 'btn btn-pri' : 'btn btn-ghost'}
            style={{ padding:'4px 12px', fontSize: 12 }}
            onClick={() => setMetric(m.value)}
          >
            {_rT(m.label)}
          </button>
        ))}
      </div>

      {/* Period radio */}
      <div style={{ display:'flex', gap: 12, marginBottom: 14, alignItems:'center' }}>
        <span className="muted" style={{ fontSize: 12 }}>{_rT("Period:")}</span>
        {[['day','Day'],['week','Week'],['month','Month'],['quarter','Quarter'],['6_months','Semi'],['annual','Annual']].map(([v,l]) => (
          <label key={v} style={{ fontSize: 12, cursor:'pointer', display:'flex', alignItems:'center', gap: 4 }}>
            <input type="radio" name="lb-period" value={v} checked={period === v} onChange={() => setPeriod(v)} />
            {_rT(l)}
          </label>
        ))}
      </div>

      {/* Results */}
      {loading && (
        <div style={{ display:'flex', flexDirection:'column', gap: 8 }}>
          {[...Array(5)].map((_,i) => (
            <div key={i} style={{ height: 36, background:'var(--bg-elev-2)', borderRadius:'var(--r-sm)', opacity: 0.5 + i*0.1 }} />
          ))}
        </div>
      )}
      {!loading && rows.length === 0 && (
        <Empty icon={<Icon name="chart" size={24}/>} title={_rT("No data")} subtitle={_rT("No records found for this metric and period.")} />
      )}
      {!loading && rows.length > 0 && (
        <div style={{ display:'flex', flexDirection:'column', gap: 6 }}>
          {rows.map((row) => {
            const medal = row.rank <= 3 ? MEDALS[row.rank - 1] : null;
            const avatarEl = (window.resolveAvatarUrl && (() => {
              const url = window.resolveAvatarUrl({ avatar_url: row.avatar_url });
              return url
                ? <img src={url} style={{ width:28, height:28, borderRadius:'50%', objectFit:'cover', flexShrink:0 }} onError={e => { e.target.style.display='none'; }} />
                : <div style={{ width:28, height:28, borderRadius:'50%', background:'var(--bg-elev-3)', flexShrink:0, display:'flex', alignItems:'center', justifyContent:'center', fontSize:11, color:'var(--text-3)' }}>{(row.display_name||'?')[0].toUpperCase()}</div>;
            })()) || <div style={{ width:28, height:28, borderRadius:'50%', background:'var(--bg-elev-3)', flexShrink:0 }} />;

            return (
              <div key={row.user_id} style={{ display:'flex', alignItems:'center', gap: 10, padding:'6px 10px', background:'var(--bg-elev-2)', borderRadius:'var(--r-sm)', border:'1px solid var(--line)' }}>
                <span style={{ width: 28, textAlign:'center', fontWeight: 700, fontSize: 13, color: medal ? 'inherit' : 'var(--text-3)', flexShrink:0 }}>
                  {medal || `#${row.rank}`}
                </span>
                {avatarEl}
                <span style={{ flex: 1, fontSize: 13, fontWeight: 500, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                  {row.display_name}
                </span>
                <span className="mono" style={{ fontSize: 13, fontWeight: 700, color:'var(--brand)', flexShrink:0 }}>
                  {formatValue(row.value)}
                </span>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

/* ── Main ReportsPage ── */
function ReportsPage() {
  const D = window.STATUS_DATA;
  const toast = useToast ? useToast() : { push: () => {} };
  const [period, setPeriod] = React.useState('week');
  const [refreshTick, setRefreshTick] = React.useState(0);
  const toastTop = useToast ? useToast() : { push: () => {} };

  const employees = D.EMPLOYEES || [];

  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) {}
    toastTop.push({ msg: _rT('Refresh complete'), kind: 'ok' });
  };

  return (
    <div className="page">
      <PageHeader
        title={_rT("Reports")}
        meta={_rT("Generate, download, or send reports via DM")}
        right={
          <div style={{ display:'flex', gap: 8, alignItems:'center' }}>
            <Refresh onClick={handleRefresh} loading={false} />
            <Segmented
              value={period}
              onChange={setPeriod}
              options={[
                { value:'day',      label:_rT('Daily') },
                { value:'week',     label:_rT('Weekly') },
                { value:'month',    label:_rT('Monthly') },
                { value:'quarter',  label:_rT('Quarter') },
                { value:'6_months', label:_rT('Semi') },
                { value:'annual',   label:_rT('Annual') },
              ]}
            />
          </div>
        }
      />

      {/* Leaderboards */}
      <LeaderboardsSection />

      {/* Charts */}
      <ChartsSection />

      {/* On-call standings moved to the On-call tab — see page-oncall.jsx.
          The component itself stays defined below so window.OnCallStandingsSection
          (set at the function's bottom) remains importable from the On-call
          page bundle without a duplicate definition. */}

      {/* Generate report form */}
      <GenerateReportForm employees={employees} period={period} setPeriod={setPeriod} />

      {/* Admin digest */}
      <div style={{ marginTop: 16 }}>
        <AdminDigestCard refreshTick={refreshTick} />
      </div>

      {/* Scheduled reports (#18) */}
      <AutoReportSchedule />

      {/* Violations (#25) */}
      <ViolationsSection />

      {/* Per-user trends (#25) */}
      <PerUserTrendsCard refreshTick={refreshTick} />

      {/* B7: per-employee violations report with type filter */}
      <PerEmployeeViolationsCard refreshTick={refreshTick} />

      {/* Hours distribution */}
      <div className="card" style={{ marginTop: 16 }}>
        <SectionHeader
          title={_rT("Hours distribution")}
          tip={_rT("Histogram of daily-hours bins across all employees in the range. Spot under/over-work patterns.")}
          sub={_rT("Per employee — stacked by day · use the Range dropdown to scope")}
        />
        <HoursDistributionChart period={period} refreshTick={refreshTick} />
      </div>
    </div>
  );
}

/* ── Per-user picker for a scheduled report row ── */
// Admin chooses individual recipients OR "all employees together" with one
// click. Replaces the old comma-separated user-id text input with a real
// employee checklist (name + matrix_id) sourced from window.STATUS_DATA.
function ScheduledReportUserPicker({ selectedIds, onSave, onCancel }) {
  const D = window.STATUS_DATA || {};
  const employees = (D.EMPLOYEES || []).filter(e => !e.is_test_account);
  const [sel, setSel] = useState(() => new Set((selectedIds || []).map(String)));
  const [q, setQ]     = useState('');

  const toggle = (id) => setSel(prev => {
    const next = new Set(prev);
    const s = String(id);
    if (next.has(s)) next.delete(s); else next.add(s);
    return next;
  });
  const selectAll = () => setSel(new Set(employees.map(e => String(e.id))));
  const clearAll  = () => setSel(new Set());

  const filtered = employees.filter(e => {
    const t = q.trim().toLowerCase();
    if (!t) return true;
    return (e.display_name || '').toLowerCase().includes(t)
        || (e.matrix_id    || '').toLowerCase().includes(t);
  });

  return (
    <div>
      <div style={{ display:'flex', alignItems:'center', gap: 10, marginBottom: 8 }}>
        <input className="inp" placeholder={_rT("Search…")} value={q}
          onChange={e => setQ(e.target.value)}
          style={{ flex: 1, fontSize: 12, padding:'4px 8px' }} />
        <button className="btn btn-ghost" style={{ fontSize: 11, padding:'3px 8px' }}
          onClick={selectAll}>{_rAr() ? `تحديد الكل (${employees.length})` : `Select all (${employees.length})`}</button>
        <button className="btn btn-ghost" style={{ fontSize: 11, padding:'3px 8px' }}
          onClick={clearAll}>{_rT("Clear")}</button>
        <span className="muted" style={{ fontSize: 11 }}>{_rAr() ? `${sel.size} محدد` : `${sel.size} picked`}</span>
      </div>
      <div style={{
        maxHeight: 220, overflowY:'auto',
        border:'1px solid var(--line)', borderRadius:'var(--r-sm)',
        background:'var(--bg)',
        display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(220px, 1fr))',
        padding: 6, gap: 2,
      }}>
        {filtered.length === 0 && (
          <div className="muted" style={{ fontSize: 12, padding: 8 }}>{_rT("No employees match")}</div>
        )}
        {filtered.map(e => {
          const on = sel.has(String(e.id));
          return (
            <label key={e.id} style={{
              display:'flex', alignItems:'center', gap: 8, padding:'4px 8px',
              fontSize: 12.5, cursor:'pointer', borderRadius:'var(--r-xs)',
              background: on ? 'var(--brand-soft)' : 'transparent',
            }}>
              <input type="checkbox" checked={on} onChange={() => toggle(e.id)} />
              <span style={{ flex: 1, color:'var(--text)' }}>{e.display_name}</span>
              <span className="mono" style={{ fontSize: 10.5, color:'var(--text-3)' }}>
                {e.matrix_id}
              </span>
            </label>
          );
        })}
      </div>
      <div style={{ display:'flex', justifyContent:'flex-end', gap: 8, marginTop: 10 }}>
        <button className="btn btn-ghost" onClick={onCancel} style={{ fontSize: 12 }}>
          {_rT("Cancel")}
        </button>
        <button className="btn btn-pri" onClick={() => onSave([...sel])} style={{ fontSize: 12 }}>
          {_rAr() ? `حفظ ${sel.size} مستلم` : `Save ${sel.size} recipient${sel.size === 1 ? '' : 's'}`}
        </button>
      </div>
    </div>
  );
}

/* ── Auto-Report Scheduling panel (Bug 18 — restored + scheduler jobs table) ── */
function AutoReportSchedule() {
  // Q10: full admin-managed scheduled-report surface.
  // GET /api/scheduled-reports  → list items with enabled, recipients_kind,
  //   recipient_ids, channel, last_run_at/status/count, next_run_at.
  // PATCH /api/scheduled-reports/{cadence_key} updates a single row.
  // POST /api/scheduled-reports/{cadence_key}/run-now fires immediately.
  const [items, setItems] = useState([]);
  const [isAdmin, setIsAdmin] = useState(true);
  const [busy, setBusy] = useState(null);
  const [jobs, setJobs] = useState([]);
  const [editing, setEditing] = useState(null);  // cadence_key being edited
  const toast = useToast();

  const reload = async () => {
    try {
      const r = await fetch('/api/scheduled-reports', { credentials: 'same-origin' });
      if (r.status === 403) { setIsAdmin(false); return; }
      if (r.ok) { const d = await r.json(); setItems(d.items || []); setIsAdmin(true); }
    } catch(_) {}
  };

  const reloadJobs = async () => {
    try {
      const r = await fetch('/api/server-health', { credentials: 'same-origin' });
      if (r.ok) {
        const d = await r.json();
        setJobs(Array.isArray(d.scheduler_jobs) ? d.scheduler_jobs : []);
      }
    } catch(_) {}
  };

  useEffect(() => { reload(); reloadJobs(); }, []);

  const patch = async (cadence_key, body) => {
    setBusy(cadence_key);
    try {
      const r = await fetch(`/api/scheduled-reports/${cadence_key}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'same-origin',
        body: JSON.stringify(body),
      });
      if (!r.ok) throw new Error(parseDetail(await r.json().catch(() => null), r.status));
      toast.push({ msg: _rAr() ? `تم تحديث ${cadence_key}` : `Updated ${cadence_key}`, kind: 'ok' });
      await reload();
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل التحديث: ' : 'Update failed: ') + e.message, kind: 'err' });
    } finally { setBusy(null); }
  };

  const runNow = async (cadence_key) => {
    setBusy(cadence_key);
    try {
      const r = await fetch(`/api/scheduled-reports/${cadence_key}/run-now`, {
        method: 'POST', credentials: 'same-origin',
      });
      if (!r.ok) throw new Error(parseDetail(await r.json().catch(() => null), r.status));
      toast.push({ msg: _rT('Report fired'), kind: 'ok' });
      await reload();
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل التشغيل: ' : 'Run failed: ') + e.message, kind: 'err' });
    } finally { setBusy(null); }
  };

  const fmtRel = (iso) => {
    if (!iso) return '—';
    try {
      const d = new Date(iso);
      const diff = (d.getTime() - Date.now()) / 1000;
      const abs = Math.abs(diff);
      const ar = _rAr();
      const sign = diff < 0 ? (ar ? 'مضت' : 'ago') : (ar ? 'خلال' : 'in');
      if (abs < 60)      return diff < 0 ? (ar ? 'الآن' : 'just now') : (ar ? 'الآن' : 'now');
      if (abs < 3600)    return ar ? `${sign} ${Math.round(abs/60)} دقيقة` : `${Math.round(abs/60)}m ${sign}`;
      if (abs < 86400)   return ar ? `${sign} ${Math.round(abs/3600)} ساعة` : `${Math.round(abs/3600)}h ${sign}`;
      return d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'});
    } catch (_) { return iso; }
  };

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("Scheduled reports")}
        tip={_rT("Admin-managed scheduled report dispatch. Toggle each cadence on/off, pick recipients (employees / admins / specific users / room), pick channel, and see last-run + next-run.")}
        sub={_rT("Each cadence runs on its cron; PATCH updates take effect on the next firing.")}
        right={<Refresh onClick={() => { reload(); reloadJobs(); }} loading={false} label={_rT("Refresh")} />}
      />

      {!isAdmin ? (
        <div className="muted" style={{ fontSize: 13, padding: '8px 0' }}>
          {_rT("Admins only. Ask an admin to configure scheduled reports.")}
        </div>
      ) : (
        <table className="t" style={{ fontSize: 12, marginBottom: 16 }}>
          <thead>
            <tr>
              <th>{_rT("Cadence")}</th><th>{_rT("Cron")}</th><th>{_rT("Enabled")}</th>
              <th>{_rT("Recipients")}</th><th>{_rT("Channel")}</th>
              <th>{_rT("Last run")}</th><th>{_rT("Next run")}</th><th></th>
            </tr>
          </thead>
          <tbody>
            {items.map(it => (
              <React.Fragment key={it.cadence_key}>
                <tr>
                  <td style={{ fontWeight: 600 }}>{it.label}</td>
                  <td className="mono muted" style={{ fontSize: 11 }}>{it.cron}</td>
                  <td>
                    <label style={{ display:'flex', alignItems:'center', gap:6, cursor: busy === it.cadence_key ? 'wait' : 'pointer' }}>
                      <input type="checkbox" checked={!!it.enabled}
                        disabled={busy === it.cadence_key}
                        onChange={e => patch(it.cadence_key, { enabled: e.target.checked })} />
                      <span style={{ fontSize:11, color: it.enabled ? 'var(--ok)' : 'var(--text-3)' }}>
                        {it.enabled ? _rT('ON') : _rT('OFF')}
                      </span>
                    </label>
                  </td>
                  <td>
                    <select className="sel" value={it.recipients_kind}
                      disabled={busy === it.cadence_key}
                      onChange={e => patch(it.cadence_key, { recipients_kind: e.target.value })}
                      style={{ fontSize: 11, padding: '2px 6px' }}>
                      <option value="employees">{_rT("Every employee")}</option>
                      <option value="admins">{_rT("Admins only")}</option>
                      <option value="users">{_rT("Specific users")}</option>
                      <option value="room">{_rT("Matrix room")}</option>
                    </select>
                    {(it.recipients_kind === 'users' || it.recipients_kind === 'room') && (
                      <button className="btn btn-ghost"
                        style={{ marginLeft: 6, padding: '1px 6px', fontSize: 11 }}
                        onClick={() => setEditing(editing === it.cadence_key ? null : it.cadence_key)}>
                        {_rAr() ? `${(it.recipient_ids || []).length} محدد` : `${(it.recipient_ids || []).length} set`}
                      </button>
                    )}
                  </td>
                  <td>
                    <select className="sel" value={it.channel}
                      disabled={busy === it.cadence_key}
                      onChange={e => patch(it.cadence_key, { channel: e.target.value })}
                      style={{ fontSize: 11, padding: '2px 6px' }}>
                      <option value="dm">{_rT("DM")}</option>
                      <option value="room">{_rT("Room post")}</option>
                    </select>
                  </td>
                  <td className="mono" style={{ fontSize: 11 }}>
                    <span title={it.last_run_at || ''}>{fmtRel(it.last_run_at)}</span>
                    {it.last_run_status && (
                      <span style={{
                        marginLeft: 6, fontSize: 10, padding: '1px 5px',
                        borderRadius: 3,
                        background: it.last_run_status === 'ok' ? 'rgba(20,180,80,.15)' :
                                    it.last_run_status === 'partial' ? 'rgba(220,180,30,.18)' : 'rgba(220,80,80,.18)',
                        color: it.last_run_status === 'ok' ? 'var(--ok)' :
                               it.last_run_status === 'partial' ? '#daa30a' : 'var(--err)',
                      }}>{it.last_run_status} · {it.last_run_count}</span>
                    )}
                  </td>
                  <td className="mono muted" style={{ fontSize: 11 }} title={it.next_run_at || ''}>
                    {fmtRel(it.next_run_at)}
                  </td>
                  <td>
                    <button className="btn btn-ghost" style={{ padding:'2px 8px', fontSize:11 }}
                      disabled={busy === it.cadence_key}
                      onClick={() => runNow(it.cadence_key)}>{_rT("Run now")}</button>
                  </td>
                </tr>
                {editing === it.cadence_key && (
                  <tr>
                    <td colSpan={8} style={{ background:'var(--bg-elev-2)', padding:'10px 12px' }}>
                      {it.recipients_kind === 'room' ? (
                        <>
                          <div style={{ fontSize:11, color:'var(--text-3)', marginBottom:4 }}>
                            {_rT("Matrix room ID (e.g. !abc:k9.ms):")}
                          </div>
                          <input className="inp" defaultValue={(it.recipient_ids || [])[0] || ''}
                            style={{ width: '100%', fontSize: 12, fontFamily: 'var(--font-mono)' }}
                            onBlur={e => {
                              const v = e.target.value.trim();
                              patch(it.cadence_key, { recipient_ids: v ? [v] : [] });
                              setEditing(null);
                            }} />
                        </>
                      ) : (
                        // Per-user / all-users picker. Checklist of every
                        // employee — admin ticks the ones who should
                        // receive this cadence. "Select all" + "Clear"
                        // shortcuts make all-users vs per-user trivial.
                        <ScheduledReportUserPicker
                          selectedIds={it.recipient_ids || []}
                          onSave={(ids) => {
                            patch(it.cadence_key, { recipient_ids: ids });
                            setEditing(null);
                          }}
                          onCancel={() => setEditing(null)}
                        />
                      )}
                    </td>
                  </tr>
                )}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      )}

      {jobs.length > 0 && (
        <>
          <div style={{ fontSize:12, fontWeight:600, color:'var(--text-2)', marginBottom:8, marginTop: isAdmin ? 8 : 0 }}>
            {_rT("Active scheduler jobs")}
          </div>
          <table className="t" style={{ fontSize:12 }}>
            <thead>
              <tr>
                <th>{_rT("Job name")}</th>
                <th>{_rT("Cron / trigger")}</th>
                <th>{_rT("Next run")}</th>
              </tr>
            </thead>
            <tbody>
              {jobs.map((j, i) => (
                <tr key={i}>
                  <td style={{ fontWeight:500 }}>{j.name}</td>
                  <td className="mono muted" style={{ fontSize:11 }}>{j.cron || '—'}</td>
                  <td className="mono" style={{ fontSize:11 }}>
                    {j.next ? new Date(j.next).toLocaleString() : '—'}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </>
      )}
    </div>
  );
}

/* ── Charts: period → API range param mapping ── */
const CHART_PERIODS = [
  { value: 'day',   label: 'Day',   range: 'daily'   },
  { value: 'week',  label: 'Week',  range: 'weekly'  },
  { value: 'month', label: 'Month', range: 'monthly' },
];

/* ── Chart 1: Stacked bar — daily attendance breakdown ── */
function AttendanceStackedBar({ range }) {
  const [data, setData]     = useState(null);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  useEffect(() => {
    if (!range) return;
    setLoading(true);
    Promise.allSettled([
      fetch(`/api/reports/timeseries?range=${range}&metric=present`, { credentials: 'same-origin' }).then(r => r.ok ? r.json() : Promise.reject(r.status)),
      fetch(`/api/reports/timeseries?range=${range}&metric=late`,    { credentials: 'same-origin' }).then(r => r.ok ? r.json() : Promise.reject(r.status)),
    ]).then((results) => {
      const presentData = results[0].status === 'fulfilled' ? results[0].value : { labels: [], datasets: [] };
      const lateData    = results[1].status === 'fulfilled' ? results[1].value : { labels: [], datasets: [] };
      const _ts_anyOk = results[0].status === 'fulfilled' || results[1].status === 'fulfilled';
      if (!_ts_anyOk) { setLoading(false); return; }
      // Continue with whichever metric(s) succeeded.
      void _ts_anyOk;
      const labels = presentData.labels || [];
      const numUsers = presentData.datasets ? presentData.datasets.length : 0;

      // Sum across users per day
      const presentPerDay = labels.map((_, i) =>
        (presentData.datasets || []).reduce((s, ds) => s + (ds.data[i] || 0), 0)
      );
      const latePerDay = labels.map((_, i) =>
        (lateData.datasets || []).reduce((s, ds) => s + (ds.data[i] || 0), 0)
      );
      // on_time = present but not late
      const onTimePerDay = labels.map((_, i) => Math.max(0, presentPerDay[i] - latePerDay[i]));
      const absentPerDay = labels.map((_, i) => Math.max(0, numUsers - presentPerDay[i]));

      setData({ labels, onTimePerDay, latePerDay, absentPerDay, numUsers });
    }).catch(e => {
      toast.push({ msg: (_rAr() ? 'فشل جلب مخطط الحضور: ' : 'Attendance chart fetch failed: ') + e, kind: 'err' });
      setData(null);
    }).finally(() => setLoading(false));
  }, [range]);

  if (loading) return <div className="muted" style={{ padding: '20px 0', fontSize: 13, textAlign:'center' }}>{_rT("Loading…")}</div>;
  if (!data || !data.labels.length) return <Empty icon={<Icon name="chart" size={24}/>} title={_rT("No attendance data")} subtitle={_rT("No records for this period.")} />;

  const { labels, onTimePerDay, latePerDay, absentPerDay } = data;
  const maxVal = Math.max(...labels.map((_, i) => onTimePerDay[i] + latePerDay[i] + absentPerDay[i]), 1);

  const SVG_W = 480, SVG_H = 180, PAD_L = 28, PAD_B = 36, PAD_T = 12, PAD_R = 12;
  const chartW = SVG_W - PAD_L - PAD_R;
  const chartH = SVG_H - PAD_B - PAD_T;
  const n = labels.length;
  const barW = Math.max(4, Math.min(30, (chartW / n) * 0.7));
  const gap   = chartW / n;

  const toY  = (v) => PAD_T + chartH - (v / maxVal) * chartH;
  const toH  = (v) => (v / maxVal) * chartH;

  // X-axis labels — show every Nth
  const labelStep = Math.ceil(n / 8);
  const fmtLabel = (iso) => {
    const d = new Date(iso + 'T00:00:00');
    return `${d.getMonth()+1}/${d.getDate()}`;
  };

  const COLORS = { onTime: '#10b981', late: '#f59e0b', absent: '#f43f5e' };

  return (
    <div>
      <svg width="100%" viewBox={`0 0 ${SVG_W} ${SVG_H}`} style={{ overflow:'visible', display:'block' }}>
        {/* Y gridlines */}
        {[0,0.25,0.5,0.75,1].map(f => {
          const y = PAD_T + chartH - f * chartH;
          return (
            <g key={f}>
              <line x1={PAD_L} y1={y} x2={SVG_W - PAD_R} y2={y} stroke="var(--line)" strokeWidth={0.5} strokeDasharray="3,3" />
              <text x={PAD_L - 4} y={y + 4} textAnchor="end" fill="var(--text-3)" fontSize={8} fontFamily="var(--font-mono)">{Math.round(f * maxVal)}</text>
            </g>
          );
        })}
        {/* Bars */}
        {labels.map((label, i) => {
          const cx = PAD_L + i * gap + gap / 2;
          const x  = cx - barW / 2;
          const h1 = toH(onTimePerDay[i]);
          const h2 = toH(latePerDay[i]);
          const h3 = toH(absentPerDay[i]);
          const y1 = PAD_T + chartH - h1;
          const y2 = y1 - h2;
          const y3 = y2 - h3;
          return (
            <g key={label}>
              {onTimePerDay[i] > 0 && <rect x={x} y={y1} width={barW} height={h1} fill={COLORS.onTime} rx={1}>
                <title>{`${fmtLabel(label)}\n${_rT("On time")}: ${onTimePerDay[i]}`}</title>
              </rect>}
              {latePerDay[i] > 0 && <rect x={x} y={y2} width={barW} height={h2} fill={COLORS.late} rx={1}>
                <title>{`${fmtLabel(label)}\n${_rT("Late")}: ${latePerDay[i]}`}</title>
              </rect>}
              {absentPerDay[i] > 0 && <rect x={x} y={y3} width={barW} height={h3} fill={COLORS.absent} rx={1} fillOpacity={0.6}>
                <title>{`${fmtLabel(label)}\n${_rT("Absent")}: ${absentPerDay[i]}`}</title>
              </rect>}
              {i % labelStep === 0 && (
                <text x={cx} y={SVG_H - 4} textAnchor="middle" fill="var(--text-3)" fontSize={8} fontFamily="var(--font-mono)">{fmtLabel(label)}</text>
              )}
            </g>
          );
        })}
        {/* Axes */}
        <line x1={PAD_L} y1={PAD_T} x2={PAD_L} y2={PAD_T + chartH} stroke="var(--line)" strokeWidth={1} />
        <line x1={PAD_L} y1={PAD_T + chartH} x2={SVG_W - PAD_R} y2={PAD_T + chartH} stroke="var(--line)" strokeWidth={1} />
      </svg>
      {/* Legend */}
      <div style={{ display:'flex', gap: 16, marginTop: 8, fontSize: 11, flexWrap:'wrap' }}>
        {[['On time', COLORS.onTime, 1], ['Late', COLORS.late, 1], ['Absent', COLORS.absent, 0.6]].map(([l, c, op]) => (
          <span key={l} style={{ display:'flex', alignItems:'center', gap: 5 }}>
            <span style={{ width:10, height:10, borderRadius:2, background:c, opacity:op, display:'inline-block' }}/>
            <span style={{ color:'var(--text-2)' }}>{_rT(l)}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

/* ── Chart 2: Line chart — total hours per day ── */
function HoursTrendLine({ range }) {
  const [data, setData]     = useState(null);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  useEffect(() => {
    if (!range) return;
    setLoading(true);
    fetch(`/api/reports/timeseries?range=${range}&metric=hours`, { credentials: 'same-origin' })
      .then(r => r.ok ? r.json() : Promise.reject(r.status))
      .then(raw => {
        const labels = raw.labels || [];
        const hoursPerDay = labels.map((_, i) =>
          (raw.datasets || []).reduce((s, ds) => s + (ds.data[i] || 0), 0)
        );
        setData({ labels, hoursPerDay });
      })
      .catch(e => {
        toast.push({ msg: (_rAr() ? 'فشل جلب مخطط الساعات: ' : 'Hours chart fetch failed: ') + e, kind: 'err' });
        setData(null);
      })
      .finally(() => setLoading(false));
  }, [range]);

  if (loading) return <div className="muted" style={{ padding: '20px 0', fontSize: 13, textAlign:'center' }}>{_rT("Loading…")}</div>;
  if (!data || !data.labels.length) return <Empty icon={<Icon name="chart" size={24}/>} title={_rT("No hours data")} subtitle={_rT("No records for this period.")} />;

  const { labels, hoursPerDay } = data;
  const maxVal = Math.max(...hoursPerDay, 1);
  const minVal = 0;

  const SVG_W = 480, SVG_H = 180, PAD_L = 32, PAD_B = 36, PAD_T = 12, PAD_R = 12;
  const chartW = SVG_W - PAD_L - PAD_R;
  const chartH = SVG_H - PAD_B - PAD_T;
  const n = labels.length;

  const toX = (i) => PAD_L + (i / Math.max(n - 1, 1)) * chartW;
  const toY = (v) => PAD_T + chartH - ((v - minVal) / (maxVal - minVal)) * chartH;

  const labelStep = Math.ceil(n / 8);
  const fmtLabel  = (iso) => { const d = new Date(iso + 'T00:00:00'); return `${d.getMonth()+1}/${d.getDate()}`; };

  const pts = labels.map((_, i) => `${toX(i)},${toY(hoursPerDay[i])}`).join(' ');
  const fillPts = `${PAD_L},${PAD_T + chartH} ${pts} ${toX(n-1)},${PAD_T + chartH}`;

  return (
    <div>
      <svg width="100%" viewBox={`0 0 ${SVG_W} ${SVG_H}`} style={{ overflow:'visible', display:'block' }}>
        <defs>
          <linearGradient id="hoursGrad" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#0ea5e9" stopOpacity="0.35" />
            <stop offset="100%" stopColor="#0ea5e9" stopOpacity="0.03" />
          </linearGradient>
        </defs>
        {/* Y gridlines */}
        {[0, 0.25, 0.5, 0.75, 1].map(f => {
          const y = PAD_T + chartH - f * chartH;
          const v = Math.round(f * maxVal);
          return (
            <g key={f}>
              <line x1={PAD_L} y1={y} x2={SVG_W - PAD_R} y2={y} stroke="var(--line)" strokeWidth={0.5} strokeDasharray="3,3"/>
              <text x={PAD_L - 4} y={y + 4} textAnchor="end" fill="var(--text-3)" fontSize={8} fontFamily="var(--font-mono)">{v}h</text>
            </g>
          );
        })}
        {/* Fill */}
        {n > 1 && <polygon points={fillPts} fill="url(#hoursGrad)" />}
        {/* Line */}
        {n > 1 && <polyline points={pts} fill="none" stroke="#0ea5e9" strokeWidth={2} strokeLinejoin="round" strokeLinecap="round" />}
        {/* Dots + tooltips */}
        {labels.map((label, i) => (
          <circle key={label} cx={toX(i)} cy={toY(hoursPerDay[i])} r={3} fill="#0ea5e9" stroke="var(--bg)" strokeWidth={1.5}>
            <title>{`${fmtLabel(label)}: ${hoursPerDay[i].toFixed(1)}h`}</title>
          </circle>
        ))}
        {/* X labels */}
        {labels.map((label, i) => i % labelStep === 0 && (
          <text key={label} x={toX(i)} y={SVG_H - 4} textAnchor="middle" fill="var(--text-3)" fontSize={8} fontFamily="var(--font-mono)">{fmtLabel(label)}</text>
        ))}
        {/* Axes */}
        <line x1={PAD_L} y1={PAD_T} x2={PAD_L} y2={PAD_T + chartH} stroke="var(--line)" strokeWidth={1}/>
        <line x1={PAD_L} y1={PAD_T + chartH} x2={SVG_W - PAD_R} y2={PAD_T + chartH} stroke="var(--line)" strokeWidth={1}/>
      </svg>
      <div style={{ fontSize:11, color:'var(--text-3)', marginTop: 6, textAlign:'center' }}>{_rT("Total workforce hours/day")}</div>
    </div>
  );
}

/* ── Chart 3: Donut — status distribution ── */
function StatusDonut({ range, periodLabel }) {
  const [data, setData]     = useState(null);
  const [loading, setLoading] = useState(false);
  const [hovered, setHovered] = useState(null);
  const toast = useToast();

  useEffect(() => {
    if (!range) return;
    setLoading(true);
    fetch(`/api/reports/distribution?range=${range}`, { credentials: 'same-origin' })
      .then(r => r.ok ? r.json() : Promise.reject(r.status))
      .then(raw => {
        const labels = (raw.attendance && raw.attendance.labels) || [];
        const counts = (raw.attendance && raw.attendance.data)   || [];
        setData({ labels, counts });
      })
      .catch(e => {
        toast.push({ msg: (_rAr() ? 'فشل جلب التوزيع: ' : 'Distribution fetch failed: ') + e, kind: 'err' });
        setData(null);
      })
      .finally(() => setLoading(false));
  }, [range]);

  if (loading) return <div className="muted" style={{ padding: '20px 0', fontSize: 13, textAlign:'center' }}>{_rT("Loading…")}</div>;
  if (!data || !data.labels.length) return <Empty icon={<Icon name="chart" size={24}/>} title={_rT("No distribution data")} subtitle={_rT("No records for this period.")} />;

  const { labels, counts } = data;
  const total = counts.reduce((s, v) => s + v, 0) || 1;
  // Color map by label substring
  const labelColor = (l) => {
    const ll = l.toLowerCase();
    if (ll.includes('late'))    return '#f59e0b';
    if (ll.includes('absent'))  return '#f43f5e';
    if (ll.includes('sign'))    return '#8b5cf6';
    if (ll.includes('present')) return '#10b981';
    return '#0ea5e9';
  };

  const SIZE = 180, R = 70, IR = 46, CX = SIZE/2, CY = SIZE/2;
  const C = 2 * Math.PI * R;

  // Build slices
  let cumAngle = -Math.PI / 2; // start at top
  const slices = labels.map((label, i) => {
    const v = counts[i] || 0;
    if (!v) return null;
    const frac  = v / total;
    const angle = frac * 2 * Math.PI;
    const x1 = CX + R * Math.cos(cumAngle);
    const y1 = CY + R * Math.sin(cumAngle);
    cumAngle += angle;
    const x2 = CX + R * Math.cos(cumAngle);
    const y2 = CY + R * Math.sin(cumAngle);
    const ix1 = CX + IR * Math.cos(cumAngle - angle);
    const iy1 = CY + IR * Math.sin(cumAngle - angle);
    const ix2 = CX + IR * Math.cos(cumAngle);
    const iy2 = CY + IR * Math.sin(cumAngle);
    const large = angle > Math.PI ? 1 : 0;
    const d = `M ${ix1} ${iy1} L ${x1} ${y1} A ${R} ${R} 0 ${large} 1 ${x2} ${y2} L ${ix2} ${iy2} A ${IR} ${IR} 0 ${large} 0 ${ix1} ${iy1} Z`;
    const color = labelColor(label);
    const isHov = hovered === i;
    return (
      <path
        key={label}
        d={d}
        fill={color}
        fillOpacity={isHov ? 1 : 0.85}
        stroke="var(--bg)"
        strokeWidth={isHov ? 2 : 1}
        style={{ cursor:'pointer', transition:'fill-opacity 0.15s' }}
        onMouseEnter={() => setHovered(i)}
        onMouseLeave={() => setHovered(null)}
      >
        <title>{`${label}: ${v} (${Math.round(v/total*100)}%)`}</title>
      </path>
    );
  }).filter(Boolean);

  // Center label
  const hovLabel = hovered != null ? labels[hovered] : periodLabel;
  const hovCount = hovered != null ? counts[hovered] : total;
  const hovPct   = hovered != null ? `${Math.round(counts[hovered]/total*100)}%` : _rT('total');

  return (
    <div style={{ display:'flex', gap: 24, alignItems:'center', flexWrap:'wrap' }}>
      <svg width={SIZE} height={SIZE} viewBox={`0 0 ${SIZE} ${SIZE}`} style={{ flexShrink:0 }}>
        <circle cx={CX} cy={CY} r={R}  fill="none" stroke="var(--line)" strokeWidth={1} />
        <circle cx={CX} cy={CY} r={IR} fill="var(--bg-elev)" />
        {slices}
        <text x={CX} y={CY - 8} textAnchor="middle" fill="var(--text)" fontSize={15} fontWeight={700} fontFamily="var(--font-mono)">{hovCount}</text>
        <text x={CX} y={CY + 6} textAnchor="middle" fill="var(--text-3)" fontSize={8}  fontFamily="var(--font-mono)">{hovPct}</text>
        <text x={CX} y={CY + 18} textAnchor="middle" fill="var(--text-3)" fontSize={7.5} fontFamily="var(--font-mono)">{hovLabel}</text>
      </svg>
      <div style={{ flex:1, minWidth:140, display:'flex', flexDirection:'column', gap: 7 }}>
        {labels.map((label, i) => {
          const v = counts[i] || 0;
          const pct = Math.round(v / total * 100);
          const color = labelColor(label);
          return (
            <div key={label} style={{ display:'flex', alignItems:'center', gap: 8, fontSize: 12, cursor:'default' }}
              onMouseEnter={() => setHovered(i)} onMouseLeave={() => setHovered(null)}>
              <span style={{ width:10, height:10, borderRadius:2, background:color, flexShrink:0, opacity: hovered === i ? 1 : 0.85 }}/>
              <span style={{ flex:1, color:'var(--text-2)' }}>{label}</span>
              <span className="mono" style={{ color:'var(--text)', minWidth:28, textAlign:'right', fontWeight:600 }}>{v}</span>
              <span className="mono muted" style={{ minWidth:32, textAlign:'right' }}>{pct}%</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ── On-call standings section ── */
function OnCallStandingsSection() {
  const [period, setPeriod] = useState('30d');
  const [team, setTeam]     = useState('');
  const [data, setData]     = useState(null);
  const [loading, setLoading] = useState(false);
  const toast = useToast();

  const PERIODS = [
    { value: '7d',  label: _rT('7 days') },
    { value: '30d', label: _rT('30 days') },
    { value: '90d', label: _rT('90 days') },
  ];

  const load = async (p, t) => {
    setLoading(true);
    try {
      const qs = `period=${p}${t ? `&team=${encodeURIComponent(t)}` : ''}`;
      const r = await fetch(`/api/oncall/metrics?${qs}`, { credentials: 'same-origin' });
      if (!r.ok) throw new Error(await r.text());
      setData(await r.json());
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل جلب مقاييس المناوبة: ' : 'On-call metrics fetch failed: ') + e.message, kind: 'err' });
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { load(period, team); }, [period, team]);

  const cardStyle = {
    flex: '1 1 140px',
    background: 'var(--surface-2)',
    borderRadius: 10,
    padding: '14px 18px',
    textAlign: 'center',
  };

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("On-call standings")}
          tip={_rT("Per-user on-call coverage stats — shifts, hours covered, response time avg. Defensive metric for fair-rotation review.")}
        sub={_rT("Shift counts, hours on call, and escalations by period")}
        right={
          <div style={{ display:'flex', gap: 6, alignItems:'center', flexWrap:'wrap' }}>
            {PERIODS.map(p => (
              <button
                key={p.value}
                className={period === p.value ? 'btn btn-pri' : 'btn btn-ghost'}
                style={{ padding:'3px 10px', fontSize: 11 }}
                onClick={() => setPeriod(p.value)}
              >
                {p.label}
              </button>
            ))}
            <input
              className="inp"
              placeholder={_rT("Filter team…")}
              value={team}
              onChange={e => setTeam(e.target.value)}
              style={{ width: 120, padding:'3px 8px', fontSize: 11 }}
            />
          </div>
        }
      />

      {loading && <div className="muted" style={{ padding: 12, fontSize: 13 }}>{_rT("Loading…")}</div>}

      {!loading && data && (
        <>
          {/* Summary cards */}
          <div style={{ display:'flex', gap: 12, marginTop: 16, flexWrap:'wrap' }}>
            <div style={cardStyle}>
              <div style={{ fontSize: 26, fontWeight: 700, color:'var(--accent)' }}>{data.shifts_total}</div>
              <div style={{ fontSize: 11, color:'var(--text-2)', marginTop: 4 }}>{_rT("Total shifts")}</div>
            </div>
            <div style={cardStyle}>
              <div style={{ fontSize: 26, fontWeight: 700, color:'var(--accent)' }}>{data.hours_total}h</div>
              <div style={{ fontSize: 11, color:'var(--text-2)', marginTop: 4 }}>{_rT("Total hours on call")}</div>
            </div>
            <div style={cardStyle}>
              <div style={{ fontSize: 26, fontWeight: 700, color:'var(--accent)' }}>{data.escalations}</div>
              <div style={{ fontSize: 11, color:'var(--text-2)', marginTop: 4 }}>{_rT("Escalations")}</div>
            </div>
          </div>

          {/* Ranked lists */}
          <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(260px,1fr))', gap: 24, marginTop: 24 }}>
            {/* Top users by hours */}
            <div>
              <div style={{ fontSize: 12, fontWeight: 600, color:'var(--text-2)', marginBottom: 10 }}>
                {_rT("Top users by hours on call")}
              </div>
              {(data.per_user ?? []).length === 0
                ? <div className="muted" style={{ fontSize: 12 }}>{_rT("No data for this period.")}</div>
                : (data.per_user ?? []).slice(0, 10).map((u, i) => (
                    <div key={u.user_id} style={{ display:'flex', alignItems:'center', gap: 8, padding:'6px 0', borderBottom:'1px solid var(--line)' }}>
                      <span style={{ fontSize: 11, color:'var(--text-3)', width: 18, textAlign:'right' }}>#{i+1}</span>
                      <span style={{ flex: 1, fontSize: 13, fontWeight: 500 }}>{u.display_name}</span>
                      <span style={{ fontSize: 12, color:'var(--text-2)' }}>{u.hours}h</span>
                      <span className="chip" style={{ fontSize: 10 }}>{_rAr() ? `${u.shifts} مناوبة` : `${u.shifts} shift${u.shifts !== 1 ? 's' : ''}`}</span>
                    </div>
                  ))
              }
            </div>

            {/* Top teams by shifts */}
            <div>
              <div style={{ fontSize: 12, fontWeight: 600, color:'var(--text-2)', marginBottom: 10 }}>
                {_rT("Top teams by shifts")}
              </div>
              {(data.per_team ?? []).length === 0
                ? <div className="muted" style={{ fontSize: 12 }}>{_rT("No data for this period.")}</div>
                : (data.per_team ?? []).slice(0, 10).map((t, i) => (
                    <div key={t.team_name} style={{ display:'flex', alignItems:'center', gap: 8, padding:'6px 0', borderBottom:'1px solid var(--line)' }}>
                      <span style={{ fontSize: 11, color:'var(--text-3)', width: 18, textAlign:'right' }}>#{i+1}</span>
                      <span style={{ flex: 1, fontSize: 13, fontWeight: 500 }}>{t.team_name}</span>
                      <span style={{ fontSize: 12, color:'var(--text-2)' }}>{t.hours}h</span>
                      <span className="chip" style={{ fontSize: 10 }}>{_rAr() ? `${t.shifts} مناوبة` : `${t.shifts} shift${t.shifts !== 1 ? 's' : ''}`}</span>
                    </div>
                  ))
              }
            </div>
          </div>
        </>
      )}

      {!loading && !data && (
        <div className="muted" style={{ padding: 12, fontSize: 13 }}>{_rT("No on-call data available.")}</div>
      )}
    </div>
  );
}
// Re-exposed so the On-call page bundle can mount the same standings block.
window.OnCallStandingsSection = OnCallStandingsSection;

/* ── Charts section — period picker + 2-col grid ── */

/* ── Violations section (#25) — period filter + table + pie + trend ── */
function ViolationsSection() {
  const [period, setPeriod]   = React.useState('week');
  const [search, setSearch]   = React.useState('');
  const [rows, setRows]       = React.useState([]);
  const [breakdown, setBreakdown] = React.useState({ labels: [], data: [], total: 0 });
  const [timeline, setTimeline]   = React.useState({ labels: [], data: [], total: 0 });
  const [loading, setLoading]     = React.useState(false);
  const toast = useToast();
  const trendRef = React.useRef(null);
  const pieRef   = React.useRef(null);

  const PERIODS = [
    { value: 'day',     label: _rT('Day') },
    { value: 'week',    label: _rT('Week') },
    { value: 'month',   label: _rT('Month') },
    { value: 'quarter', label: _rT('Quarter') },
    { value: 'year',    label: _rT('Year') },
  ];
  const PIE_COLORS = ['#ef4444', '#f59e0b', '#3b82f6', '#a855f7', '#10b981', '#ec4899', '#14b8a6'];

  const load = async (p) => {
    setLoading(true);
    try {
      // Scope all 3 fetches to the same search so donut/trend/table never drift.
      const searchQ = search ? '&search=' + encodeURIComponent(search) : '';
      const [r1, r2, r3] = await Promise.all([
        fetch('/api/summary/violations?period=' + encodeURIComponent(p) + searchQ,
              { credentials: 'same-origin' }).then(r => r.ok ? r.json() : []),
        fetch('/api/violations/breakdown?period=' + encodeURIComponent(p) + searchQ,
              { credentials: 'same-origin' }).then(r => r.ok ? r.json() : { labels: [], data: [], total: 0 }),
        fetch('/api/violations/timeline?period=' + encodeURIComponent(p === 'day' ? 'week' : p) + searchQ,
              { credentials: 'same-origin' }).then(r => r.ok ? r.json() : { labels: [], data: [], total: 0 }),
      ]);
      setRows(Array.isArray(r1) ? r1 : []);
      setBreakdown(r2);
      setTimeline(r3);
    } catch(e) {
      toast.push({ msg: (_rAr() ? 'فشل جلب المخالفات: ' : 'Violations fetch failed: ') + e.message, kind: 'err' });
    } finally {
      setLoading(false);
    }
  };

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

  // Chart.js pie + line
  React.useEffect(() => {
    if (!window.Chart || !pieRef.current || !breakdown.labels.length) return;
    const ctx = pieRef.current.getContext('2d');
    if (pieRef.current._chart) pieRef.current._chart.destroy();
    pieRef.current._chart = new window.Chart(ctx, {
      type: 'doughnut',
      data: {
        labels: breakdown.labels,
        datasets: [{
          data: breakdown.data,
          backgroundColor: breakdown.labels.map((_, i) => PIE_COLORS[i % PIE_COLORS.length]),
          borderWidth: 2,
          borderColor: 'var(--bg-elev-2)',
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { position: 'right', labels: { color: 'var(--text-1)', boxWidth: 12, font:{size:11} } },
          tooltip: {},
        },
      },
    });
    return () => { if (pieRef.current && pieRef.current._chart) pieRef.current._chart.destroy(); };
  }, [breakdown]);

  React.useEffect(() => {
    if (!window.Chart || !trendRef.current || !timeline.labels.length) return;
    const ctx = trendRef.current.getContext('2d');
    if (trendRef.current._chart) trendRef.current._chart.destroy();
    trendRef.current._chart = new window.Chart(ctx, {
      type: 'line',
      data: {
        labels: timeline.labels.map(d => d.slice(5)),
        datasets: [{
          label: _rT('Violations'),
          data: timeline.data,
          borderColor: '#ef4444',
          backgroundColor: 'rgba(239,68,68,0.18)',
          fill: true,
          tension: 0.3,
          pointRadius: 2,
        }],
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: {
          y: { beginAtZero: true, ticks: { color: 'var(--text-2)', stepSize: 1 } },
          x: { ticks: { color: 'var(--text-2)', maxTicksLimit: 8 } },
        },
      },
    });
    return () => { if (trendRef.current && trendRef.current._chart) trendRef.current._chart.destroy(); };
  }, [timeline]);

  const totalViolations = rows.reduce((s, r) => s + (r.violation_count || 0), 0);

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("⚠️ Violations")}
          tip={_rT("Unified violations card (#1, #28). Donut + grid + trend + table read from the same counts+events arrays — so the donut and the count next to it never disagree.")}
        sub={_rAr() ? `${totalViolations} مخالفة هذا الـ${period} · النقاط المتبقية من ${rows[0]?.strike_cap || 3} لكل مستخدم` : `${totalViolations} violation${totalViolations !== 1 ? 's' : ''} this ${period} · strikes left out of ${rows[0]?.strike_cap || 3} per user`}
        right={
          <select className="sel" value={period} onChange={e => setPeriod(e.target.value)}
            style={{ fontSize: 12, padding: '4px 8px' }}>
            {PERIODS.map(p => (<option key={p.value} value={p.value}>{p.label}</option>))}
          </select>
        }
      />

      {/* Charts row */}
      <div className="violations-charts" style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap: 12, padding:'8px 16px 16px' }}>
        <div style={{ background:'var(--surface-2)', borderRadius: 8, padding: 12 }}>
          <div style={{ fontSize: 12, color:'var(--text-2)', marginBottom: 6 }}>{_rT("By type")}</div>
          <div style={{ height: 180, position:'relative' }}>
            {breakdown.labels.length === 0 && !loading && (
              <div className="muted" style={{ position:'absolute', inset:0, display:'flex', alignItems:'center', justifyContent:'center', fontSize:13 }}>{_rT("No violations in this window 🎉")}</div>
            )}
            <canvas ref={pieRef} style={{ width:'100%', height:'100%' }} />
          </div>
        </div>
        <div style={{ background:'var(--surface-2)', borderRadius: 8, padding: 12 }}>
          <div style={{ fontSize: 12, color:'var(--text-2)', marginBottom: 6 }}>{_rT("Trend")}</div>
          <div style={{ height: 180, position:'relative' }}>
            {timeline.labels.length === 0 && !loading && (
              <div className="muted" style={{ position:'absolute', inset:0, display:'flex', alignItems:'center', justifyContent:'center', fontSize:13 }}>—</div>
            )}
            <canvas ref={trendRef} style={{ width:'100%', height:'100%' }} />
          </div>
        </div>
      </div>

      {/* Search + table — search scopes pie + trend + table together */}
      <div style={{ padding:'0 16px 12px', display:'flex', alignItems:'center', gap:8, marginBottom: 8, flexWrap:'wrap' }}>
        <input
          className="inp"
          placeholder={_rT("Search by name…")}
          value={search}
          onChange={e => setSearch(e.target.value)}
          style={{ maxWidth: 280 }}
        />
        {search && (
          <button className="btn btn-ghost"
            style={{ padding:'4px 10px', fontSize: 11 }}
            onClick={() => setSearch('')}
            title={_rT("Reset to all users")}>
            {_rT("All users")}
          </button>
        )}
        <span className="muted" style={{ fontSize: 11 }}>
          {search ? (_rAr() ? `عرض الحلقة + الاتجاه + الجدول لـ "${search}"` : `Showing donut + trend + table for "${search}"`) : (_rAr() ? `عرض كل المستخدمين · ${rows.length}` : `Showing all users · ${rows.length}`)}
        </span>
      </div>
      <div style={{ padding:'0 16px 12px' }}>
        <div style={{ overflowX: 'auto' }}>
          <table className="t" style={{ width:'100%', fontSize: 12.5 }}>
            <thead>
              <tr>
                <th>{_rT("User")}</th>
                <th>{_rT("Team")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Violations in the selected period")}>{_rT("Period total")}</th>
                <th>{_rT("By type")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Days late in the selected period")}>{_rT("Late")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Days absent in the selected period")}>{_rT("Absent")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Days worked below the expected hours")}>{_rT("Short")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Attendance % over the selected period")}>{_rT("Att %")}</th>
                <th style={{ textAlign:'right' }} title={_rT("Lifetime strikes left out of strike cap (default 3)")}>{_rT("Strikes left (lifetime)")}</th>
                <th>{_rT("Last")}</th>
              </tr>
            </thead>
            <tbody>
              {loading && <tr><td colSpan="10" className="muted" style={{padding:12}}>{_rT("Loading…")}</td></tr>}
              {!loading && rows.length === 0 && (
                <tr><td colSpan="10" className="muted" style={{padding:12}}>{_rT("No data.")}</td></tr>
              )}
              {rows.map(r => {
                const left = Math.max(0, r.strikes_left || 0);
                const cap  = r.strike_cap || 3;
                const leftColor = left === 0 ? 'var(--err)' : left === 1 ? 'var(--warn)' : 'var(--ok)';
                return (
                  <tr key={r.user_id}>
                    <td>{r.display_name}</td>
                    <td className="muted">{r.team || '—'}</td>
                    <td className="num mono" style={{ textAlign:'right', fontWeight:600 }}>{r.violation_count}</td>
                    <td>
                      {Object.entries(r.by_type || {}).length === 0 ? (
                        <span className="muted">—</span>
                      ) : Object.entries(r.by_type || {}).map(([k, v], i) => (
                        <span key={k} style={{
                          display:'inline-block', padding:'1px 7px', borderRadius:999,
                          background: PIE_COLORS[i % PIE_COLORS.length], color:'#fff',
                          fontSize: 10.5, marginRight:4, marginTop:2,
                        }}>{k.replace('_',' ')}: {v}</span>
                      ))}
                    </td>
                    <td className="num mono" style={{ textAlign:'right', color: (r.days_late||0) ? 'var(--warn)' : 'var(--text-2)' }}>{r.days_late || 0}</td>
                    <td className="num mono" style={{ textAlign:'right', color: (r.days_absent||0) ? 'var(--err)' : 'var(--text-2)' }}>{r.days_absent || 0}</td>
                    <td className="num mono" style={{ textAlign:'right', color:'var(--text-2)' }}>{r.short_days || 0}</td>
                    <td className="num mono" style={{ textAlign:'right', fontWeight:600,
                      color: (r.attendance_pct||0) < 60 ? 'var(--err)' : (r.attendance_pct||0) < 80 ? 'var(--warn)' : 'var(--text-1)' }}>
                      {r.attendance_pct != null ? Math.round(r.attendance_pct) + '%' : '—'}
                    </td>
                    <td className="num mono" style={{ textAlign:'right' }}>
                      <span style={{ color: leftColor, fontWeight:700 }}>{left}</span>
                      <span className="muted" style={{ fontSize:10.5 }}> / {cap}</span>
                    </td>
                    <td className="muted mono" style={{ fontSize: 11 }}>
                      {r.last_violation ? r.last_violation.slice(0, 16).replace('T', ' ') : '—'}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}


function ChartsSection() {
  const [period, setPeriod] = React.useState('week');
  const selected = CHART_PERIODS.find(p => p.value === period) || CHART_PERIODS[1];

  return (
    <div className="card" style={{ marginTop: 16 }}>
      <SectionHeader
        title={_rT("Charts")}
          tip={_rT("Hours-per-day, attendance %, top contributors. Auto-refresh on filter change. PDF export via the Generate Report card above.")}
        sub={_rT("Attendance breakdown, hours trend, and status distribution")}
        right={
          <div style={{ display:'flex', gap: 6, alignItems:'center' }}>
            {CHART_PERIODS.map(p => (
              <button
                key={p.value}
                className={period === p.value ? 'btn btn-pri' : 'btn btn-ghost'}
                style={{ padding:'3px 10px', fontSize: 11 }}
                onClick={() => setPeriod(p.value)}
              >
                {_rT(p.label)}
              </button>
            ))}
          </div>
        }
      />

      {/* Top row: stacked bar + line chart */}
      <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(300px, 1fr))', gap: 24, marginTop: 20 }}>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, color:'var(--text-2)', marginBottom: 10 }}>{_rT("Daily attendance breakdown")}</div>
          <AttendanceStackedBar range={selected.range} />
        </div>
        <div>
          <div style={{ fontSize: 12, fontWeight: 600, color:'var(--text-2)', marginBottom: 10 }}>{_rT("Total hours per day")}</div>
          <HoursTrendLine range={selected.range} />
        </div>
      </div>

      {/* Bottom row: donut spans both */}
      <div style={{ marginTop: 28, borderTop:'1px solid var(--line)', paddingTop: 20 }}>
        <div style={{ fontSize: 12, fontWeight: 600, color:'var(--text-2)', marginBottom: 14 }}>{_rT("Status distribution")} — {_rT(selected.label)}</div>
        <StatusDonut range={selected.range} periodLabel={_rT(selected.label)} />
      </div>
    </div>
  );
}

window.ReportsPage = ReportsPage;
