// tab-clockin.jsx — Clock-in triage. Groups people by why they're not in
// (severity-ordered) with bulk actions. Ported from design v3-tab-clockin.jsx.

const { useState: cUseState, useMemo: cUseMemo } = React;

function fmtMinsLate(mins) {
  if (mins == null || mins <= 0) return '';
  if (mins < 60) return `${mins}m late`;
  const h = Math.floor(mins / 60);
  const m = mins % 60;
  return m ? `${h}h ${m}m late` : `${h}h late`;
}
function fmtTime(t) { return t || '—'; }

function ClockinSummaryStrip({ counts, selected, onSelect }) {
  const groups = [
    { key: 'late_critical',     label: 'Critical',         sev: 'critical', desc: '>2h late, unresponsive' },
    { key: 'late_recent',       label: 'Late',             sev: 'high',     desc: 'Late <2h, recoverable' },
    { key: 'shift_not_started', label: 'Not yet started',  sev: 'ok',       desc: 'Afternoon shifts' },
    { key: 'on_leave',          label: 'On leave',         sev: 'leave',    desc: 'Approved absence' },
    { key: 'day_off',           label: 'Day off',          sev: 'ok',       desc: 'Scheduled' },
  ];
  const clocked = (counts.clocked_done || 0) + (counts.clocked_working || 0) + (counts.clocked_incomplete || 0);
  const notClocked = (counts.late_critical || 0) + (counts.late_recent || 0);
  const notDue = counts.shift_not_started || 0;
  const absent = (counts.on_leave || 0) + (counts.day_off || 0);
  const expected = clocked + notClocked;
  const pctExpectedIn = expected > 0 ? Math.round(clocked / expected * 100) : 100;

  return (
    <div className="clockin-strip">
      <div className="clockin-strip-hero">
        <div className="clockin-strip-hero-num" style={{ color: notClocked > 50 ? '#b91c1c' : notClocked > 10 ? '#b45309' : '#15803d' }}>
          {notClocked}
        </div>
        <div className="clockin-strip-hero-lbl">
          <div className="t">Not clocked in · need an action</div>
          <div className="s">of {expected} expected on shift · {clocked} clocked in · {absent} absent · {notDue} not yet due</div>
        </div>
        <div className="clockin-strip-progress">
          <div className="clockin-strip-progress-track">
            <div className="clockin-strip-progress-fill" style={{ width: `${pctExpectedIn}%` }}/>
          </div>
          <div className="clockin-strip-progress-lbl">
            <span style={{ color: pctExpectedIn >= 85 ? '#15803d' : '#b45309', fontWeight: 700 }}>{pctExpectedIn}%</span> of expected shift is in
          </div>
        </div>
      </div>

      <div className="clockin-strip-chips">
        {groups.map(g => (
          <button
            key={g.key}
            className={'clockin-strip-chip' + (selected === g.key ? ' active' : '')}
            onClick={() => onSelect(selected === g.key ? null : g.key)}
            style={{ borderColor: selected === g.key ? window.YDLoader.SEV_META[g.sev].color : '#e5e7eb' }}>
            <div className="row">
              <SevDot sev={g.sev}/>
              <span className="num">{counts[g.key] || 0}</span>
            </div>
            <div className="t">{g.label}</div>
            <div className="s">{g.desc}</div>
          </button>
        ))}
      </div>
    </div>
  );
}

function ClockinRowDetailed({ m, checked, onToggle, onLog }) {
  const sev = m.severity;
  return (
    <div className={'ci-row ci-row-detailed sev-' + sev}>
      <input type="checkbox" checked={checked} onChange={onToggle}/>
      <Avatar name={m.name} size={36}/>
      <div className="ci-row-main">
        <div className="nm">
          {m.name}
          {m.minutesLateClock > 0 && (
            <span className="chip chip-mini chip-danger" style={{ marginLeft: 8 }}>
              <SevDot sev={sev} size={5}/>
              {fmtMinsLate(m.minutesLateClock)}
            </span>
          )}
        </div>
        <div className="meta">
          Shift {fmtTime(m.todayShiftStart)} · {m.role} · Pace WTD {m.pace || '—'}/hr
          {m.missed >= 2 && <span style={{ color: '#b91c1c', marginLeft: 4 }}> · {m.missed} missed days this week</span>}
        </div>
      </div>
      <div className="ci-row-actions">
        <button className="btn btn-dark" onClick={() => onLog([m])}>+ Log action</button>
      </div>
    </div>
  );
}

