// admin-payouts.jsx — the dedicated Payouts tab (People group, before Instructors).
//
// Joe does payouts monthly. He needs to: pick a date range, see per-teacher how
// many sessions there are, how many actually happened ("confirmed"), how much he
// owes, and press one button to settle a teacher's whole payout for the period.
//
// A "payout" is the teacher_rate on each booking, but it's only OWED for
// CONFIRMED sessions:
//   - absent (bookings.no_show, the teacher's "Mark as absent" button) → never owed.
//   - confirmed = NOT absent AND (teacher added notes OR the lesson is 15 min past
//     its end, scheduled_at + duration + 15). A lesson at 5pm (60 min) confirms at
//     6:15; a 3pm lesson at 4:15.
//   - a not-yet-happened session still shows in the Sessions count (so Joe can wake
//     up and see "2 classes today") but adds $0 until it confirms.
// Settling marks every confirmed + unsettled booking for that teacher (in the
// current range) paid + settled in one update — same end state as the per-booking
// "Payout sent" button, reversible from the instructor card.
//
// Reads useAdminData(); the only write is ADMIN_DATA.settleBookings(ids).

const AP_PRESETS = [
  { id:'today',     label:'Today'        },
  { id:'yesterday', label:'Yesterday'    },
  { id:'tomorrow',  label:'Tomorrow'     },
  { id:'7d',        label:'Last 7 days'  },
  { id:'30d',       label:'Last 30 days' },
  { id:'month',     label:'This month'   },
  { id:'lastmonth', label:'Last month'   },
  { id:'all',       label:'All time'     },
  { id:'custom',    label:'Custom'       },
];
// Calendar-date math on YYYY-MM-DD keys, anchored at noon UTC so a DST shift
// can't roll a date across midnight.
const apAddDays = (key, n) => {
  const [y,m,d] = key.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m-1, d, 12));
  dt.setUTCDate(dt.getUTCDate() + n);
  return dt.toISOString().slice(0,10);
};
const apMonthStart = (key) => key.slice(0,7) + '-01';
const apMonthEnd = (key) => {
  const [y,m] = key.split('-').map(Number);
  const last = new Date(Date.UTC(y, m, 0, 12)).getUTCDate();
  return `${y}-${String(m).padStart(2,'0')}-${String(last).padStart(2,'0')}`;
};
const apPrevMonthStart = (key) => {
  const [y,m] = key.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m-1, 1, 12));
  dt.setUTCMonth(dt.getUTCMonth() - 1);
  return dt.toISOString().slice(0,7) + '-01';
};
const apResolveRange = (preset, today, cFrom, cTo) => {
  switch (preset) {
    case 'today':     return { start: today, end: today };
    case 'yesterday': { const y = apAddDays(today, -1); return { start:y, end:y }; }
    case 'tomorrow':  { const t = apAddDays(today,  1); return { start:t, end:t }; }
    case '7d':        return { start: apAddDays(today, -6),  end: today };
    case '30d':       return { start: apAddDays(today, -29), end: today };
    case 'month':     return { start: apMonthStart(today),   end: apMonthEnd(today) };
    case 'lastmonth': { const s = apPrevMonthStart(today);   return { start: s, end: apMonthEnd(s) }; }
    case 'all':       return { start: null, end: null };
    case 'custom':    return { start: cFrom || null, end: cTo || null };
    default:          return { start: today, end: today };
  }
};
const apFmtKey = (k) => {
  if (!k) return '';
  const [y,m,d] = k.split('-').map(Number);
  return new Date(Date.UTC(y, m-1, d, 12)).toLocaleDateString(undefined, { month:'short', day:'numeric', year:'numeric' });
};
const ap$ = (n) => {
  const v = Math.round((Number(n) || 0) * 100) / 100;
  return '$' + (Number.isInteger(v) ? v.toLocaleString() : v.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
};

const AdminPayouts = () => {
  const data = window.useAdminData();
  const [preset, setPreset]     = React.useState('today');
  const [cFrom, setCFrom]       = React.useState('');
  const [cTo, setCTo]           = React.useState('');
  const [confirmId, setConfirmId] = React.useState(null); // teacher row pending settle-confirm
  const [busyId, setBusyId]     = React.useState(null);
  const [err, setErr]           = React.useState('');
  // Re-render every minute so a lesson auto-confirms on screen 15 min after it ends.
  const [nowMin, setNowMin] = React.useState(() => Math.floor(Date.now() / 60000));
  React.useEffect(() => {
    const t = setInterval(() => setNowMin(Math.floor(Date.now() / 60000)), 60000);
    return () => clearInterval(t);
  }, []);

  const adminTz = window.adminSchTz;
  const ymd = React.useCallback((iso) => {
    if (!iso) return '';
    try { return window.Calendar.time.dateKey(new Date(iso), adminTz); }
    catch (e) { return (iso || '').slice(0, 10); }
  }, [adminTz]);
  const today = ymd(new Date().toISOString());
  const range = apResolveRange(preset, today, cFrom, cTo);

  const agg = React.useMemo(() => {
    const sampleIds = new Set((data.instructors || []).filter(i => i.isSample).map(i => i.id));
    const nameById  = new Map((data.instructors || []).map(i => [i.id, i.name]));
    const inRange   = (k) => !!k && (!range.start || k >= range.start) && (!range.end || k <= range.end);
    const now = Date.now();
    const CONFIRM_MS = 15 * 60000;
    const byIns = new Map();
    let sessions = 0, confirmed = 0, absent = 0, payout = 0, settled = 0, stillToPay = 0, confirmedNoRate = 0;
    for (const b of (data.bookings || [])) {
      if (b.status === 'cancelled') continue;       // cancelled never counts
      if (sampleIds.has(b.instructorId)) continue;   // sample instructors aren't real money
      if (!inRange(ymd(b.scheduledAt))) continue;
      const isAbsent = b.noShow === true;
      const hasNotes = !!(b.teacherNotes && b.teacherNotes.trim());
      const endMs    = new Date(b.scheduledAt).getTime() + (Number(b.durationMinutes) || 60) * 60000;
      const timePassed = Number.isFinite(endMs) && now >= endMs + CONFIRM_MS;
      const isConfirmed = !isAbsent && (hasNotes || timePassed);
      const hasRate = b.teacherRate != null;
      const rate = hasRate ? (Number(b.teacherRate) || 0) : 0;
      const cur = byIns.get(b.instructorId) || {
        id: b.instructorId,
        name: nameById.get(b.instructorId) || b.instructor?.name || 'Unknown teacher',
        sessions: 0, confirmed: 0, absent: 0, payout: 0, settled: 0, stillToPay: 0, unsettledIds: [],
      };
      cur.sessions += 1;
      if (isAbsent) cur.absent += 1;
      if (isConfirmed) {
        cur.confirmed += 1; cur.payout += rate;
        if (!hasRate) confirmedNoRate += 1;
        if (b.settled) cur.settled += rate;
        else { cur.stillToPay += rate; cur.unsettledIds.push(b.id); }
      }
      byIns.set(b.instructorId, cur);
      sessions += 1; if (isAbsent) absent += 1;
      if (isConfirmed) { confirmed += 1; payout += rate; if (b.settled) settled += rate; else stillToPay += rate; }
    }
    const rows = [...byIns.values()].sort((a,b) => b.stillToPay - a.stillToPay || b.payout - a.payout || b.sessions - a.sessions);
    return { rows, sessions, confirmed, absent, payout, settled, stillToPay, confirmedNoRate, teachers: rows.length };
  }, [data.bookings, data.instructors, range.start, range.end, ymd, nowMin]);

  const rangeLabel = (() => {
    if (preset === 'all') return 'All time';
    if (preset === 'custom') {
      const s = range.start, e = range.end;
      if (s && e) return `${apFmtKey(s)} – ${apFmtKey(e)}`;
      if (s)      return `${apFmtKey(s)} onward`;
      if (e)      return `Through ${apFmtKey(e)}`;
      return 'All dates';
    }
    if (range.start === range.end) return apFmtKey(range.start);
    return `${apFmtKey(range.start)} – ${apFmtKey(range.end)}`;
  })();

  const doSettle = async (row) => {
    setBusyId(row.id); setErr('');
    try { await data.settleBookings(row.unsettledIds); }
    catch (e) { setErr((row.name || 'Teacher') + ': ' + (e.message || 'settle failed')); }
    finally { setBusyId(null); setConfirmId(null); }
  };

  const chip = (active) => ({
    background: active ? 'oklch(22% 0.06 265)' : 'oklch(97% 0.005 265)',
    color: active ? '#fff' : 'oklch(42% 0.04 265)',
    border: '1px solid ' + (active ? 'oklch(22% 0.06 265)' : 'oklch(89% 0.02 265)'),
    borderRadius: 20, padding:'6px 14px', fontSize:12.5, fontWeight:600,
    cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", whiteSpace:'nowrap',
  });
  const dateInput = { marginLeft:7, padding:'5px 8px', borderRadius:7, border:'1px solid oklch(88% 0.02 265)', fontSize:12, fontFamily:"'Plus Jakarta Sans', sans-serif", color:'oklch(24% 0.05 265)' };
  const th = (align) => ({ textAlign:align, padding:'9px 10px', fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.05em', color:'oklch(56% 0.03 265)' });
  const td = (align, opts={}) => ({ textAlign:align, padding:'10px', fontSize:13.5, color:'oklch(26% 0.05 265)', verticalAlign:'middle', ...opts });

  if (data.loading) {
    return <div style={{ padding:60, textAlign:'center', color:'oklch(55% 0.03 265)', fontSize:14 }}>Loading payouts…</div>;
  }

  return (
    <div>
      <div style={{ background:'#fff', borderRadius:14, border:'1px solid oklch(90% 0.01 265)', boxShadow:'0 1px 4px oklch(18% 0.06 265 / 0.04)', padding:'20px 24px', marginBottom:22 }}>
        {/* Header: title + date-range chips */}
        <div style={{ display:'flex', alignItems:'flex-start', justifyContent:'space-between', gap:14, flexWrap:'wrap', marginBottom:16 }}>
          <div>
            <div style={{ fontSize:18, fontWeight:700, color:'oklch(15% 0.04 265)' }}>Payouts</div>
            <div style={{ fontSize:12, color:'oklch(56% 0.03 265)', marginTop:3 }}>Owed to teachers · {rangeLabel} · counts only confirmed lessons (15 min after they end, unless marked absent)</div>
          </div>
          <div style={{ display:'flex', gap:6, flexWrap:'wrap' }}>
            {AP_PRESETS.map(p => (
              <button key={p.id} onClick={()=>{ setPreset(p.id); setConfirmId(null); }} style={chip(preset === p.id)}>{p.label}</button>
            ))}
          </div>
        </div>

        {preset === 'custom' && (
          <div style={{ display:'flex', gap:14, flexWrap:'wrap', alignItems:'center', marginBottom:16, padding:'12px 14px', background:'oklch(98% 0.005 60)', borderRadius:10, border:'1px solid oklch(93% 0.01 265)' }}>
            <label style={{ fontSize:12, fontWeight:600, color:'oklch(42% 0.04 265)' }}>From<input type="date" value={cFrom} max={cTo || undefined} onChange={e=>setCFrom(e.target.value)} style={dateInput} /></label>
            <label style={{ fontSize:12, fontWeight:600, color:'oklch(42% 0.04 265)' }}>To<input type="date" value={cTo} min={cFrom || undefined} onChange={e=>setCTo(e.target.value)} style={dateInput} /></label>
          </div>
        )}

        {/* Headline numbers */}
        <div style={{ display:'flex', gap:36, flexWrap:'wrap', alignItems:'flex-end' }}>
          <div>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(58% 0.03 265)', marginBottom:4 }}>Still to pay</div>
            <div style={{ fontFamily:"'Cormorant Garamond', serif", fontSize:40, fontWeight:700, lineHeight:1, color: agg.stillToPay > 0 ? 'oklch(45% 0.16 35)' : 'oklch(40% 0.13 150)' }}>{agg.stillToPay > 0 ? ap$(agg.stillToPay) : 'All settled'}</div>
          </div>
          <div>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(58% 0.03 265)', marginBottom:4 }}>Confirmed payout</div>
            <div style={{ fontFamily:"'Cormorant Garamond', serif", fontSize:40, fontWeight:700, lineHeight:1, color:'oklch(20% 0.06 265)' }}>{ap$(agg.payout)}</div>
          </div>
        </div>
        <div style={{ fontSize:12.5, color:'oklch(50% 0.03 265)', marginTop:10 }}>
          {agg.sessions} session{agg.sessions === 1 ? '' : 's'} · {agg.confirmed} confirmed{agg.absent > 0 ? ` · ${agg.absent} absent` : ''} · {ap$(agg.settled)} already settled
        </div>
        {agg.confirmedNoRate > 0 && (
          <div style={{ fontSize:11.5, color:'oklch(48% 0.12 60)', marginTop:6, fontStyle:'italic' }}>
            {agg.confirmedNoRate} confirmed session{agg.confirmedNoRate === 1 ? '' : 's'} {agg.confirmedNoRate === 1 ? 'has' : 'have'} no teacher rate set — counted as $0.
          </div>
        )}
        {err && <div style={{ fontSize:12, color:'oklch(45% 0.18 25)', marginTop:8, fontWeight:600 }}>{err}</div>}

        {/* Per-teacher breakdown + settle */}
        {agg.rows.length === 0 ? (
          <div style={{ marginTop:18, padding:'20px 0', textAlign:'center', fontSize:13, color:'oklch(62% 0.03 265)', fontStyle:'italic', borderTop:'1px solid oklch(94% 0.005 60)' }}>
            No sessions in this range.
          </div>
        ) : (
          <div style={{ overflowX:'auto', marginTop:18, borderTop:'1px solid oklch(94% 0.005 60)', paddingTop:6 }}>
            <table style={{ width:'100%', borderCollapse:'collapse', minWidth:620 }}>
              <thead>
                <tr style={{ borderBottom:'1.5px solid oklch(90% 0.01 265)' }}>
                  <th style={th('left')}>Teacher</th>
                  <th style={th('right')}>Sessions</th>
                  <th style={th('right')}>Confirmed</th>
                  <th style={th('right')}>Payout</th>
                  <th style={th('right')}>Settled</th>
                  <th style={th('right')}>Still to pay</th>
                  <th style={th('right')}></th>
                </tr>
              </thead>
              <tbody>
                {agg.rows.map(r => {
                  const busy = busyId === r.id;
                  const canSettle = r.unsettledIds.length > 0;
                  return (
                    <tr key={r.id} style={{ borderBottom:'1px solid oklch(95% 0.005 60)' }}>
                      <td style={td('left', { fontWeight:600 })}>{r.name}</td>
                      <td style={td('right')}>{r.sessions}</td>
                      <td style={td('right')}>{r.confirmed}{r.absent > 0 ? <span style={{ color:'oklch(60% 0.1 35)', fontSize:11 }}> · {r.absent} abs</span> : ''}</td>
                      <td style={td('right', { fontWeight:700 })}>{ap$(r.payout)}</td>
                      <td style={td('right', { color:'oklch(45% 0.03 265)' })}>{ap$(r.settled)}</td>
                      <td style={td('right', { fontWeight:700, color: r.stillToPay > 0 ? 'oklch(45% 0.16 35)' : 'oklch(60% 0.02 265)' })}>{r.stillToPay > 0 ? ap$(r.stillToPay) : '—'}</td>
                      <td style={td('right')}>
                        {confirmId === r.id ? (
                          <span style={{ display:'inline-flex', gap:6, alignItems:'center', justifyContent:'flex-end' }}>
                            <button disabled={busy} onClick={()=>doSettle(r)} title={`Marks ${r.unsettledIds.length} confirmed session${r.unsettledIds.length===1?'':'s'} paid + settled`}
                              style={{ background:'oklch(34% 0.13 150)', color:'#fff', border:'none', borderRadius:7, padding:'6px 11px', fontSize:12, fontWeight:700, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", whiteSpace:'nowrap' }}>
                              {busy ? 'Settling…' : `Confirm ${ap$(r.stillToPay)}`}
                            </button>
                            <button disabled={busy} onClick={()=>setConfirmId(null)}
                              style={{ background:'#fff', color:'oklch(45% 0.04 265)', border:'1px solid oklch(88% 0.02 265)', borderRadius:7, padding:'6px 10px', fontSize:12, fontWeight:600, cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
                              Cancel
                            </button>
                          </span>
                        ) : (
                          <button disabled={!canSettle || busy} onClick={()=>{ setErr(''); setConfirmId(r.id); }}
                            title={canSettle ? `Settle this teacher's ${r.unsettledIds.length} confirmed unsettled session${r.unsettledIds.length===1?'':'s'}` : 'Nothing outstanding to settle'}
                            style={{ background: canSettle ? 'oklch(22% 0.06 265)' : 'oklch(96% 0.005 265)', color: canSettle ? '#fff' : 'oklch(70% 0.02 265)', border:'1px solid ' + (canSettle ? 'oklch(22% 0.06 265)' : 'oklch(90% 0.01 265)'), borderRadius:7, padding:'6px 12px', fontSize:12, fontWeight:700, cursor: canSettle ? 'pointer' : 'not-allowed', fontFamily:"'Plus Jakarta Sans', sans-serif", whiteSpace:'nowrap' }}>
                            {canSettle ? `Settle ${ap$(r.stillToPay)}` : 'Settled'}
                          </button>
                        )}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  );
};

Object.assign(window, { AdminPayouts });
