// book-trial.jsx — Calendar picker modal. Student picks a date, then a free slot.
// Times displayed in the student's local timezone with the instructor's TZ shown.

const BookTrialModal = ({ instructor, onClose, onBooked }) => {
  const auth = window.useAuth();
  const studentTz = (Intl.DateTimeFormat().resolvedOptions().timeZone) || 'UTC';
  // Anchor for the instructor's stored availability hours. Loaded from
  // profiles.timezone alongside the other per-instructor data below;
  // falls back to ET only if the profile row has no timezone set (legacy
  // rows pre-v33 trigger).
  const [instructorTz, setInstructorTz] = React.useState('America/New_York');

  const [weekOffset, setWeekOffset] = React.useState(0); // 0 = this week, 1 = next, ...
  const [selectedDate, setSelectedDate] = React.useState(null); // ISO date string yyyy-mm-dd
  const [selectedHour, setSelectedHour] = React.useState(null); // ISO datetime string in UTC
  const [message, setMessage] = React.useState('');
  const [availability, setAvailability] = React.useState([]);
  const [bookings, setBookings] = React.useState([]);
  const [loadingSlots, setLoadingSlots] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [success, setSuccess] = React.useState(null);

  const [exceptions, setExceptions] = React.useState([]);
  React.useEffect(() => {
    (async () => {
      setLoadingSlots(true);
      const nowIso = new Date().toISOString();
      const [{ data: avail }, { data: bks }, { data: exs }, { data: prof }] = await Promise.all([
        window.supa.from('availability_slots').select('*').eq('instructor_id', instructor.id),
        window.supa.from('bookings').select('scheduled_at, duration_minutes').eq('instructor_id', instructor.id).gte('scheduled_at', nowIso),
        // Time-off / one-off blocks (v37). Anonymous viewers may not have a
        // session — RLS lets only authenticated callers SELECT, so anon
        // users get an empty list (no blocks shown). That's intentional:
        // the trial page is mostly for guests; the real booking flow uses
        // InstructorBookingPage which has tighter auth.
        window.supa.from('availability_exceptions').select('*')
          .eq('instructor_id', instructor.id).gte('end_at', nowIso),
        // instructors.id == profiles.id for instructor accounts, so we
        // pull the anchor zone for this instructor's availability hours
        // from profiles.timezone (same pattern as instructor-booking-page).
        window.supa.from('profiles').select('timezone').eq('id', instructor.id).maybeSingle(),
      ]);
      setAvailability(avail || []);
      setBookings(bks || []);
      setExceptions(exs || []);
      if (prof?.timezone) setInstructorTz(prof.timezone);
      setLoadingSlots(false);
    })();
  }, [instructor.id]);

  // Build the 7 days of this/next week
  const today = startOfDay(new Date());
  const weekDays = Array.from({ length: 7 }, (_, i) => addDays(today, i + weekOffset * 7));

  // For the selected date, compute available 1-hour blocks.
  // Slots are anchored in the INSTRUCTOR's timezone: an "9 AM" row in
  // availability_slots means 9 AM on the instructor's clock, regardless
  // of where the student is. We build the slot's absolute moment via
  // Calendar.time.makeDate(...instructorTz), then let the student see it
  // formatted in their own zone downstream.
  const slotsForSelectedDate = React.useMemo(() => {
    if (!selectedDate) return [];
    const [y, m, d] = selectedDate.split('-').map(Number);
    // day_of_week in availability_slots is Sun=0. Use a UTC anchor for
    // the weekday lookup so the index doesn't shift by a day for
    // timezones west of UTC.
    const dow = new Date(Date.UTC(y, m-1, d)).getUTCDay();
    const ranges = availability.filter(a => a.day_of_week === dow);
    const blocks = [];
    ranges.forEach(r => {
      const [sh] = r.start_time.split(':').map(Number);
      const [eh] = r.end_time.split(':').map(Number);
      for (let h = sh; h < eh; h++) {
        const slotStart = window.Calendar.time.makeDate(y, m, d, h, 0, instructorTz);
        // Skip if in the past
        if (slotStart.getTime() < Date.now() + 60 * 60 * 1000) return;
        // Skip if a booking already exists at this hour
        const conflict = bookings.some(b => {
          const bStart = new Date(b.scheduled_at).getTime();
          const bEnd = bStart + (b.duration_minutes || 60) * 60000;
          const sStart = slotStart.getTime();
          const sEnd = sStart + 60 * 60000;
          return bStart < sEnd && bEnd > sStart;
        });
        // Skip if the time intersects any active exception block
        const blocked = window.Calendar.shape.isSlotBlocked && window.Calendar.shape.isSlotBlocked(exceptions, slotStart, 60);
        if (!conflict && !blocked) blocks.push(slotStart.toISOString());
      }
    });
    return blocks;
  }, [selectedDate, availability, bookings, exceptions, instructorTz]);

  const submit = async () => {
    if (!auth.user) { setError('Please sign in first.'); return; }
    if (!selectedHour) { setError('Pick a time slot to continue.'); return; }
    setBusy(true); setError(null);
    // Route through Bookings.db.bookAsStudent → student_book_lesson RPC.
    // The RPC enforces auth, the assignment check, the credit balance,
    // AND (since v54) the block-time check — closing the bypass where a
    // direct bookings.insert could land a row inside an availability
    // exception window.
    try {
      await window.Bookings.db.bookAsStudent({
        instructorId:    instructor.id,
        scheduledAt:     selectedHour,
        durationMinutes: 60,
        message:         message || null,
      });
      setSuccess('Booking requested! The instructor will confirm shortly.');
      setTimeout(() => { onBooked && onBooked(); }, 1200);
    } catch (e) {
      setError(e?.message || 'Booking failed. Please try again.');
    } finally {
      setBusy(false);
    }
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(15,20,40,0.55)', backdropFilter: 'blur(6px)',
      zIndex: 1000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20,
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 720, background: '#fff', borderRadius: 18, padding: 32,
        boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
        fontFamily: "'Plus Jakarta Sans', sans-serif",
        maxHeight: '90vh', overflowY: 'auto',
      }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 }}>
          <div>
            <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.14em', color: 'oklch(72% 0.17 80)', textTransform: 'uppercase', marginBottom: 6 }}>Book a trial</div>
            <h2 style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: 26, fontWeight: 600, color: 'oklch(22% 0.06 265)', lineHeight: 1.15 }}>
              with {window.MASTERY.maskTeacherName(instructor.full_name)}
            </h2>
            <div style={{ fontSize: 13, color: 'oklch(50% 0.03 265)', marginTop: 4 }}>
              60 min · ${instructor.rate} · Times shown in {studentTz}
            </div>
          </div>
          <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'oklch(55% 0.03 265)', fontSize: 24 }}>×</button>
        </div>

        {/* Week navigator */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: '18px 0 10px' }}>
          <button onClick={() => setWeekOffset(o => Math.max(0, o - 1))} disabled={weekOffset === 0}
            style={navBtn(weekOffset === 0)}>← Previous</button>
          <div style={{ fontWeight: 600, color: 'oklch(22% 0.06 265)', fontSize: 14 }}>
            {weekDays[0].toLocaleDateString(undefined, { month: 'short', day: 'numeric' })} – {weekDays[6].toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
          </div>
          <button onClick={() => setWeekOffset(o => Math.min(4, o + 1))} disabled={weekOffset >= 4}
            style={navBtn(weekOffset >= 4)}>Next →</button>
        </div>

        {/* Day picker */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 6, marginBottom: 18 }}>
          {weekDays.map(d => {
            const dateStr = isoDate(d);
            const isSelected = dateStr === selectedDate;
            const dow = d.getDay();
            const hasAvail = availability.some(a => a.day_of_week === dow);
            return (
              <button key={dateStr}
                onClick={() => { setSelectedDate(dateStr); setSelectedHour(null); }}
                disabled={!hasAvail}
                style={{
                  background: isSelected ? 'oklch(22% 0.06 265)' : (hasAvail ? '#fff' : 'oklch(96% 0.01 265)'),
                  color: isSelected ? '#fff' : (hasAvail ? 'oklch(22% 0.06 265)' : 'oklch(70% 0.02 265)'),
                  border: `1.5px solid ${isSelected ? 'oklch(22% 0.06 265)' : 'oklch(88% 0.01 265)'}`,
                  borderRadius: 10, padding: '10px 6px', cursor: hasAvail ? 'pointer' : 'not-allowed',
                  fontFamily: "'Plus Jakarta Sans', sans-serif",
                }}>
                <div style={{ fontSize: 11, fontWeight: 500, opacity: 0.7 }}>
                  {d.toLocaleDateString(undefined, { weekday: 'short' })}
                </div>
                <div style={{ fontSize: 16, fontWeight: 700, marginTop: 2 }}>
                  {d.getDate()}
                </div>
              </button>
            );
          })}
        </div>

        {/* Time slot picker */}
        <div style={{ background: 'oklch(98% 0.008 60)', borderRadius: 12, padding: 18, minHeight: 120 }}>
          {!selectedDate && <div style={{ textAlign: 'center', color: 'oklch(55% 0.03 265)', fontSize: 13, padding: '20px 0' }}>Pick a date to see times.</div>}
          {selectedDate && loadingSlots && <div style={{ textAlign: 'center', color: 'oklch(55% 0.03 265)', fontSize: 13 }}>Loading slots…</div>}
          {selectedDate && !loadingSlots && slotsForSelectedDate.length === 0 && (
            <div style={{ textAlign: 'center', color: 'oklch(55% 0.03 265)', fontSize: 13 }}>No open times on this day. Try another.</div>
          )}
          {selectedDate && slotsForSelectedDate.length > 0 && (
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(96px, 1fr))', gap: 8 }}>
              {slotsForSelectedDate.map(iso => {
                const dt = new Date(iso);
                const label = dt.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
                const isSelected = iso === selectedHour;
                return (
                  <button key={iso} onClick={() => setSelectedHour(iso)} style={{
                    background: isSelected ? 'oklch(22% 0.06 265)' : '#fff',
                    color: isSelected ? '#fff' : 'oklch(22% 0.06 265)',
                    border: `1.5px solid ${isSelected ? 'oklch(22% 0.06 265)' : 'oklch(88% 0.01 265)'}`,
                    borderRadius: 8, padding: '10px 0', cursor: 'pointer',
                    fontSize: 14, fontWeight: 600,
                    fontFamily: "'Plus Jakarta Sans', sans-serif",
                  }}>{label}</button>
                );
              })}
            </div>
          )}
        </div>

        {/* Message + confirm */}
        {selectedHour && (
          <div style={{ marginTop: 18 }}>
            <label style={{ display: 'block', fontSize: 12, fontWeight: 600, color: 'oklch(38% 0.04 265)', marginBottom: 6 }}>
              Note to {instructor.full_name.split(' ')[0]} (optional)
            </label>
            <textarea value={message} onChange={e => setMessage(e.target.value)}
              placeholder="I'm a beginner looking for a fun, no-pressure first lesson…"
              style={{
                width: '100%', minHeight: 80, padding: '10px 12px',
                border: '1.5px solid oklch(88% 0.01 265)', borderRadius: 10,
                fontFamily: "'Plus Jakarta Sans', sans-serif", fontSize: 14,
                resize: 'vertical', outline: 'none',
              }} />
          </div>
        )}

        {error && <div style={{ background: 'oklch(96% 0.03 25)', color: 'oklch(40% 0.15 25)', padding: '10px 14px', borderRadius: 8, fontSize: 13, marginTop: 12 }}>{error}</div>}
        {success && <div style={{ background: 'oklch(96% 0.04 158)', color: 'oklch(32% 0.1 155)', padding: '10px 14px', borderRadius: 8, fontSize: 13, marginTop: 12 }}>{success}</div>}

        <div style={{ display: 'flex', gap: 10, marginTop: 18 }}>
          <button onClick={onClose} style={{
            flex: 1, background: 'transparent', color: 'oklch(22% 0.06 265)',
            border: '1.5px solid oklch(82% 0.04 265)', borderRadius: 10, padding: '12px 0',
            fontWeight: 600, fontSize: 14, cursor: 'pointer',
            fontFamily: "'Plus Jakarta Sans', sans-serif",
          }}>Cancel</button>
          <button onClick={submit} disabled={!selectedHour || busy} style={{
            flex: 2, background: 'oklch(22% 0.06 265)', color: '#fff',
            border: 'none', borderRadius: 10, padding: '12px 0',
            fontWeight: 700, fontSize: 14,
            cursor: !selectedHour || busy ? 'not-allowed' : 'pointer',
            opacity: !selectedHour || busy ? 0.6 : 1,
            fontFamily: "'Plus Jakarta Sans', sans-serif",
          }}>
            {busy ? 'Booking…' : 'Confirm booking'}
          </button>
        </div>
      </div>
    </div>
  );
};

function startOfDay(d) { const x = new Date(d); x.setHours(0,0,0,0); return x; }
function addDays(d, n) { const x = new Date(d); x.setDate(x.getDate() + n); return x; }
function isoDate(d) { return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`; }
function navBtn(disabled) {
  return {
    background: 'none', border: '1.5px solid oklch(88% 0.01 265)',
    borderRadius: 8, padding: '7px 14px',
    fontSize: 13, fontWeight: 600,
    color: disabled ? 'oklch(75% 0.02 265)' : 'oklch(22% 0.06 265)',
    cursor: disabled ? 'not-allowed' : 'pointer',
    fontFamily: "'Plus Jakarta Sans', sans-serif",
  };
}

window.BookTrialModal = BookTrialModal;
window.Bookings = window.Bookings || {};
window.Bookings.ui = window.Bookings.ui || {};
window.Bookings.ui.BookTrial = BookTrialModal;