function ClockinRowCompact({ m, checked, onToggle, onLog, sev = 'high' }) {
  return (
    <div className={'ci-row ci-row-compact sev-' + sev}>
      <input type="checkbox" checked={checked} onChange={onToggle}/>
      <Avatar name={m.name} size={26}/>
      <div className="nm">{m.name}</div>
      <div className="meta">{m.role}</div>
      <div className="shift">Shift {fmtTime(m.todayShiftStart)}</div>
      <div className="late">
        <SevDot sev={sev}/>
        <span>{fmtMinsLate(m.minutesLateClock)}</span>
      </div>
      <div className="pace">Pace {m.pace || 0}/hr</div>
      <div className="ci-row-actions">
        <button className="btn btn-sm btn-dark" onClick={() => onLog([m])}>+ Log action</button>
      </div>
    </div>
  );
}

function ClockinRowMinimal({ m, sev }) {
  const isOnLeave = sev === 'leave';
  return (
    <div className={'ci-row ci-row-minimal sev-' + sev}>
      <Avatar name={m.name} size={22}/>
      <div className="nm">{m.name}</div>
      <div className="meta">{m.role}</div>
      <div className="shift">
        {isOnLeave ? (m.leaveInfo?.records?.[0]?.reason || 'On leave')
          : (m.dailyShifts && m.dailyShifts[window.YD.TODAY_IDX]?.isDayOff) ? 'Day off'
          : `Shift ${fmtTime(m.todayShiftStart)}`}
      </div>
    </div>
  );
}

function ClockinGroup({ title, subtitle, items, sev, renderer, defaultOpen = true, onLog, selected, onToggle, bulkActions }) {
  const [open, setOpen] = cUseState(defaultOpen);
  const [pageSize, setPageSize] = cUseState(10);
  const visible = items.slice(0, pageSize);
  const allSelected = items.length > 0 && items.every(m => selected.has(m.email));
  const someSelected = items.some(m => selected.has(m.email)) && !allSelected;

  return (
    <div className={'ci-group sev-' + sev + (open ? '' : ' collapsed')}>
      <div className="ci-group-hd" onClick={() => setOpen(!open)}>
        <button className="ci-group-chev" aria-label="Toggle">
          <svg width="10" height="10" viewBox="0 0 10 10" style={{ transform: open ? 'rotate(90deg)' : 'none', transition: 'transform 0.15s' }}>
            <path d="M3 1l4 4-4 4" stroke="currentColor" fill="none" strokeWidth="1.5" strokeLinecap="round"/>
          </svg>
        </button>
        <SevDot sev={sev} size={10}/>
        <div className="ci-group-title">
          <span className="t">{title}</span>
          <span className="n">{items.length}</span>
        </div>
        <span className="ci-group-sub">{subtitle}</span>
        <div style={{ flex: 1 }}/>
        {open && bulkActions && items.length > 0 && (
          <div className="ci-group-bulk" onClick={(e) => e.stopPropagation()}>
            <label className="ci-select-all">
              <input
                type="checkbox"
                checked={allSelected}
                ref={el => el && (el.indeterminate = someSelected)}
                onChange={() => {
                  if (allSelected) items.forEach(m => selected.has(m.email) && onToggle(m.email));
                  else items.forEach(m => !selected.has(m.email) && onToggle(m.email));
                }}/>
              <span>Select all</span>
            </label>
          </div>
        )}
      </div>

      {open && (
        <div className="ci-group-bd">
          {items.length === 0 ? (
            <div className="ci-group-empty">No one in this group.</div>
          ) : (
            <>
              <div className="ci-group-list">
                {visible.map(m => React.cloneElement(renderer(m), {
                  key: m.email,
                  checked: selected.has(m.email),
                  onToggle: () => onToggle(m.email),
                  onLog,
                }))}
              </div>
              {items.length > pageSize && (
                <button className="ci-group-more" onClick={() => setPageSize(pageSize + 20)}>
                  Show {Math.min(20, items.length - pageSize)} more · {items.length - pageSize} hidden
                </button>
              )}
            </>
          )}
        </div>
      )}
    </div>
  );
}

