// tab-overview.jsx — triage banner + KPIs + today snapshot + leaderboard + actions.
// Ported from the design's v3-tabs-other.jsx :TabOverview.

function fmtK(n) {
  if (n == null || isNaN(n)) return '—';
  if (n >= 1_000_000) return (n / 1_000_000).toFixed(2).replace(/\.?0+$/, '') + 'M';
  if (n >= 1_000) return (n / 1_000).toFixed(1).replace(/\.0$/, '') + 'k';
  return String(Math.round(n));
}

function TriageTier({ sev, count, label, desc, onClick, passive }) {
  const meta = window.YDLoader.SEV_META[sev];
  return (
    <button
      className={'triage-tier' + (passive ? ' passive' : '')}
      onClick={!passive ? onClick : undefined}
      style={{ '--sev-color': meta.color, '--sev-bg': meta.bg, '--sev-border': meta.border }}>
      <div className="triage-tier-hd">
        <SevDot sev={sev} size={8}/>
        <span className="lbl">{label}</span>
      </div>
      <div className="triage-tier-num">{count}</div>
      <div className="triage-tier-desc">{desc}</div>
    </button>
  );
}

function TodayStatusGrid({ onPickBucket }) {
  const buckets = window.YD.TODAY_BUCKETS;
  const items = [
    { key: 'completed',     label: 'Done',           count: buckets.completed.length,     color: '#15803d', bg: '#f0fdf4' },
    { key: 'working',       label: 'Working',        count: buckets.working.length,       color: '#1d4ed8', bg: '#eff6ff' },
    { key: 'incomplete',    label: 'Incomplete',     count: buckets.incomplete.length,    color: '#b45309', bg: '#fffbeb' },
    { key: 'lateNoClock',   label: 'Not clocked in', count: buckets.lateNoClock.length,   color: '#b91c1c', bg: '#fef2f2' },
    { key: 'notYetStarted', label: 'Not yet started',count: buckets.notYetStarted.length, color: '#6b7280', bg: '#f9fafb' },
    { key: 'onLeave',       label: 'On leave',       count: buckets.onLeave.length,       color: '#1d4ed8', bg: '#eff6ff' },
  ];
  return (
    <div className="today-grid">
      {items.map(it => {
        const clickable = it.count > 0 && typeof onPickBucket === 'function';
        return (
          <button
            type="button"
            key={it.key}
            disabled={!clickable}
            onClick={clickable ? () => onPickBucket(it) : undefined}
            className="today-tile"
            style={{
              background: it.bg, borderColor: it.bg,
              border: 'none', textAlign: 'left',
              cursor: clickable ? 'pointer' : 'default',
              opacity: it.count === 0 ? 0.7 : 1,
              transition: 'transform 0.08s ease',
            }}
            onMouseDown={clickable ? (e) => e.currentTarget.style.transform = 'translateY(1px)' : undefined}
            onMouseUp={clickable ? (e) => e.currentTarget.style.transform = '' : undefined}
            onMouseLeave={clickable ? (e) => e.currentTarget.style.transform = '' : undefined}>
            <div className="today-tile-num" style={{ color: it.color }}>{it.count}</div>
            <div className="today-tile-lbl">{it.label}</div>
          </button>
        );
      })}
    </div>
  );
}

const BUCKET_DESCRIPTIONS = {
  completed:     'Finished today’s shift',
  working:       'Currently clocked in',
  incomplete:    'Clocked in but missed targets',
  lateNoClock:   'Late and not yet clocked in',
  notYetStarted: 'Shift hasn’t started yet',
  onLeave:       'Approved leave',
};

