// src/features/calendar/ui/block-time-modal.jsx
//
// Shared "Block off this time" modal. One component drives the UX from
// all three sides (teacher / student / admin). Caller passes EXACTLY ONE
// owner identifier:
//   <BlockTimeModal instructorId="..." onClose={...} />
//   <BlockTimeModal studentId="..."    onClose={...} />
//
// The modal:
//   1. Lists existing future exceptions for that owner (with delete X).
//   2. Has a form to add a new range (date + start/end + optional reason).
//   3. Writes to public.availability_exceptions via window.supa.
//
// RLS in v37-schema gates writes: admin always; teacher for own
// instructor_id; student where student_id = auth.uid(). The component
// doesn't assume — it submits and reports what the server says.
//
// The pure-function isSlotBlocked() predicate used to live here; it's
// now in src/features/calendar/utils.js as window.Calendar.shape.isSlotBlocked.

const BTM_TODAY = () => {
  const d = new Date();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${d.getFullYear()}-${m}-${day}`;
};

const BTM_combine = (dateStr, hour, minute, tz) => {
  // Anchor the wall-clock {date, hour, minute} in the OWNER's profile
  // timezone, not the browser's. Same teacher blocking "Tue 10am" should
  // produce the same absolute instant regardless of whether they're at
  // home in NY or on vacation in Madrid — profile.timezone is the anchor
  // (default 'America/New_York' on the profiles table).
  const [y, m, d] = dateStr.split('-').map(Number);
  const zone = tz || window.Calendar.time.detect();
  const dt = window.Calendar.time.makeDate(y, m, d, hour, minute || 0, zone);
  return dt.toISOString();
};

const BTM_formatRange = (startIso, endIso, tz) => {
  // Render the absolute moment in the supplied IANA zone (the anchor the
  // block was written in), not the browser's. Bug fix 2026-05-21:
  // previously this read getFullYear/Month/Date + toLocaleDate/TimeString
  // with no timeZone option, so an owner-in-NY viewing from a browser-in-
  // Madrid saw "Tue 9 AM NY" displayed as "Tue 3 PM" with no labelling.
  const s = new Date(startIso), e = new Date(endIso);
  const zone = tz || window.Calendar.time.detect();
  const dOpts = { weekday: 'short', month: 'short', day: 'numeric', timeZone: zone };
  const tOpts = { hour: 'numeric', minute: '2-digit', timeZone: zone };
  const sParts = window.Calendar.time.partsIn(s, zone);
  const eParts = window.Calendar.time.partsIn(e, zone);
  const sameDay =
    sParts.year  === eParts.year  &&
    sParts.month === eParts.month &&
    sParts.day   === eParts.day;
  if (sameDay) {
    return `${s.toLocaleDateString(undefined, dOpts)} · ${s.toLocaleTimeString(undefined, tOpts)} – ${e.toLocaleTimeString(undefined, tOpts)}`;
  }
  return `${s.toLocaleDateString(undefined, dOpts)} ${s.toLocaleTimeString(undefined, tOpts)} → ${e.toLocaleDateString(undefined, dOpts)} ${e.toLocaleTimeString(undefined, tOpts)}`;
};

const BlockTimeModal = ({ instructorId, studentId, ownerName, ownerTimezone, onClose }) => {
  // Default the picker to the owner's profile timezone (the "correct" anchor for
  // their calendar), but let the user override it for THIS block — useful when
  // they want to enter times in a different zone for a one-off (e.g. traveling).
  const [selectedTz, setSelectedTz] = React.useState(
    ownerTimezone || window.Calendar.time.detect()
  );
  const ownerKind = instructorId ? 'instructor' : studentId ? 'student' : null;
  if (!ownerKind) {
    return (
      <div style={{ position:'fixed', inset:0, background:'rgba(0,0,0,0.4)', display:'flex', alignItems:'center', justifyContent:'center', zIndex:9000 }} onClick={onClose}>
        <div style={{ background:'#fff', padding:24, borderRadius:12 }}>
          BlockTimeModal needs either instructorId or studentId.
          <button onClick={onClose} style={{ marginLeft:14 }}>Close</button>
        </div>
      </div>
    );
  }

  const [exceptions, setExceptions] = React.useState(null);
  const [busy,  setBusy]  = React.useState(false);
  const [err,   setErr]   = React.useState('');
  const [okMsg, setOkMsg] = React.useState('');

  const [date,    setDate]    = React.useState(BTM_TODAY());
  const [allDay,  setAllDay]  = React.useState(true);
  const [startH,  setStartH]  = React.useState(9);
  const [endH,    setEndH]    = React.useState(17);
  const [reason,  setReason]  = React.useState('');

  const reload = React.useCallback(async () => {
    setErr('');
    try {
      const data = await window.Calendar.db.loadExceptions({ instructorId, studentId });
      setExceptions(data);
    } catch (e) {
      setErr(e?.message || String(e));
    }
  }, [instructorId, studentId]);

  React.useEffect(() => { reload(); }, [reload]);

  const submit = async () => {
    setErr(''); setOkMsg('');
    // View-As guard: if admin is impersonating, the studentId / instructorId
    // props point at the wrong user (auth.user.id is the admin, not the
    // impersonated user). Refuse the write — admin should use the admin
    // dashboard's Block button on the user's card instead.
    if (window.MASTERY && window.MASTERY.viewAs) {
      setErr("View-as is read-only. Go back to the admin dashboard and use the Block button on this user's card.");
      return;
    }
    if (!date) { setErr('Pick a date.'); return; }
    let startIso, endIso;
    if (allDay) {
      startIso = BTM_combine(date, 0, 0, selectedTz);
      const [y, m, d] = date.split('-').map(Number);
      const eDt = window.Calendar.time.makeDate(y, m, d, 24, 0, selectedTz);
      endIso = eDt.toISOString();
    } else {
      const s = Number(startH), e = Number(endH);
      if (!(e > s)) { setErr('End time must be after start time.'); return; }
      startIso = BTM_combine(date, s, 0, selectedTz);
      endIso   = BTM_combine(date, e, 0, selectedTz);
    }
    setBusy(true);
    const row = {
      start_at: startIso,
      end_at:   endIso,
      reason:   reason.trim() || null,
    };
    if (instructorId) row.instructor_id = instructorId;
    if (studentId)    row.student_id    = studentId;
    try {
      await window.Calendar.db.insertException(row);
    } catch (e) {
      setBusy(false);
      setErr(e?.message || String(e));
      return;
    }
    setBusy(false);
    setReason('');
    setOkMsg('Blocked.');
    setTimeout(() => setOkMsg(''), 1800);
    reload();
  };

  const remove = async (row) => {
    if (window.MASTERY && window.MASTERY.viewAs) {
      setErr("View-as is read-only. Go back to the admin dashboard to manage this user's blocks.");
      return;
    }
    // v88: warn the user that deleting an imported block locally will be
    // overwritten by the next Google sync — they should delete it on Google.
    const msg = row.is_imported
      ? 'This block came from your Google Calendar. Deleting it here will only remove it until the next sync — delete the event in Google Calendar to remove it permanently. Continue?'
      : 'Remove this block?';
    if (!window.confirm(msg)) return;
    setBusy(true);
    try {
      await window.Calendar.db.deleteException(row.id);
    } catch (e) {
      setBusy(false);
      setErr(e?.message || String(e));
      return;
    }
    setBusy(false);
    reload();
  };

  const fld = { width:'100%', padding:'10px 12px', 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(56% 0.04 265)', marginBottom:5 };

  const ownerLabel = ownerName
    ? `${ownerKind === 'instructor' ? 'Teacher' : 'Student'} · ${ownerName}`
    : (ownerKind === 'instructor' ? 'Teacher' : 'Student');

  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:16, padding:'26px 28px', width:560, 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={{ fontFamily:"'Cormorant Garamond', serif", fontSize:22, fontWeight:600, color:'oklch(18% 0.03 265)', marginBottom:4 }}>Block off time</div>
        <div style={{ fontSize:12, color:'oklch(58% 0.03 265)', marginBottom:18 }}>
          {ownerLabel}. Blocked ranges are skipped when picking times in the booking calendar.
        </div>

        <div style={{ marginBottom:20 }}>
          <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(50% 0.04 265)', marginBottom:8 }}>Upcoming blocks</div>
          {exceptions === null ? (
            <div style={{ fontSize:13, color:'oklch(60% 0.03 265)', padding:'10px 0' }}>Loading…</div>
          ) : exceptions.length === 0 ? (
            <div style={{ fontSize:13, color:'oklch(60% 0.03 265)', padding:'10px 0', fontStyle:'italic' }}>None — nothing is blocked.</div>
          ) : (
            <div style={{ display:'flex', flexDirection:'column', gap:8 }}>
              {exceptions.map(r => {
                // Render each row in `selectedTz` — the anchor zone the
                // form is currently set to (defaults to the owner's
                // profile.timezone). The DB doesn't persist the anchor
                // per-block, so this is the best signal we have; the
                // label below makes the assumption visible.
                const rowTz = selectedTz;
                // v88: imported rows show the Google event title in place
                // of the user-entered reason, with a subdued "from Google"
                // tag so the instructor knows where it came from.
                const imported = !!r.is_imported;
                const displayTitle = imported
                  ? (r.imported_title || '(untitled Google event)')
                  : r.reason;
                const rowBg = imported ? 'oklch(96% 0.02 230)' : 'oklch(98% 0.005 60)';
                const rowBorder = imported ? '1px solid oklch(88% 0.03 230)' : '1px solid oklch(92% 0.01 265)';
                return (
                  <div key={r.id} style={{ display:'flex', alignItems:'center', gap:12, padding:'10px 12px', background:rowBg, border:rowBorder, borderRadius:8 }}>
                    <div style={{ flex:1, minWidth:0 }}>
                      <div style={{ fontSize:13, fontWeight:600, color:'oklch(22% 0.06 265)' }}>{BTM_formatRange(r.start_at, r.end_at, rowTz)}</div>
                      <div style={{ fontSize:11, color:'oklch(58% 0.03 265)', marginTop:2 }}>
                        {imported ? <span style={{ color:'oklch(40% 0.14 235)', fontWeight:600 }}>from Google · </span> : null}
                        stored TZ: {rowTz}
                      </div>
                      {displayTitle && <div style={{ fontSize:12, color:'oklch(54% 0.04 265)', marginTop:2 }}>{displayTitle}</div>}
                    </div>
                    <button onClick={() => remove(r)} disabled={busy} style={{ background:'oklch(96% 0.04 25)', color:'oklch(40% 0.18 25)', border:'1px solid oklch(88% 0.05 25)', borderRadius:6, padding:'5px 10px', fontSize:11, fontWeight:600, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
                      Remove
                    </button>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        <div style={{ borderTop:'1px solid oklch(92% 0.01 265)', paddingTop:16 }}>
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:10, marginBottom:10, flexWrap:'wrap' }}>
            <div style={{ fontSize:11, fontWeight:700, textTransform:'uppercase', letterSpacing:'0.06em', color:'oklch(50% 0.04 265)' }}>Add a new block</div>
            <div style={{ display:'flex', alignItems:'center', gap:6 }}>
              <span style={{ fontSize:11, color:'oklch(58% 0.03 265)' }}>Times shown in</span>
              <window.Calendar.ui.TimezoneBadge value={selectedTz} onChange={setSelectedTz} compact />
            </div>
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12, marginBottom:12 }}>
            <div style={{ gridColumn:'1/-1' }}>
              <label style={lbl}>Date</label>
              <input type="date" value={date} min={BTM_TODAY()} onChange={e => setDate(e.target.value)} style={fld} />
            </div>
          </div>
          <label style={{ display:'flex', alignItems:'center', gap:8, fontSize:13, color:'oklch(40% 0.04 265)', cursor:'pointer', marginBottom:12 }}>
            <input type="checkbox" checked={allDay} onChange={e => setAllDay(e.target.checked)} style={{ accentColor:'oklch(22% 0.06 265)' }} />
            All day
          </label>
          {!allDay && (
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12, marginBottom:12 }}>
              <div>
                <label style={lbl}>From</label>
                <select value={startH} onChange={e => setStartH(Number(e.target.value))} style={fld}>
                  {Array.from({length:24},(_,h)=>h).map(h => (
                    <option key={h} value={h}>{h===0?'12 AM':h<12?`${h} AM`:h===12?'12 PM':`${h-12} PM`}</option>
                  ))}
                </select>
              </div>
              <div>
                <label style={lbl}>To</label>
                <select value={endH} onChange={e => setEndH(Number(e.target.value))} style={fld}>
                  {Array.from({length:25},(_,h)=>h).map(h => (
                    <option key={h} value={h}>{h===0?'12 AM':h<12?`${h} AM`:h===12?'12 PM':h===24?'12 AM (next)':`${h-12} PM`}</option>
                  ))}
                </select>
              </div>
            </div>
          )}
          <div style={{ marginBottom:14 }}>
            <label style={lbl}>Reason (optional)</label>
            <input value={reason} onChange={e => setReason(e.target.value)} placeholder="Doctor appointment, vacation, etc." style={fld} />
          </div>

          {err   && <div style={{ fontSize:13, color:'oklch(40% 0.15 25)', marginBottom:12, padding:'9px 12px', background:'oklch(96% 0.06 25)', borderRadius:7 }}>{err}</div>}
          {okMsg && <div style={{ fontSize:13, color:'oklch(28% 0.13 150)', marginBottom:12, fontWeight:600 }}>{okMsg}</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:600, fontSize:14, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", opacity:busy?0.7:1 }}>
              {busy ? 'Saving…' : 'Block this time'}
            </button>
            <button onClick={onClose} style={{ padding:'12px 18px', 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" }}>Done</button>
          </div>
        </div>
      </div>
    </div>
  );
};

// Public: under Calendar.ui.* (canonical) + the old bare global
// (backward-compat for callers not yet migrated).
window.Calendar.ui = window.Calendar.ui || {};
window.Calendar.ui.BlockTimeModal = BlockTimeModal;
window.BlockTimeModal             = BlockTimeModal;