function TabClockin() {
  const [filter, setFilter] = cUseState(null);
  const [selected, setSelected] = cUseState(new Set());
  const [toast, setToast] = cUseState(null);
  const [modalTargets, setModalTargets] = cUseState(null);
  const [remindOpen, setRemindOpen] = cUseState(false);

  const counts = cUseMemo(() => {
    const c = { clocked_done: 0, clocked_working: 0, clocked_incomplete: 0, late_critical: 0, late_recent: 0, shift_not_started: 0, on_leave: 0, day_off: 0, unknown: 0 };
    window.YD.MEMBERS.forEach(m => { c[m.clockInReason] = (c[m.clockInReason] || 0) + 1; });
    return c;
  }, []);

  const byReason = cUseMemo(() => {
    const b = {};
    window.YD.MEMBERS.forEach(m => { (b[m.clockInReason] = b[m.clockInReason] || []).push(m); });
    (b.late_critical || []).sort((a, b) => b.minutesLateClock - a.minutesLateClock);
    (b.late_recent || []).sort((a, b) => b.minutesLateClock - a.minutesLateClock);
    (b.shift_not_started || []).sort((a, b) => (a.todayShiftStart || '').localeCompare(b.todayShiftStart || ''));
    return b;
  }, []);

  const toggle = (email) => {
    setSelected(prev => {
      const n = new Set(prev);
      if (n.has(email)) n.delete(email); else n.add(email);
      return n;
    });
  };

  const openLog = (targets) => setModalTargets(targets);
  const openBulkLog = () => {
    const list = window.YD.MEMBERS.filter(m => selected.has(m.email));
    if (list.length) setModalTargets(list);
  };
  const onSaved = (count) => {
    setModalTargets(null);
    setSelected(new Set());
    setToast(`Logged action for ${count} ${count === 1 ? 'person' : 'people'}`);
    setTimeout(() => setToast(null), 2400);
  };

  const today = new Date();
  const needAction = (counts.late_critical || 0) + (counts.late_recent || 0);
  const notDue = counts.shift_not_started || 0;

  return (
    <div className="page page-clockin">
      <PageHeader
        eyebrow={`Today · ${today.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' })} · ${today.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })}`}
        title="Clock-in triage"
        subtitle={`${needAction} need an action · ${counts.late_critical || 0} critical, ${counts.late_recent || 0} late <2h · ${notDue} not yet due today`}
        actions={
          <div className="flex g8 ac">
            <button className="btn">Export</button>
          </div>
        }/>

      <ClockinSummaryStrip counts={counts} selected={filter} onSelect={setFilter}/>

      {selected.size > 0 && (
        <div className="ci-bulk-bar">
          <div className="ci-bulk-bar-lbl">
            <strong>{selected.size}</strong> selected
            <button className="btn btn-ghost btn-sm" onClick={() => setSelected(new Set())}>Clear</button>
          </div>
          <div className="ci-bulk-bar-actions">
            <button className="btn btn-sm" onClick={() => setRemindOpen(true)}>
              Remind in Chat
            </button>
            <button className="btn btn-sm btn-dark" onClick={openBulkLog}>
              + Log action for {selected.size}
            </button>
          </div>
        </div>
      )}

      {remindOpen && (
        <RemindInChatModal
          targets={Array.from(selected).map((email) => window.YD.MEMBERS.find((m) => m.email === email)).filter(Boolean)}
          onClose={() => setRemindOpen(false)}
          onSent={(sentCount, results) => {
            setRemindOpen(false);
            setSelected(new Set());
            const failed = results.filter((r) => !r.sent);
            const fellBack = results.filter((r) => r.sent && r.source && r.source !== 'team');
            if (failed.length > 0) {
              setToast(`Sent to ${sentCount}; ${failed.length} team${failed.length === 1 ? '' : 's'} failed — check Chat config.`);
            } else if (fellBack.length > 0) {
              const teams = fellBack.map((r) => r.team).join(', ');
              setToast(`Sent to ${sentCount}, but ${fellBack.length === 1 ? '' : `${fellBack.length} teams (`}${teams}${fellBack.length === 1 ? '' : ')'} used the default webhook — check Settings → Notifications → Chat webhooks.`);
            } else {
              setToast(`Reminder sent · ${sentCount} ${sentCount === 1 ? 'person' : 'people'}`);
            }
            setTimeout(() => setToast(null), 5000);
          }}/>
      )}

      <div className="ci-groups">
        {(filter === null || filter === 'late_critical') && (
          <ClockinGroup sev="critical" title="Critical — call now" subtitle="Late > 2h · escalate if unreachable"
            items={byReason.late_critical || []} defaultOpen bulkActions
            selected={selected} onToggle={toggle} onLog={openLog}
            renderer={(m) => <ClockinRowDetailed m={m}/>}/>
        )}
        {(filter === null || filter === 'late_recent') && (
          <ClockinGroup sev="high" title="Late — recoverable" subtitle="Within 2h of shift start · ping first"
            items={byReason.late_recent || []} defaultOpen={false} bulkActions
            selected={selected} onToggle={toggle} onLog={openLog}
            renderer={(m) => <ClockinRowCompact m={m} sev="high"/>}/>
        )}
        {(filter === null || filter === 'shift_not_started') && (
          <ClockinGroup sev="ok" title="Not yet started" subtitle="Afternoon/evening shifts · no action"
            items={byReason.shift_not_started || []} defaultOpen={false} bulkActions={false}
            selected={selected} onToggle={toggle} onLog={openLog}
            renderer={(m) => <ClockinRowMinimal m={m} sev="ok"/>}/>
        )}
        {(filter === null || filter === 'on_leave') && (
          <ClockinGroup sev="leave" title="On approved leave" subtitle="No action needed"
            items={byReason.on_leave || []} defaultOpen={false} bulkActions={false}
            selected={selected} onToggle={toggle} onLog={openLog}
            renderer={(m) => <ClockinRowMinimal m={m} sev="leave"/>}/>
        )}
        {(filter === null || filter === 'day_off') && (
          <ClockinGroup sev="ok" title="Day off" subtitle="Scheduled rest day"
            items={byReason.day_off || []} defaultOpen={false} bulkActions={false}
            selected={selected} onToggle={toggle} onLog={openLog}
            renderer={(m) => <ClockinRowMinimal m={m} sev="ok"/>}/>
        )}
      </div>

      {toast && <div className="toast">{toast}</div>}
      {modalTargets && (
        <ActionModal
          targets={modalTargets}
          onClose={() => setModalTargets(null)}
          onSaved={onSaved}/>
      )}
    </div>
  );
}

// Confirms the Chat reminder send and lets the lead append a note. Groups
// the target list by team so the lead can see "this will post to UGC A's
// Space and UGC B's Space" before clicking. Backend posts one card per
// team using getTeamWebhook; PMs (admins) can mix teams in one selection.
function RemindInChatModal({ targets, onClose, onSent }) {
  const [note, setNote] = cUseState('');
  const [busy, setBusy] = cUseState(false);
  const [err, setErr] = cUseState(null);

  // Group targets by team for the preview.
  const byTeam = {};
  for (const m of targets) {
    const team = m.team || 'Unassigned';
    (byTeam[team] = byTeam[team] || []).push(m);
  }
  const teamNames = Object.keys(byTeam).sort();

  const submit = async () => {
    setBusy(true); setErr(null);
    try {
      const resp = await window.YDApp.call('notifyClockInReminder', {
        emails: targets.map((m) => m.email),
        note: note.trim(),
      });
      onSent(resp.sentCount || 0, resp.results || []);
    } catch (e) {
      setErr(e.message || String(e));
      setBusy(false);
    }
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div
        className="modal-card modal-card-wide"
        onClick={(e) => e.stopPropagation()}
        style={{ maxHeight: 'calc(100vh - 40px)', display: 'flex', flexDirection: 'column' }}>
        <div className="modal-hd" style={{ flex: '0 0 auto' }}>
          <h3>Remind in Chat · {targets.length} {targets.length === 1 ? 'person' : 'people'}</h3>
          <button className="modal-x" onClick={onClose} aria-label="Close">×</button>
        </div>
        <div className="modal-bd" style={{ overflowY: 'auto', flex: '1 1 auto', minHeight: 0 }}>
          <div className="meta" style={{ marginBottom: 10 }}>
            One Chat card per team. Each Space gets a list of who to nudge plus your optional note. Make sure each team has a webhook in <code>config/chat</code> first — teams without one are flagged after sending.
          </div>
          {teamNames.map((team) => (
            <div key={team} style={{ marginBottom: 12 }}>
              <div style={{ fontWeight: 700, fontSize: 13, marginBottom: 4 }}>
                {team} <span className="meta">· {byTeam[team].length} {byTeam[team].length === 1 ? 'annotator' : 'annotators'}</span>
              </div>
              <div className="meta" style={{ fontSize: 11, paddingLeft: 8 }}>
                {byTeam[team].map((m) => m.name).join(' · ')}
              </div>
            </div>
          ))}
          <label className="modal-lbl" style={{ marginTop: 12 }}>Note (optional)</label>
          <textarea
            className="modal-input"
            value={note}
            onChange={(e) => setNote(e.target.value)}
            disabled={busy}
            rows={3}
            placeholder="e.g. Day's productivity matters · please clock in within 15 min"/>
          {err && <div className="modal-err">{err}</div>}
        </div>
        <div className="modal-actions" style={{ flex: '0 0 auto' }}>
          <button className="btn" onClick={onClose} disabled={busy}>Cancel</button>
          <button className="btn btn-dark" onClick={submit} disabled={busy}>
            {busy ? 'Sending…' : `Send to ${teamNames.length} Space${teamNames.length === 1 ? '' : 's'}`}
          </button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { TabClockin });
