// src/features/admin/ui/admin-schedule-modals.jsx
//
// The series-actions modal (reschedule whole series / cancel whole
// series from this lesson forward). Extracted from admin-schedule.jsx
// so the main file is closer to budget.
//
// Public on window: AdminSeriesActionsModal.

// admin-schedule.jsx — Business-wide schedule view.
//
// Joe wanted a single place to see EVERY class across the business:
// what happened today, what's happening today, what's coming up. Joe's
// requirement: "calendar view (or at least a list view about all the
// classes that happened, are happening today, and will happen".
//
// We render it as a filterable list grouped by day. (A real calendar
// grid view is a later enhancement — the list is what Joe explicitly
// allowed-as-good-enough in his message.)

const adminSchH = (h) => h === 0 ? '12 AM' : h === 12 ? '12 PM' : h > 12 ? `${h-12} PM` : `${h} AM`;
const adminSchFmt$ = (n) => n == null || n === '' ? '—' : '$' + Number(n);

// Admin-side timezone helpers. Every displayed time should carry the
// abbreviation so admin always knows whether the clock he's reading is
// EDT, PDT, BST, etc. — otherwise a 9 PM lesson with a teacher in another
// zone is ambiguous. The full IANA name is exposed for hover/tooltip use.
const adminSchTz = (() => {
  try { return Intl.DateTimeFormat().resolvedOptions().timeZone; }
  catch (e) { return 'UTC'; }
})();
const adminSchTzAbbrev = (date) => {
  try {
    const parts = new Intl.DateTimeFormat('en-US', { timeZone: adminSchTz, timeZoneName: 'short' })
      .formatToParts(date || new Date());
    return parts.find(p => p.type === 'timeZoneName')?.value || '';
  } catch (e) { return ''; }
};
window.adminSchTz = adminSchTz;
window.adminSchTzAbbrev = adminSchTzAbbrev;