// Lists every person in a `Today · shift status` bucket with what they've
// produced today (resources, hours, pace). Clicking a row drops into the
// existing PersonModal for the full drilldown. Used only on Overview;
// other pages have their own member tables.
function TodayBucketModal({ bucket, onClose, onPickPerson }) {
  const idx = window.YD.TODAY_IDX;
  const members = (window.YD.TODAY_BUCKETS[bucket.key] || []).slice().map((m) => {
    const k = (m.dailyKpi || [])[idx] || { resources: 0, hours: 0 };
    const pace = k.hours > 0 ? Math.round((k.resources / k.hours) * 10) / 10 : 0;
    return { m, resources: k.resources || 0, hours: k.hours || 0, pace };
  }).sort((a, b) => b.resources - a.resources);

  const totalRes = members.reduce((s, r) => s + r.resources, 0);
  const totalHrs = members.reduce((s, r) => s + r.hours, 0);

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div
        className="modal-card modal-card-xwide"
        onClick={(e) => e.stopPropagation()}
        style={{ maxHeight: 'calc(100vh - 40px)', display: 'flex', flexDirection: 'column' }}>
        <div className="modal-hd" style={{ flex: '0 0 auto' }}>
          <div style={{ minWidth: 0, flex: 1 }}>
            <h3 style={{ margin: 0, fontSize: 16 }}>
              {bucket.label} · {members.length}
            </h3>
            <div className="meta" style={{ marginTop: 2 }}>
              {BUCKET_DESCRIPTIONS[bucket.key] || ''}
              {totalRes > 0 && ` · ${fmtK(totalRes)} resources today across ${totalHrs.toFixed(1)}h`}
            </div>
          </div>
          <button className="modal-x" onClick={onClose} aria-label="Close">×</button>
        </div>
        <div className="modal-bd" style={{ padding: 0, overflowY: 'auto', flex: '1 1 auto', minHeight: 0 }}>
          {members.length === 0 ? (
            <div style={{ padding: 24, textAlign: 'center', color: '#9ca3af', fontSize: 13 }}>Nobody here.</div>
          ) : (
            <table className="pl-table" style={{ width: '100%' }}>
              <thead style={{ position: 'sticky', top: 0, background: '#fff', zIndex: 1 }}>
                <tr>
                  <th>Person</th>
                  <th className="num">Resources</th>
                  <th className="num">Hours</th>
                  <th className="num">Pace</th>
                </tr>
              </thead>
              <tbody>
                {members.map(({ m, resources, hours, pace }) => (
                  <tr
                    key={m.email}
                    onClick={() => onPickPerson(m.email)}
                    style={{ cursor: 'pointer' }}>
                    <td>
                      <div className="flex ac g8">
                        <Avatar name={m.name} size={26}/>
                        <div style={{ minWidth: 0 }}>
                          <div style={{ fontSize: 13, fontWeight: 600 }}>{m.name}</div>
                          <div className="meta">{m.email}</div>
                        </div>
                      </div>
                    </td>
                    <td className="num mono">{resources > 0 ? fmtK(resources) : '—'}</td>
                    <td className="num mono">{hours > 0 ? hours.toFixed(1) + 'h' : '—'}</td>
                    <td className="num mono">{pace > 0 ? pace : '—'}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
        <div className="modal-actions" style={{ flex: '0 0 auto' }}>
          <button className="btn btn-dark" onClick={onClose}>Close</button>
        </div>
      </div>
    </div>
  );
}

// One-decimal rounding wrapper; floating-point subtraction sometimes
// produces values like 10.900000000000006 from 138.6 - 127.7. Apply
// before display.
function round1(n) { return Math.round((n || 0) * 10) / 10; }

function PaceSparkline({ trend, loading }) {
  // Fall back to the single-point placeholder until getTeamPaceTrend resolves.
  // While loading we show the placeholder line so the card isn't blank.
  const pts = (trend && trend.length) ? trend : (window.YD.PACE_TREND || []);
  if (!pts.length) return <div className="meta">No trend data yet.</div>;
  const expected = window.YD.TEAM.expectedPace || 120;
  const rawMax = Math.max(expected + 10, ...pts.map(p => p.pace));
  const rawMin = Math.min(expected - 10, ...pts.map(p => p.pace));
  // Pad axis to nearest 10 so the labels read cleanly (130, 140, ...).
  const max = Math.ceil(rawMax / 10) * 10;
  const min = Math.max(0, Math.floor(rawMin / 10) * 10);
  const w = 300, h = 100;
  const padL = 28; // room for Y-axis labels
  const innerW = w - padL;
  const x = i => padL + (i / Math.max(1, pts.length - 1)) * innerW;
  const y = v => h - ((v - min) / Math.max(1, max - min)) * h;
  const d = pts.map((p, i) => `${i === 0 ? 'M' : 'L'} ${x(i).toFixed(1)} ${y(p.pace).toFixed(1)}`).join(' ');
  const expY = y(expected);
  const current = pts[pts.length - 1];
  const prev = pts.length > 1 ? pts[pts.length - 2] : current;
  const delta = round1(current.pace - prev.pace);
  // Three Y-axis ticks: top, expected line, bottom.
  const ticks = [max, expected, min].filter((v, i, a) => a.indexOf(v) === i).sort((a, b) => b - a);
  return (
    <div>
      <div className="flex ac jb" style={{ marginBottom: 10 }}>
        <div>
          <div className="mono" style={{ fontSize: 28, fontWeight: 700 }}>
            {round1(current.pace)}<span style={{ fontSize: 13, color: '#6b7280', marginLeft: 4 }}>/hr</span>
          </div>
          <div className="meta" style={{ color: delta >= 0 ? '#15803d' : '#b91c1c' }}>
            {delta === 0 ? '—' : delta > 0 ? '▲' : '▼'} {Math.abs(delta).toFixed(1)} vs last week
          </div>
        </div>
        <div className="meta" style={{ textAlign: 'right' }}>Expected <b style={{ color: '#111' }}>{expected}</b></div>
      </div>
      <svg viewBox={`0 0 ${w} ${h + 4}`} width="100%" height={h + 4} style={{ display: 'block' }}>
        {/* Y-axis tick labels + grid lines */}
        {ticks.map((tick) => {
          const ty = y(tick);
          const isExp = tick === expected;
          return (
            <g key={tick}>
              <line
                x1={padL} y1={ty} x2={w} y2={ty}
                stroke={isExp ? '#d1d5db' : '#f3f4f6'}
                strokeWidth="1"
                strokeDasharray={isExp ? '3 3' : 'none'}/>
              <text
                x={padL - 4} y={ty + 3}
                textAnchor="end"
                fontSize="9"
                fontFamily="Inconsolata, monospace"
                fill={isExp ? '#6b7280' : '#9ca3af'}>
                {tick}
              </text>
            </g>
          );
        })}
        <path d={d + ` L ${x(pts.length - 1)} ${h} L ${padL} ${h} Z`} fill="rgba(17,17,17,0.05)"/>
        <path d={d} fill="none" stroke="#111" strokeWidth="2"/>
        {pts.map((p, i) => (
          <circle key={i} cx={x(i)} cy={y(p.pace)} r={i === pts.length - 1 ? 4 : 3}
            fill={i === pts.length - 1 ? '#111' : '#fff'} stroke="#111" strokeWidth="1.5"/>
        ))}
      </svg>
      <div className="flex jb" style={{ fontSize: 10, color: '#6b7280', marginTop: 4, paddingLeft: padL }}>
        {pts.map(p => <span key={p.week}>{p.week}</span>)}
      </div>
    </div>
  );
}

function TopPerformersMini() {
  const top = (window.YD.LEADERBOARD || []).slice(0, 5);
  if (!top.length) return <div className="meta">No data yet.</div>;
  return (
    <div className="col g8">
      {top.map(r => (
        <div key={r.email} className="lbx-row">
          <div className="lbx-rank">#{r.rank}</div>
          <Avatar name={r.name} size={28}/>
          <div className="lbx-name">{r.name}</div>
          <div className="lbx-pace mono">{r.pace || 0}<span style={{ fontSize: 10, color: '#6b7280' }}>/hr</span></div>
          <div className="lbx-res mono">{fmtK(r.resources)}</div>
        </div>
      ))}
    </div>
  );
}

function RecentActionsMini() {
  const all = window.YD.ACTION_LOG || [];
  const log = all.slice(0, 5);
  const monitoredOpen = all.filter(a => a.status === 'open' && a.isMonitored);
  return (
    <div className="col g10">
      {monitoredOpen.length > 0 && (
        <div className="flex jb ac" style={{
          padding: '8px 10px', borderRadius: 8,
          background: '#fffbeb', border: '1px solid #fde68a',
        }}>
          <div style={{ fontSize: 12, color: '#92400e' }}>
            <b style={{ fontFamily: 'Inconsolata, monospace', fontSize: 16, marginRight: 6 }}>{monitoredOpen.length}</b>
            on formal monitoring
          </div>
          <span className="meta">PIP · Verbal · Performance Notice</span>
        </div>
      )}
      {!log.length ? (
        <div className="meta">No actions logged yet.</div>
      ) : log.map((a, i) => (
        <div key={i} className="al-row">
          <div className="al-when">{(a.when || '').slice(11, 16) || '—'}</div>
          <div className="al-action">
            <b>{a.action}</b>
            <span className="subject"> · {a.subject}</span>
          </div>
          <div className="al-by">{a.who}</div>
        </div>
      ))}
    </div>
  );
}

function TabOverview({ setTab, goToRoster, weekOffset, setWeekOffset }) {
  const td = window.YD.TEAM;
  const bySev = window.YD.BY_SEVERITY;
  const buckets = window.YD.TODAY_BUCKETS;
  const clocked = buckets.completed.length + buckets.working.length + buckets.incomplete.length;
  const total = td.memberCount;
  const todayDate = new Date();
  const [bucket, setBucket] = React.useState(null);
  const [viewEmail, setViewEmail] = React.useState(null);
  const [trend, setTrend] = React.useState(null);
  const [trendLoading, setTrendLoading] = React.useState(true);

  // Lazy-load the 5-week pace trend after the page mounts so first paint
  // isn't blocked by the extra round trips. Falls back to the single-point
  // placeholder if it errors (rare — usually means the team has no historical
  // KPI ingested yet).
  //
  // Result is cached in localStorage with a 6h TTL because the trend is
  // historical (5 closed weeks + this week) — it barely changes during a
  // workday. Saves ~7K Firestore reads per Overview load on a hot cache.
  React.useEffect(() => {
    const team = td.teamName || '';
    if (!team) return;
    const cacheKey = `yd-pace-trend:${team}`;
    const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
    try {
      const raw = window.localStorage.getItem(cacheKey);
      if (raw) {
        const parsed = JSON.parse(raw);
        if (parsed && parsed.fetchedAt && (Date.now() - parsed.fetchedAt) < TTL_MS) {
          setTrend(parsed.trend);
          setTrendLoading(false);
          return; // cache hit — skip the network round trip entirely
        }
      }
    } catch { /* malformed cache, fall through to fetch */ }
    setTrendLoading(true);
    window.YDApp.call('getTeamPaceTrend', { team })
      .then((resp) => {
        const weeks = (resp && resp.weeks) || [];
        const next = weeks.map((w) => ({ week: w.week, pace: w.pace }));
        setTrend(next);
        try {
          window.localStorage.setItem(cacheKey, JSON.stringify({ fetchedAt: Date.now(), trend: next }));
        } catch { /* storage full or disabled — non-fatal */ }
      })
      .catch((e) => { console.warn('getTeamPaceTrend failed', e); })
      .finally(() => setTrendLoading(false));
  }, [td.teamName]);

  return (
    <div className="page">
      <PageHeader
        eyebrow={`Team lead · ${todayDate.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' })} · ${todayDate.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })}`}
        title={`${td.teamName} · Overview`}
        subtitle={`Lead ${td.leadName || '—'} · ${total} annotators`}
        actions={
          <div className="flex g8 ac">
            <div className="segbar">
              <button
                className={weekOffset === 0 ? 'active' : ''}
                onClick={() => setWeekOffset && setWeekOffset(0)}>
                This week
              </button>
              <button
                className={weekOffset === -1 ? 'active' : ''}
                onClick={() => setWeekOffset && setWeekOffset(-1)}>
                Last week
              </button>
            </div>
          </div>
        }/>

      <div className="triage-banner">
        <div className="triage-hd">
          <div className="triage-hd-lbl">
            <div className="eyebrow">Needs attention now</div>
            <h2 className="triage-hd-title">
              <span className="n" style={{ color: bySev.critical.length + bySev.high.length > 0 ? '#b91c1c' : '#15803d' }}>
                {bySev.critical.length + bySev.high.length}
              </span>
              <span className="t">people need a response today</span>
            </h2>
          </div>
          <button className="btn btn-dark" onClick={() => setTab('clockin')}>
            Open clock-in triage →
          </button>
        </div>
        <div className="triage-tiers">
          <TriageTier sev="critical" count={bySev.critical.length} label="Critical" desc="Call now · escalate if unreachable" onClick={() => setTab('clockin')}/>
          <TriageTier sev="high"     count={bySev.high.length}     label="High"     desc="Message in next 30 min"            onClick={() => goToRoster && goToRoster('high')}/>
          <TriageTier sev="watch"    count={bySev.watch.length}    label="Watch"    desc="Note, check end of day"            onClick={() => goToRoster && goToRoster('watch')}/>
          <TriageTier sev="ok"       count={bySev.ok.length}       label="On track" desc="Maintain"                           onClick={() => goToRoster && goToRoster('ok')}/>
          <TriageTier sev="leave"    count={bySev.leave.length}    label="On leave" desc="Approved"                           passive/>
        </div>
      </div>

      <div className="kpi-row">
        <div className="kpi-tile">
          <div className="lbl">Week resources</div>
          <div className="val">{fmtK(td.totalResources)}</div>
          <div className="sub">{total} annotators · WTD</div>
        </div>
        <div className="kpi-tile">
          <div className="lbl">Team pace /hr</div>
          <div className="val">{td.teamPace || 0}</div>
          <div className="sub">
            vs <b>{td.expectedPace || '—'}</b> expected
            {td.expectedPace > 0 && (
              <span style={{ color: td.teamPace >= td.expectedPace ? '#15803d' : '#b45309', marginLeft: 4 }}>
                · {td.teamPace >= td.expectedPace ? 'on track' : `${Math.round((1 - td.teamPace / td.expectedPace) * 100)}% below`}
              </span>
            )}
          </div>
        </div>
        <div className="kpi-tile">
          <div className="lbl">Clocked in</div>
          <div className="val">{clocked}<span className="denom"> / {total}</span></div>
          <div className="sub">{total > 0 ? Math.round(clocked / total * 100) : 0}% of team</div>
        </div>
        <div className="kpi-tile">
          <div className="lbl">Needs attention</div>
          <div className="val" style={{ color: bySev.critical.length + bySev.high.length > 0 ? '#b91c1c' : '#15803d' }}>
            {bySev.critical.length + bySev.high.length}
          </div>
          <div className="sub">{bySev.critical.length} critical · {bySev.high.length} high</div>
        </div>
      </div>

      <div className="row g16">
        <div className="card f1">
          <div className="card-hd card-hd-bottomline">
            <h2>Today · shift status</h2>
            <button className="btn btn-sm btn-ghost" onClick={() => setTab('clockin')}>View all →</button>
          </div>
          <div className="card-bd">
            <TodayStatusGrid onPickBucket={setBucket}/>
          </div>
        </div>
        <div className="card" style={{ width: 340 }}>
          <div className="card-hd card-hd-bottomline">
            <h2>Team pace trend</h2>
            <span className="meta">{trendLoading ? 'Loading…' : '5 weeks'}</span>
          </div>
          <div className="card-bd">
            <PaceSparkline trend={trend} loading={trendLoading}/>
          </div>
        </div>
      </div>

      <div className="row g16">
        <div className="card f1">
          <div className="card-hd card-hd-bottomline">
            <h2>Top performers · week</h2>
            <button className="btn btn-sm btn-ghost" onClick={() => setTab('performance')}>Full leaderboard →</button>
          </div>
          <div className="card-bd"><TopPerformersMini/></div>
        </div>
        <div className="card f1">
          <div className="card-hd card-hd-bottomline">
            <h2>Recent actions</h2>
            <button className="btn btn-sm btn-ghost" onClick={() => setTab('actionlog')}>Full log →</button>
          </div>
          <div className="card-bd"><RecentActionsMini/></div>
        </div>
      </div>

      {bucket && (
        <TodayBucketModal
          bucket={bucket}
          onClose={() => setBucket(null)}
          onPickPerson={(email) => { setBucket(null); setViewEmail(email); }}/>
      )}
      {viewEmail && (
        <PersonModal email={viewEmail} onClose={() => setViewEmail(null)}/>
      )}
    </div>
  );
}

Object.assign(window, { TabOverview, fmtK });