// ── Series Actions Modal ─────────────────────────────────────────────
// Opens when the admin clicks "Series…" on any recurring booking row.
// Two destructive actions, both gated on a confirmation step:
//   - Reschedule this AND all future lessons (shifts everything by the
//     same delta — calls admin_reschedule_series_from_here)
//   - Cancel this AND all future lessons (calls admin_cancel_series_from_here)
const AdminSeriesActionsModal = ({ booking, onClose }) => {
  const data = window.useAdminData();
  const original = new Date(booking.scheduledAt);
  const [mode, setMode]         = React.useState(null);    // null | 'reschedule' | 'cancel'
  const [newDate, setNewDate]   = React.useState(() => booking.scheduledAt.slice(0, 10));
  const [newTime, setNewTime]   = React.useState(() => {
    const d = new Date(booking.scheduledAt);
    return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
  });
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');

  const newDateObj = (() => {
    try { return new Date(`${newDate}T${newTime}:00`); }
    catch (e) { return null; }
  })();
  const newTzAbbrev = newDateObj && !isNaN(newDateObj) ? adminSchTzAbbrev(newDateObj) : adminSchTzAbbrev();

  const submit = async () => {
    setBusy(true); setError('');
    try {
      if (mode === 'reschedule') {
        const newIso = newDateObj.toISOString();
        const n = await data.rescheduleSeriesFromHere(booking.id, newIso);
        const newWhen = newDateObj.toLocaleString(undefined, { weekday:'short', month:'short', day:'numeric', hour:'numeric', minute:'2-digit' });
        alert(`✓ ${n} lesson${n === 1 ? '' : 's'} rescheduled to ${newWhen} ${newTzAbbrev} (this + all future).`);
      } else if (mode === 'cancel') {
        const n = await data.cancelSeriesFromHere(booking.id);
        alert(`✓ ${n} lesson${n === 1 ? '' : 's'} cancelled (this + all future).`);
      }
      onClose();
    } catch (e) { setError(e.message || 'Operation failed.'); }
    finally { setBusy(false); }
  };

  const fld = { width:'100%', padding:'11px 13px', borderRadius:8, border:'1.5px solid oklch(88% 0.015 265)', fontSize:14, fontFamily:"'Plus Jakarta Sans', sans-serif", color:'oklch(22% 0.06 265)', background:'#fff', outline:'none', boxSizing:'border-box' };
  const lbl = { display:'block', fontSize:10, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(52% 0.04 265)', marginBottom:5 };

  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(10,12,24,0.4)', display:'flex', alignItems:'center', justifyContent:'center', zIndex:9000, padding:18 }} onClick={onClose}>
      <div style={{ background:'#fff', borderRadius:14, padding:'26px', width:460, maxHeight:'92vh', overflowY:'auto', boxShadow:'0 20px 60px rgba(0,0,0,0.2)', fontFamily:"'Plus Jakarta Sans', sans-serif" }} onClick={e => e.stopPropagation()}>
        <div style={{ fontWeight:700, fontSize:16, color:'oklch(18% 0.03 265)', marginBottom:4 }}>↻ Recurring series actions</div>
        <div style={{ fontSize:12, color:'oklch(58% 0.03 265)', marginBottom:18, lineHeight:1.5 }}>
          This affects <strong>this lesson AND every future occurrence in the series</strong>. To edit just this one lesson, close this and use the per-lesson reschedule/cancel buttons instead.
        </div>

        <div style={{ background:'oklch(98% 0.005 60)', borderRadius:8, padding:'10px 12px', marginBottom:16, fontSize:12, color:'oklch(40% 0.04 265)' }}>
          <div><strong>Picked lesson:</strong> {original.toLocaleDateString(undefined, { weekday:'long', month:'long', day:'numeric' })} at {original.toLocaleTimeString(undefined, { hour:'numeric', minute:'2-digit' })} <span style={{ fontWeight:700, color:'oklch(28% 0.05 265)' }}>{adminSchTzAbbrev(original)}</span></div>
          <div style={{ marginTop:4, fontSize:11, color:'oklch(56% 0.03 265)' }} title={adminSchTz}>Times shown in your browser's timezone ({adminSchTz}).</div>
        </div>

        {!mode && (
          <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
            <button onClick={() => setMode('reschedule')}
              style={{ background:'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:9, padding:'13px 16px', fontSize:14, fontWeight:700, cursor:'pointer', textAlign:'left', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
              📅 Move this AND all future lessons to a new time
              <div style={{ fontSize:11, fontWeight:500, opacity:0.85, marginTop:3 }}>Every lesson from this one onwards shifts by the same amount.</div>
            </button>
            <button onClick={() => setMode('cancel')}
              style={{ background:'oklch(96% 0.05 25)', color:'oklch(40% 0.18 25)', border:'1px solid oklch(88% 0.05 25)', borderRadius:9, padding:'13px 16px', fontSize:14, fontWeight:700, cursor:'pointer', textAlign:'left', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
              ✕ Cancel this AND all future lessons
              <div style={{ fontSize:11, fontWeight:500, opacity:0.85, marginTop:3 }}>Already-completed lessons stay intact (history is preserved).</div>
            </button>
            <button onClick={onClose} style={{ background:'oklch(95% 0.01 265)', border:'none', borderRadius:9, padding:'11px 0', fontSize:13, cursor:'pointer', color:'oklch(46% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif", marginTop:6 }}>Close</button>
          </div>
        )}

        {mode === 'reschedule' && (
          <div>
            <div style={{ display:'grid', gridTemplateColumns:'2fr 1fr', gap:10, marginBottom:8 }}>
              <div>
                <label style={lbl}>New date</label>
                <input type="date" value={newDate} onChange={e => setNewDate(e.target.value)} style={fld} />
              </div>
              <div>
                <label style={lbl}>New time</label>
                <input type="time" value={newTime} onChange={e => setNewTime(e.target.value)} style={fld} />
              </div>
            </div>
            <div style={{ fontSize:11, color:'oklch(56% 0.03 265)', marginBottom:14 }} title={adminSchTz}>
              Interpreted in your browser's timezone — <strong>{newTzAbbrev}</strong> ({adminSchTz}).
            </div>
            {error && <div style={{ background:'oklch(95% 0.06 25)', color:'oklch(40% 0.15 25)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12 }}>{error}</div>}
            <div style={{ display:'flex', gap:10 }}>
              <button onClick={submit} disabled={busy} style={{ flex:1, background:'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:9, padding:'12px 0', fontWeight:700, fontSize:14, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", opacity:busy?0.7:1 }}>
                {busy ? 'Saving…' : `Apply to this + all future (${newTzAbbrev})`}
              </button>
              <button onClick={() => setMode(null)} disabled={busy} style={{ padding:'12px 16px', background:'oklch(95% 0.01 265)', border:'none', borderRadius:9, fontSize:13, cursor:'pointer', color:'oklch(46% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>Back</button>
            </div>
          </div>
        )}

        {mode === 'cancel' && (
          <div>
            <div style={{ background:'oklch(96% 0.05 25)', color:'oklch(36% 0.16 25)', padding:'12px 14px', borderRadius:8, fontSize:13, marginBottom:14, lineHeight:1.55 }}>
              ⚠ This will cancel this lesson AND every future lesson in the series. Past + completed lessons stay intact. <strong>This cannot be undone in bulk</strong> — you'd have to re-create each cancelled occurrence manually.
            </div>
            {error && <div style={{ background:'oklch(95% 0.06 25)', color:'oklch(40% 0.15 25)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12 }}>{error}</div>}
            <div style={{ display:'flex', gap:10 }}>
              <button onClick={submit} disabled={busy} style={{ flex:1, background:'oklch(40% 0.18 25)', color:'#fff', border:'none', borderRadius:9, padding:'12px 0', fontWeight:700, fontSize:14, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", opacity:busy?0.7:1 }}>
                {busy ? 'Cancelling…' : 'Yes, cancel all future'}
              </button>
              <button onClick={() => setMode(null)} disabled={busy} style={{ padding:'12px 16px', background:'oklch(95% 0.01 265)', border:'none', borderRadius:9, fontSize:13, cursor:'pointer', color:'oklch(46% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>Back</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};


window.AdminSeriesActionsModal = AdminSeriesActionsModal;


// ── Delete Booking Modal ────────────────────────────────────────────
// Opens when the admin clicks "Delete" on any booking row. For one-off
// bookings it's a single confirmation. For bookings that are part of a
// recurring series it offers two choices: delete just this occurrence,
// or delete this AND every later occurrence in the series.
const AdminDeleteBookingModal = ({ booking, onClose }) => {
  const data = window.useAdminData();
  const [busy, setBusy]   = React.useState(false);
  const [error, setError] = React.useState('');

  const at        = new Date(booking.scheduledAt);
  const teacher   = (data.instructors || []).find(i => i.id === booking.instructorId);
  const student   = (data.students    || []).find(s => s.id === booking.studentId);
  const isSeries  = !!booking.seriesId;
  // "Future" here means "this occurrence + every later one in the series".
  // Read from the local cache so the count appears instantly; the DB-side
  // delete uses the same gte('scheduled_at', ref) so they stay aligned.
  const futureCount = isSeries
    ? (data.bookings || []).filter(b => b.seriesId === booking.seriesId && b.scheduledAt >= booking.scheduledAt).length
    : 1;

  const deleteOne = async () => {
    setBusy(true); setError('');
    try { await data.deleteBooking(booking.id); onClose(); }
    catch (e) { setError(e.message || 'Delete failed'); setBusy(false); }
  };
  const deleteFuture = async () => {
    setBusy(true); setError('');
    try {
      const n = await data.deleteSeriesFromHere(booking.id);
      onClose();
      alert(`✓ ${n} class${n === 1 ? '' : 'es'} deleted (this + all future).`);
    } catch (e) { setError(e.message || 'Delete failed'); setBusy(false); }
  };

  const dangerBtn = (filled) => ({
    background: filled ? 'oklch(40% 0.18 25)' : '#fff',
    color: filled ? '#fff' : 'oklch(40% 0.18 25)',
    border: filled ? 'none' : '1px solid oklch(82% 0.12 25)',
    borderRadius:9, padding:'13px 16px', fontSize:14, fontWeight:700,
    cursor: busy ? 'wait' : 'pointer', textAlign:'left',
    fontFamily:"'Plus Jakarta Sans', sans-serif", opacity: busy ? 0.7 : 1,
  });

  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(10,12,24,0.4)', display:'flex', alignItems:'center', justifyContent:'center', zIndex:9000, padding:18 }} onClick={onClose}>
      <div style={{ background:'#fff', borderRadius:14, padding:'26px', width:460, maxHeight:'92vh', overflowY:'auto', boxShadow:'0 20px 60px rgba(0,0,0,0.2)', fontFamily:"'Plus Jakarta Sans', sans-serif" }} onClick={e => e.stopPropagation()}>
        <div style={{ fontWeight:700, fontSize:16, color:'oklch(18% 0.03 265)', marginBottom:4 }}>Delete class</div>
        <div style={{ fontSize:12, color:'oklch(58% 0.03 265)', marginBottom:14, lineHeight:1.5 }}>
          Rows are permanently removed from the database. This cannot be undone.
        </div>

        <div style={{ background:'oklch(98% 0.005 60)', borderRadius:8, padding:'10px 12px', marginBottom:16, fontSize:12, color:'oklch(40% 0.04 265)', lineHeight:1.5 }}>
          <div><strong>{student?.name || 'Student'}</strong> with <strong>{teacher?.name || 'Teacher'}</strong></div>
          <div>{at.toLocaleDateString(undefined, { weekday:'long', month:'long', day:'numeric' })} · {at.toLocaleTimeString(undefined, { hour:'numeric', minute:'2-digit' })} <span style={{ fontWeight:700, color:'oklch(28% 0.05 265)' }}>{adminSchTzAbbrev(at)}</span> · {booking.durationMinutes} min</div>
          {isSeries && (
            <div style={{ marginTop:5, color:'oklch(36% 0.13 75)', fontWeight:600 }}>
              ↻ Part of a recurring series — {futureCount} occurrence{futureCount === 1 ? '' : 's'} from this one onwards.
            </div>
          )}
          <div style={{ marginTop:5, fontSize:11, color:'oklch(56% 0.03 265)' }} title={adminSchTz}>Times shown in your browser's timezone ({adminSchTz}).</div>
        </div>

        {error && <div style={{ background:'oklch(95% 0.06 25)', color:'oklch(40% 0.15 25)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12 }}>{error}</div>}

        <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
          <button onClick={deleteOne} disabled={busy} style={dangerBtn(true)}>
            {busy ? 'Deleting…' : 'Delete only this class'}
            <div style={{ fontSize:11, fontWeight:500, opacity:0.85, marginTop:3 }}>
              {isSeries ? 'Other occurrences in the series stay intact.' : 'Removes this single booking row.'}
            </div>
          </button>
          {isSeries && futureCount > 1 && (
            <button onClick={deleteFuture} disabled={busy} style={dangerBtn(false)}>
              Delete this + all {futureCount - 1} future class{futureCount - 1 === 1 ? '' : 'es'}
              <div style={{ fontSize:11, fontWeight:500, opacity:0.85, marginTop:3 }}>
                Every occurrence from this one onwards is permanently removed.
              </div>
            </button>
          )}
          <button onClick={onClose} disabled={busy} style={{ background:'oklch(95% 0.01 265)', border:'none', borderRadius:9, padding:'11px 0', fontSize:13, cursor: busy ? 'wait' : 'pointer', color:'oklch(46% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif", marginTop:6 }}>
            Cancel
          </button>
        </div>
      </div>
    </div>
  );
};

window.AdminDeleteBookingModal = AdminDeleteBookingModal;


// ── Reschedule Single Booking Modal ─────────────────────────────────
// Opens from the schedule detail drawer's "Reschedule this class" action.
// Moves ONE booking to a new date/time through the normal booking-update
// path (data.updateBooking → bookings.scheduled_at), which also PATCHes
// the teacher's Google Calendar event. For a recurring booking this shifts
// only THIS occurrence; "this + all future" stays the job of the series-
// actions modal. No email fires on a direct move — same as the existing
// approve-reschedule path, which also silently updates the time.
const AdminRescheduleBookingModal = ({ booking, onClose }) => {
  const data = window.useAdminData();
  const original = new Date(booking.scheduledAt);
  const [newDate, setNewDate] = React.useState(() => booking.scheduledAt.slice(0, 10));
  const [newTime, setNewTime] = React.useState(() => {
    const d = new Date(booking.scheduledAt);
    return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
  });
  const [busy, setBusy]   = React.useState(false);
  const [error, setError] = React.useState('');

  const teacher  = (data.instructors || []).find(i => i.id === booking.instructorId);
  const student  = (data.students    || []).find(s => s.id === booking.studentId);
  const isSeries = !!booking.seriesId;
  // For a recurring lesson: 'one' moves just this occurrence; 'future' shifts
  // this + every later occurrence by the same delta via rescheduleSeriesFromHere
  // (which also PATCHes each lesson's event on Google). Default 'one' so a
  // recurring lesson is never mass-moved by accident.
  const [scope, setScope] = React.useState('one');
  const futureCount = isSeries
    ? (data.bookings || []).filter(b => b.seriesId === booking.seriesId && b.scheduledAt >= booking.scheduledAt).length
    : 1;

  // Teacher availability (weekly hours + blocked time + tz). Loaded once so we
  // can HARD-BLOCK moving the class to a time the teacher hasn't opened up —
  // same constraint the student booking page enforces. A teacher with no
  // weekly hours set is unconstrained. Fails open on load error.
  const [availCtx, setAvailCtx] = React.useState(null);
  React.useEffect(() => {
    let cancelled = false;
    window.Calendar.db.loadAvailabilityContext(booking.instructorId)
      .then(ctx => { if (!cancelled) setAvailCtx(ctx); })
      .catch(() => { if (!cancelled) setAvailCtx({ slots: [], exceptions: [], instructorTz: null }); });
    return () => { cancelled = true; };
  }, [booking.instructorId]);

  const newDateObj = (() => {
    const d = new Date(`${newDate}T${newTime}:00`);
    return isNaN(d.getTime()) ? null : d;
  })();
  const newTzAbbrev = newDateObj ? adminSchTzAbbrev(newDateObj) : adminSchTzAbbrev();
  const unchanged = !!newDateObj && newDateObj.getTime() === original.getTime();
  const inPast    = !!newDateObj && newDateObj.getTime() < new Date().getTime();
  // Summary converted into the admin's browser zone so the hours line up with the
  // date/time picker (browser-local) instead of the teacher's raw local numbers.
  const availSummary = availCtx ? window.Calendar.shape.weeklyAvailabilitySummary(availCtx.slots, availCtx.instructorTz, adminSchTz, newDateObj) : '';
  // Soft signals only (Move anyway) — and never on a no-op. Distinguish "outside
  // weekly hours" from "overlaps an existing lesson / blocked time".
  const outsideHours = !!(availCtx && newDateObj) && !unchanged && availCtx.slots.length > 0 &&
    !window.Calendar.shape.isWithinWeeklyAvailability(availCtx.slots, newDateObj, booking.durationMinutes, availCtx.instructorTz);
  const conflict = !!(availCtx && newDateObj) && !unchanged &&
    !!window.Calendar.shape.isSlotBlocked(availCtx.exceptions, newDateObj, booking.durationMinutes);
  const outsideAvailability = outsideHours || conflict;

  const submit = async () => {
    if (!newDateObj) { setError('Pick a valid date and time.'); return; }
    if (unchanged)   { onClose(); return; }
    setBusy(true); setError('');
    try {
      const newWhen = newDateObj.toLocaleString(undefined, { weekday:'short', month:'short', day:'numeric', hour:'numeric', minute:'2-digit' });
      if (isSeries && scope === 'future') {
        // Shift this + every later occurrence by the same delta. The RPC pushes
        // an 'update' to Google for each moved lesson, so the calendar matches.
        const n = await data.rescheduleSeriesFromHere(booking.id, newDateObj.toISOString());
        onClose();
        alert(`✓ ${n} lesson${n === 1 ? '' : 's'} moved to ${newWhen} ${newTzAbbrev} (this + all future).`);
        return;
      }
      const patch = { scheduledAt: newDateObj.toISOString() };
      // A pending reschedule request is moot once the admin sets the time
      // directly — clear it in the same write so the drawer's "Reschedule
      // requested" banner doesn't linger on a now-stale proposed time.
      if (booking.rescheduleRequestedAt) {
        patch.rescheduleRequestedAt = null;
        patch.rescheduleRequestedBy = null;
      }
      await data.updateBooking(booking.id, patch);
      onClose();
      alert(`✓ Class moved to ${newWhen} ${newTzAbbrev}.`);
    } catch (e) { setError(e.message || 'Reschedule failed.'); setBusy(false); }
  };

  const fld = { width:'100%', padding:'11px 13px', borderRadius:8, border:'1.5px solid oklch(88% 0.015 265)', fontSize:14, fontFamily:"'Plus Jakarta Sans', sans-serif", color:'oklch(22% 0.06 265)', background:'#fff', outline:'none', boxSizing:'border-box' };
  const lbl = { display:'block', fontSize:10, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(52% 0.04 265)', marginBottom:5 };
  const scopeBtn = (active) => ({
    flex:1, padding:'9px 10px', borderRadius:8, fontSize:12.5, fontWeight:700, cursor:'pointer',
    fontFamily:"'Plus Jakarta Sans', sans-serif",
    border: active ? '1.5px solid oklch(22% 0.06 265)' : '1.5px solid oklch(88% 0.02 265)',
    background: active ? 'oklch(22% 0.06 265)' : '#fff',
    color: active ? '#fff' : 'oklch(40% 0.04 265)',
  });
  const disabled = busy || !newDateObj;

  return (
    <div style={{ position:'fixed', inset:0, background:'rgba(10,12,24,0.4)', display:'flex', alignItems:'center', justifyContent:'center', zIndex:9000, padding:18 }} onClick={onClose}>
      <div style={{ background:'#fff', borderRadius:14, padding:'26px', width:'min(460px, 92vw)', maxHeight:'92vh', overflowY:'auto', boxShadow:'0 20px 60px rgba(0,0,0,0.2)', fontFamily:"'Plus Jakarta Sans', sans-serif" }} onClick={e => e.stopPropagation()}>
        <div style={{ fontWeight:700, fontSize:16, color:'oklch(18% 0.03 265)', marginBottom:4 }}>📅 Reschedule class</div>
        <div style={{ fontSize:12, color:'oklch(58% 0.03 265)', marginBottom:16, lineHeight:1.5 }}>
          {isSeries ? 'Move just this lesson, or shift this lesson and every future one in the series.' : 'Move this class to a new date and time.'}
        </div>

        <div style={{ background:'oklch(98% 0.005 60)', borderRadius:8, padding:'10px 12px', marginBottom:16, fontSize:12, color:'oklch(40% 0.04 265)', lineHeight:1.5 }}>
          <div><strong>{student?.name || 'Student'}</strong> with <strong>{teacher?.name || 'Teacher'}</strong></div>
          <div>Currently: {original.toLocaleDateString(undefined, { weekday:'long', month:'long', day:'numeric' })} at {original.toLocaleTimeString(undefined, { hour:'numeric', minute:'2-digit' })} <span style={{ fontWeight:700, color:'oklch(28% 0.05 265)' }}>{adminSchTzAbbrev(original)}</span> · {booking.durationMinutes} min</div>
          {isSeries && (
            <div style={{ marginTop:5, color:'oklch(36% 0.13 75)', fontWeight:600 }}>
              ↻ Part of a recurring series
            </div>
          )}
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'2fr 1fr', gap:10, marginBottom:8 }}>
          <div>
            <label style={lbl}>New date</label>
            <input type="date" value={newDate} onChange={e => setNewDate(e.target.value)} style={fld} />
          </div>
          <div>
            <label style={lbl}>New time</label>
            <input type="time" value={newTime} onChange={e => setNewTime(e.target.value)} style={fld} />
          </div>
        </div>
        <div style={{ fontSize:11, color:'oklch(56% 0.03 265)', marginBottom:14 }} title={adminSchTz}>
          Interpreted in your browser's timezone — <strong>{newTzAbbrev}</strong> ({adminSchTz}).
        </div>

        {isSeries && futureCount > 1 && (
          <div style={{ marginBottom:14 }}>
            <label style={lbl}>Apply to</label>
            <div style={{ display:'flex', gap:8 }}>
              <button type="button" onClick={() => setScope('one')} style={scopeBtn(scope === 'one')}>
                Just this lesson
              </button>
              <button type="button" onClick={() => setScope('future')} style={scopeBtn(scope === 'future')}>
                This + all {futureCount - 1} future
              </button>
            </div>
            <div style={{ fontSize:11, color:'oklch(56% 0.03 265)', marginTop:7, lineHeight:1.5 }}>
              {scope === 'future'
                ? 'Every lesson from this one onwards shifts by the same amount — on the platform and on the teacher’s Google Calendar.'
                : 'Only this single occurrence moves; the rest of the series stays where it is.'}
            </div>
          </div>
        )}

        {inPast && !unchanged && (
          <div style={{ background:'oklch(96.5% 0.07 80)', color:'oklch(40% 0.13 75)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12 }}>
            Heads up — that date and time is in the past.
          </div>
        )}
        {availSummary && (
          <div style={{ fontSize:11, color:'oklch(54% 0.03 265)', marginBottom: outsideAvailability ? 6 : 12, lineHeight:1.5 }}>
            Available: <strong>{availSummary}</strong> <span style={{ color:'oklch(62% 0.02 265)' }}>(in your time zone)</span>
          </div>
        )}
        {outsideAvailability && (
          <div style={{ background:'oklch(96.5% 0.06 75)', color:'oklch(42% 0.13 70)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12, lineHeight:1.5 }}>
            {outsideHours
              ? `Heads up — that's outside ${teacher?.name || 'the teacher'}'s weekly hours.`
              : `Heads up — ${teacher?.name || 'the teacher'} already has a lesson or blocked time then.`}
            {' '}You can still move it.
          </div>
        )}
        {error && <div style={{ background:'oklch(95% 0.06 25)', color:'oklch(40% 0.15 25)', padding:'9px 12px', borderRadius:8, fontSize:12, marginBottom:12 }}>{error}</div>}

        <div style={{ display:'flex', gap:10 }}>
          <button onClick={submit} disabled={disabled} style={{ flex:1, background: outsideAvailability ? 'oklch(58% 0.14 65)' : 'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:9, padding:'12px 0', fontWeight:700, fontSize:14, cursor: busy ? 'wait' : !newDateObj ? 'not-allowed' : 'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", opacity: disabled ? 0.7 : 1 }}>
            {busy ? 'Saving…' : unchanged ? 'Keep this time' : outsideAvailability ? 'Move anyway' : (isSeries && scope === 'future' ? `Move this + all future` : `Move class (${newTzAbbrev})`)}
          </button>
          <button onClick={onClose} disabled={busy} style={{ padding:'12px 16px', background:'oklch(95% 0.01 265)', border:'none', borderRadius:9, fontSize:13, cursor:'pointer', color:'oklch(46% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>Cancel</button>
        </div>
      </div>
    </div>
  );
};

window.AdminRescheduleBookingModal = AdminRescheduleBookingModal;
