/* Room Booking - "The Sanctuary" venue scheduler.
   Day + Week calendar, click-to-book, NeuroAI suggestions, and a public
   booking-page preview with a shareable link. Persists to localStorage.
   Exports: RoomBooking.                                                  */

const SANCTUARY_ROOMS = [
  { id: "hall",   name: "The Main Hall",   cap: 120, color: "#6366f1", amen: ["screen", "wifi", "coffee"], desc: "Flagship space for convenings, AGMs and showcases." },
  { id: "garden", name: "Garden Room",     cap: 30,  color: "#0d9488", amen: ["wifi", "coffee"],            desc: "Light-filled room opening onto the courtyard." },
  { id: "quiet",  name: "The Quiet Room",  cap: 8,   color: "#a855f7", amen: ["wifi"],                       desc: "Calm space for reflection and 1:1s." },
  { id: "studio", name: "The Studio",      cap: 24,  color: "#e11d48", amen: ["screen", "wifi"],             desc: "Workshop space with movable furniture." },
  { id: "podA",   name: "Meeting Pod A",   cap: 6,   color: "#d97706", amen: ["screen", "wifi"],             desc: "Glass meeting pod with display." },
  { id: "podB",   name: "Meeting Pod B",   cap: 4,   color: "#2563eb", amen: ["wifi"],                       desc: "Small huddle pod." },
];

const HOUR_START = 8, HOUR_END = 19;
const AMEN_LABEL = { screen: "Display", wifi: "Wi-Fi", coffee: "Refreshments" };
const ROOM = (rid) => SANCTUARY_ROOMS.find((r) => r.id === rid);

function fmtHour(h) {
  const hr = Math.floor(h), m = Math.round((h - hr) * 60);
  return `${String(hr).padStart(2, "0")}:${String(m).padStart(2, "0")}`;
}
function dayKey(d) { return d.toISOString().slice(0, 10); }
function addDays(d, n) { const x = new Date(d); x.setDate(x.getDate() + n); return x; }
function mondayOf(d) { const x = new Date(d); const wd = (x.getDay() + 6) % 7; return addDays(x, -wd); }

// seed bookings across the current working week so the calendar looks alive
function seedWeek(baseDate) {
  const mon = mondayOf(baseDate);
  const POOL = [
    ["hall", 9.5, 12, "Annual Grantee Summit - prep", "Maya Chen", "The Wellspring Fund"],
    ["garden", 10, 11.5, "Lighthouse check-in", "Eleanor Vance", "Lighthouse Learning Trust"],
    ["podA", 13, 14, "Beacon fellowship review", "David Okafor", "Beacon Research Lab"],
    ["studio", 14.5, 17, "Civic Futures workshop", "Anika Patel", "Civic Lab"],
    ["quiet", 11, 12, "1:1 - James Holloway", "Maya Chen", "OpenMinds Institute"],
    ["hall", 14, 16, "Forum Theatre gala planning", "Sarah Lindqvist", "The Forum Theatre"],
    ["podB", 9, 10, "Team stand-up", "David Okafor", "The Wellspring Fund"],
    ["garden", 15, 16.5, "Haven counselling review", "Henry Park", "Haven Therapy Network"],
    ["studio", 9.5, 11.5, "Grant panel - Education", "Maya Chen", "The Wellspring Fund"],
    ["podA", 15.5, 16.5, "Dispatch editorial sync", "Liam Fitzgerald", "The Dispatch Collective"],
    ["quiet", 14, 15, "Reflection - strategy", "Sarah Lindqvist", "The Wellspring Fund"],
    ["hall", 10, 12.5, "Open Science forum", "Priya Nair", "Beacon Research Lab"],
    ["podB", 13.5, 14.5, "Quantal intro call", "Marcus Webb", "Quantal Institute"],
    ["garden", 9, 10, "Coffee with Grace Abara", "Maya Chen", "Common Ground"],
    ["studio", 13, 15, "Impact reporting workshop", "David Okafor", "The Wellspring Fund"],
  ];
  const out = [];
  // distribute across Mon-Fri with deterministic spread
  for (let day = 0; day < 5; day++) {
    const dk = dayKey(addDays(mon, day));
    const count = [4, 3, 5, 3, 2][day];
    for (let i = 0; i < count; i++) {
      const p = POOL[(day * 3 + i) % POOL.length];
      out.push({ id: `seed-${day}-${i}`, room: p[0], day: dk, start: p[1], end: p[2], title: p[3], who: p[4], org: p[5] });
    }
  }
  return out;
}

function RoomBooking({ userName }) {
  const today = React.useMemo(() => { const d = new Date(); d.setHours(0, 0, 0, 0); return d; }, []);
  const [view, setView] = React.useState("day");
  const [date, setDate] = React.useState(today);
  const [bookings, setBookings] = React.useState(() => {
    try { const s = JSON.parse(localStorage.getItem("sanctuary_bookings_v2") || "null"); if (s && s.length) return s; } catch (e) {}
    return seedWeek(today);
  });
  const [modal, setModal] = React.useState(null);
  const [detail, setDetail] = React.useState(null);
  const [publicOpen, setPublicOpen] = React.useState(false);
  const [acceptPublic, setAcceptPublic] = useLocalState("sanctuary_public", true);
  const [toast, setToast] = React.useState(null);

  React.useEffect(() => { try { localStorage.setItem("sanctuary_bookings_v2", JSON.stringify(bookings)); } catch (e) {} }, [bookings]);
  React.useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 2600); return () => clearTimeout(t); }, [toast]);

  const span = HOUR_END - HOUR_START;
  const pct = (h) => ((h - HOUR_START) / span) * 100;
  const hours = []; for (let h = HOUR_START; h <= HOUR_END; h++) hours.push(h);

  const dk = dayKey(date);
  const dayBookings = bookings.filter((b) => b.day === dk);
  const roomBookings = (rid, key) => bookings.filter((b) => b.room === rid && b.day === (key || dk)).sort((a, b) => a.start - b.start);
  const slotFree = (rid, start, end, key) => !bookings.some((b) => b.room === rid && b.day === (key || dk) && start < b.end && end > b.start);

  const weekDays = React.useMemo(() => { const mon = mondayOf(date); return Array.from({ length: 5 }, (_, i) => addDays(mon, i)); }, [date]);

  const openNew = (rid, clickPct, key) => {
    let start = HOUR_START + Math.floor((clickPct / 100) * span * 2) / 2;
    start = Math.max(HOUR_START, Math.min(HOUR_END - 1, start));
    let end = start + 1;
    if (!slotFree(rid, start, end, key)) {
      const after = roomBookings(rid, key).find((b) => b.start >= start);
      if (after && after.start > start) end = Math.min(end, after.start);
      if (end - start < 0.5) { setToast({ kind: "warn", msg: "That slot's taken - pick a free gap." }); return; }
    }
    setModal({ room: rid, start, end, title: "", who: userName, day: key || dk });
  };

  const confirmBooking = () => {
    const m = modal;
    if (!m.title.trim()) { setToast({ kind: "warn", msg: "Add a title for the booking." }); return; }
    if (!slotFree(m.room, m.start, m.end, m.day)) { setToast({ kind: "warn", msg: "That time overlaps another booking." }); return; }
    const nb = { id: "b" + Date.now(), room: m.room, day: m.day, start: m.start, end: m.end, title: m.title.trim(), who: m.who, org: "The Wellspring Fund" };
    setBookings((bs) => [...bs, nb]);
    setModal(null);
    setToast({ kind: "good", msg: `Booked ${ROOM(m.room).name} · ${fmtHour(m.start)}-${fmtHour(m.end)}` });
  };
  const cancelBooking = (id) => { setBookings((bs) => bs.filter((b) => b.id !== id)); setDetail(null); setToast({ kind: "good", msg: "Booking cancelled." }); };

  const isToday = dk === dayKey(today);
  const dateLabel = date.toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long" });
  const weekLabel = `${weekDays[0].toLocaleDateString("en-GB", { day: "numeric", month: "short" })} - ${weekDays[4].toLocaleDateString("en-GB", { day: "numeric", month: "short" })}`;

  // ---- NeuroAI suggestions ----
  const suggestions = React.useMemo(() => {
    // quietest room today
    const load = SANCTUARY_ROOMS.map((r) => ({ r, busy: roomBookings(r.id).reduce((s, b) => s + (b.end - b.start), 0) }));
    load.sort((a, b) => a.busy - b.busy);
    const quiet = load[0];
    // first free 1h slot in the quiet room
    let slot = null;
    for (let h = HOUR_START; h <= HOUR_END - 1; h += 0.5) { if (slotFree(quiet.r.id, h, h + 1)) { slot = h; break; } }
    // busiest weekday
    const dayLoad = weekDays.map((d) => ({ d, n: bookings.filter((b) => b.day === dayKey(d)).length }));
    dayLoad.sort((a, b) => b.n - a.n);
    return { quiet: quiet.r, slot, busiest: dayLoad[0] };
  }, [bookings, dk, weekDays]);

  const weekUtil = Math.round((weekDays.reduce((s, d) => s + bookings.filter((b) => b.day === dayKey(d)).reduce((t, b) => t + (b.end - b.start), 0), 0) / (weekDays.length * SANCTUARY_ROOMS.length * span)) * 100);
  const publicUrl = "sanctuary.applied-neuro.org/book";

  return (
    <div style={{ position: "absolute", inset: 0, overflow: "auto", background: "var(--bg)" }}>
      <div style={{ width: "100%", margin: "0 auto", padding: "28px 32px 64px" }}>
        {/* header */}
        <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 16, flexWrap: "wrap", marginBottom: 18 }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
              <div style={{ width: 32, height: 32, borderRadius: 9, display: "grid", placeItems: "center", background: "var(--accent-soft)", color: "var(--accent)" }}><Icon name="door" size={18} /></div>
              <div className="t-eyebrow">The Sanctuary</div>
            </div>
            <div className="display" style={{ fontSize: 30 }}>Room Booking</div>
            <div style={{ fontSize: 14, color: "var(--text-muted)", marginTop: 4 }}>Reserve a space - click any free slot to book. {SANCTUARY_ROOMS.length} rooms · {weekUtil}% booked this week.</div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <button className="btn" onClick={() => setPublicOpen(true)}><Icon name="external" size={15} /> Public booking page</button>
            <Segmented value={view} onChange={setView} options={[{ value: "week", label: "Week", icon: "grid" }, { value: "day", label: "Day", icon: "calendar" }]} />
            <div style={{ display: "flex", alignItems: "center", gap: 4, background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--radius)", padding: 4 }}>
              <button className="btn btn-icon btn-ghost" onClick={() => setDate(addDays(date, view === "week" ? -7 : -1))}><Icon name="chevronLeft" size={16} /></button>
              <button className="btn btn-sm btn-ghost" onClick={() => setDate(today)} style={isToday ? { color: "var(--accent)", fontWeight: 650 } : {}}>Today</button>
              <button className="btn btn-icon btn-ghost" onClick={() => setDate(addDays(date, view === "week" ? 7 : 1))}><Icon name="chevronRight" size={16} /></button>
            </div>
          </div>
        </div>

        {/* NeuroAI suggestions */}
        <div style={{ marginBottom: 18 }}>
          <AINote title="Booking suggestions" onAction={() => suggestions.slot != null && openNew(suggestions.quiet.id, pct(suggestions.slot) + 1)} actionLabel={suggestions.slot != null ? `Hold ${ROOM(suggestions.quiet.id).name} ${fmtHour(suggestions.slot)}` : "All booked"}>
            <strong>{suggestions.quiet.name}</strong> is the quietest space today{suggestions.slot != null ? <span> - <strong>{fmtHour(suggestions.slot)}-{fmtHour(suggestions.slot + 1)}</strong> is free.</span> : "."} {suggestions.busiest && suggestions.busiest.n > 0 && <span>Heads up: <strong>{suggestions.busiest.d.toLocaleDateString("en-GB", { weekday: "long" })}</strong> is your busiest day - book early.</span>}
          </AINote>
        </div>

        {view === "day" ? (
          <DaySchedule {...{ dateLabel, isToday, dayBookings, hours, pct, HOUR_END, HOUR_START, today, dk, roomBookings, openNew, setDetail, span }} />
        ) : (
          <WeekGrid {...{ weekDays, bookings, today, openNew, setDetail, pct, span, hours, weekLabel }} />
        )}

        {/* room cards */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginTop: 18 }}>
          {SANCTUARY_ROOMS.map((room) => {
            const bk = roomBookings(room.id);
            return (
              <div key={room.id} className="card" style={{ padding: 15 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 9 }}>
                  <span style={{ width: 9, height: 9, borderRadius: 3, background: room.color, flex: "none" }} />
                  <span style={{ fontSize: 13.5, fontWeight: 650, flex: 1 }}>{room.name}</span>
                  <span className="badge"><Icon name="users" size={12} /> {room.cap}</span>
                </div>
                <div style={{ fontSize: 12.5, color: "var(--text-muted)", lineHeight: 1.5, marginBottom: 11, minHeight: 36 }}>{room.desc}</div>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                  <div style={{ display: "flex", gap: 9 }}>
                    {room.amen.map((a) => <span key={a} style={{ display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, color: "var(--text-faint)" }}><Icon name={a} size={13} />{AMEN_LABEL[a]}</span>)}
                  </div>
                  <span className="mono" style={{ fontSize: 11, color: bk.length ? "var(--accent)" : "var(--text-faint)" }}>{bk.length ? `${bk.length} today` : "Free today"}</span>
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {modal && <BookingModal modal={modal} setModal={setModal} room={ROOM(modal.room)} onConfirm={confirmBooking} slotFree={(r, s, e) => slotFree(r, s, e, modal.day)} span={span} />}
      {detail && (
        <Overlay onClose={() => setDetail(null)}>
          <div style={{ height: 4, background: ROOM(detail.room).color }} />
          <div style={{ padding: 22 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 14 }}>
              <span style={{ width: 10, height: 10, borderRadius: 3, background: ROOM(detail.room).color }} />
              <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--text-muted)" }}>{ROOM(detail.room).name}</span>
            </div>
            <div style={{ fontSize: 19, fontWeight: 700, letterSpacing: "-0.01em", marginBottom: 14 }}>{detail.title}</div>
            <FieldRow label="When" icon="clock"><span className="mono">{fmtHour(detail.start)}-{fmtHour(detail.end)}</span> · {new Date(detail.day).toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long" })}</FieldRow>
            <FieldRow label="Booked by" icon="user">{detail.who}</FieldRow>
            <FieldRow label="On behalf of" icon="building">{detail.org}</FieldRow>
            <div style={{ display: "flex", gap: 8, marginTop: 20 }}>
              <button className="btn btn-primary btn-sm" onClick={() => setDetail(null)}>Done</button>
              <button className="btn btn-sm" style={{ color: "var(--rose)" }} onClick={() => cancelBooking(detail.id)}><Icon name="x" size={14} /> Cancel booking</button>
            </div>
          </div>
        </Overlay>
      )}
      {publicOpen && <PublicBookingModal onClose={() => setPublicOpen(false)} url={publicUrl} accept={acceptPublic} setAccept={setAcceptPublic} bookings={bookings} today={today} slotFree={slotFree} setToast={setToast} />}

      {toast && (
        <div className="fade-up" style={{ position: "fixed", bottom: 24, left: "50%", transform: "translateX(-50%)", zIndex: 60, display: "flex", alignItems: "center", gap: 9, padding: "11px 16px", borderRadius: 11, background: "var(--surface)", border: "1px solid var(--border)", boxShadow: "var(--shadow-lg)", fontSize: 13.5, fontWeight: 550 }}>
          <Icon name={toast.kind === "good" ? "check" : "bell"} size={16} style={{ color: toast.kind === "good" ? "var(--good)" : "var(--warn)" }} />
          {toast.msg}
        </div>
      )}
    </div>
  );
}

/* ---- DAY schedule: ROOMS AS COLUMNS × time rows (easy to scan) ---- */
function DaySchedule({ dateLabel, isToday, dayBookings, hours, HOUR_END, HOUR_START, today, dk, roomBookings, openNew, setDetail, span }) {
  const hpx = 56, totalH = span * hpx;
  return (
    <React.Fragment>
      <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12 }}>
        <Icon name="calendar" size={16} style={{ color: "var(--text-muted)" }} />
        <span style={{ fontSize: 15, fontWeight: 650 }}>{dateLabel}</span>
        {isToday && <span className="badge" style={{ background: "var(--accent-soft)", color: "var(--accent)", borderColor: "transparent" }}>Today</span>}
        <span style={{ fontSize: 12.5, color: "var(--text-faint)" }}>· <span className="mono">{dayBookings.length}</span> bookings · {SANCTUARY_ROOMS.length} rooms</span>
      </div>
      <div className="card" style={{ overflow: "hidden", padding: 0 }}>
        <div style={{ overflowX: "auto" }}>
          <div style={{ minWidth: 820 }}>
            {/* room column headers */}
            <div style={{ display: "flex", borderBottom: "1px solid var(--border)", background: "var(--surface-2)" }}>
              <div style={{ width: 56, flex: "none" }} />
              {SANCTUARY_ROOMS.map((room) => (
                <div key={room.id} style={{ flex: 1, minWidth: 0, padding: "11px 12px", borderLeft: "1px solid var(--border)", borderTop: `3px solid ${room.color}` }}>
                  <div style={{ fontSize: 12.5, fontWeight: 700, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{room.name}</div>
                  <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 3 }}>
                    <span style={{ display: "inline-flex", alignItems: "center", gap: 3, fontSize: 11, color: "var(--text-faint)" }}><Icon name="users" size={11} />{room.cap}</span>
                    {room.amen.map((a) => <Icon key={a} name={a} size={11} style={{ color: "var(--text-faint)" }} title={AMEN_LABEL[a]} />)}
                    <span className="mono" style={{ marginLeft: "auto", fontSize: 10, color: roomBookings(room.id).length ? room.color : "var(--text-faint)" }}>{roomBookings(room.id).length || "free"}</span>
                  </div>
                </div>
              ))}
            </div>
            {/* time grid */}
            <div style={{ display: "flex", position: "relative" }}>
              <div style={{ width: 56, flex: "none" }}>
                {hours.slice(0, -1).map((h) => (
                  <div key={h} style={{ height: hpx, borderBottom: "1px solid var(--border)", display: "flex", justifyContent: "flex-end", paddingRight: 7, paddingTop: 3 }}>
                    <span className="mono" style={{ fontSize: 10, color: "var(--text-faint)" }}>{fmtHour(h)}</span>
                  </div>
                ))}
              </div>
              {SANCTUARY_ROOMS.map((room) => (
                <div key={room.id} onClick={(e) => { const r = e.currentTarget.getBoundingClientRect(); openNew(room.id, ((e.clientY - r.top) / totalH) * 100); }}
                  style={{ flex: 1, minWidth: 0, position: "relative", borderLeft: "1px solid var(--border)", height: totalH, cursor: "pointer" }}>
                  {hours.slice(0, -1).map((h, i) => <div key={h} style={{ position: "absolute", top: (i + 1) * hpx, left: 0, right: 0, height: 1, background: "var(--border)", opacity: 0.5 }} />)}
                  {roomBookings(room.id).map((b) => {
                    const top = (b.start - HOUR_START) * hpx, height = (b.end - b.start) * hpx;
                    return (
                      <button key={b.id} onClick={(e) => { e.stopPropagation(); setDetail(b); }}
                        style={{ position: "absolute", top: top + 1, height: Math.max(22, height - 2), left: 3, right: 3, background: `color-mix(in srgb, ${room.color} 18%, var(--surface))`, border: `1px solid ${room.color}`, borderLeft: `3px solid ${room.color}`, borderRadius: 7, padding: "5px 8px", cursor: "pointer", textAlign: "left", overflow: "hidden", color: "var(--text)" }}>
                        <div style={{ fontSize: 11.5, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", lineHeight: 1.2 }}>{b.title}</div>
                        <div className="mono" style={{ fontSize: 9.5, color: "var(--text-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{fmtHour(b.start)}-{fmtHour(b.end)} · {b.who}</div>
                      </button>
                    );
                  })}
                  {isToday && (() => { const now = new Date(); const h = now.getHours() + now.getMinutes() / 60; if (h < HOUR_START || h > HOUR_END) return null; return <span style={{ position: "absolute", top: (h - HOUR_START) * hpx, left: 0, right: 0, height: 2, background: "var(--rose)", opacity: 0.7, pointerEvents: "none" }} />; })()}
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </React.Fragment>
  );
}

/* ---- WEEK grid (day columns, time rows, agenda blocks) ---- */
function WeekGrid({ weekDays, bookings, today, setDetail, openNew, pct, span, hours, weekLabel }) {
  const ROWS = 64 * (span); // px height scale
  const hpx = 52; // px per hour
  const totalH = span * hpx;
  return (
    <React.Fragment>
      <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 12 }}>
        <Icon name="calendar" size={16} style={{ color: "var(--text-muted)" }} />
        <span style={{ fontSize: 15, fontWeight: 650 }}>Week of {weekLabel}</span>
      </div>
      <div className="card" style={{ overflow: "hidden", padding: 0 }}>
        {/* day headers */}
        <div style={{ display: "flex", borderBottom: "1px solid var(--border)", background: "var(--surface-2)" }}>
          <div style={{ width: 52, flex: "none" }} />
          {weekDays.map((d) => {
            const isT = dayKey(d) === dayKey(today);
            const n = bookings.filter((b) => b.day === dayKey(d)).length;
            return (
              <div key={dayKey(d)} style={{ flex: 1, padding: "10px 8px", textAlign: "center", borderLeft: "1px solid var(--border)" }}>
                <div style={{ fontSize: 12, fontWeight: 650, color: isT ? "var(--accent)" : "var(--text)" }}>{d.toLocaleDateString("en-GB", { weekday: "short" })}</div>
                <div style={{ fontSize: 11, color: "var(--text-muted)" }}>{d.getDate()} {d.toLocaleDateString("en-GB", { month: "short" })} · {n}</div>
              </div>
            );
          })}
        </div>
        {/* time grid */}
        <div style={{ display: "flex", position: "relative" }}>
          {/* hour gutter */}
          <div style={{ width: 52, flex: "none" }}>
            {hours.slice(0, -1).map((h) => (
              <div key={h} style={{ height: hpx, borderBottom: "1px solid var(--border)", display: "flex", justifyContent: "flex-end", paddingRight: 6, paddingTop: 2 }}>
                <span className="mono" style={{ fontSize: 10, color: "var(--text-faint)" }}>{fmtHour(h)}</span>
              </div>
            ))}
          </div>
          {weekDays.map((d) => {
            const key = dayKey(d);
            const dayBk = bookings.filter((b) => b.day === key).sort((a, b) => a.start - b.start);
            return (
              <div key={key} onClick={(e) => { const r = e.currentTarget.getBoundingClientRect(); const h = HOUR_START + ((e.clientY - r.top) / totalH) * span; openNew("podA", 0, key); }}
                style={{ flex: 1, position: "relative", borderLeft: "1px solid var(--border)", height: totalH, cursor: "pointer", background: dayKey(today) === key ? "color-mix(in srgb, var(--accent) 4%, transparent)" : "transparent" }}>
                {hours.slice(0, -1).map((h, i) => <div key={h} style={{ position: "absolute", top: i * hpx, left: 0, right: 0, height: 1, background: "var(--border)", opacity: 0.5 }} />)}
                {dayBk.map((b) => {
                  const room = ROOM(b.room);
                  const top = (b.start - HOUR_START) * hpx, height = (b.end - b.start) * hpx;
                  return (
                    <button key={b.id} onClick={(e) => { e.stopPropagation(); setDetail(b); }}
                      style={{ position: "absolute", top: top + 1, height: height - 2, left: 3, right: 3, background: `color-mix(in srgb, ${room.color} 18%, var(--surface))`, border: `1px solid ${room.color}`, borderLeft: `3px solid ${room.color}`, borderRadius: 6, padding: "3px 6px", cursor: "pointer", textAlign: "left", overflow: "hidden", color: "var(--text)" }}>
                      <div style={{ fontSize: 10.5, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", lineHeight: 1.2 }}>{b.title}</div>
                      <div className="mono" style={{ fontSize: 9, color: "var(--text-muted)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{fmtHour(b.start)} · {room.name}</div>
                    </button>
                  );
                })}
              </div>
            );
          })}
        </div>
      </div>
    </React.Fragment>
  );
}

function Overlay({ children, onClose, width = 420 }) {
  return (
    <React.Fragment>
      <div onClick={onClose} className="fade-in" style={{ position: "absolute", inset: 0, background: "rgba(10,12,18,0.4)", zIndex: 50 }} />
      <div className="fade-up" style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%,-50%)", width, maxWidth: "94vw", maxHeight: "90vh", overflow: "auto", zIndex: 51, background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--radius-lg)", boxShadow: "var(--shadow-lg)" }}>
        {children}
      </div>
    </React.Fragment>
  );
}

function BookingModal({ modal, setModal, room, onConfirm, slotFree, span }) {
  const times = []; for (let h = HOUR_START; h <= HOUR_END; h += 0.5) times.push(h);
  const set = (k, v) => setModal((m) => ({ ...m, [k]: v }));
  const endOpts = times.filter((t) => t > modal.start);
  return (
    <Overlay onClose={() => setModal(null)}>
      <div style={{ height: 4, background: room.color }} />
      <div style={{ padding: 22 }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
            <span style={{ width: 10, height: 10, borderRadius: 3, background: room.color }} />
            <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--text-muted)" }}>{room.name} · cap. {room.cap}</span>
          </div>
          <button className="btn btn-icon btn-ghost" onClick={() => setModal(null)}><Icon name="x" size={17} /></button>
        </div>
        <div style={{ fontSize: 18, fontWeight: 700, letterSpacing: "-0.01em", marginBottom: 4 }}>New booking</div>
        <div style={{ fontSize: 12.5, color: "var(--text-muted)", marginBottom: 16 }}>{new Date(modal.day).toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long" })}</div>
        <label className="field-label">Title</label>
        <input autoFocus className="input focusable" placeholder="e.g. Grantee check-in" value={modal.title} onChange={(e) => set("title", e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") onConfirm(); }} style={{ marginBottom: 12 }} />
        <div style={{ display: "flex", gap: 10, marginBottom: 12 }}>
          <div style={{ flex: 1 }}>
            <label className="field-label">From</label>
            <select className="input focusable" value={modal.start} onChange={(e) => { const s = Number(e.target.value); set("start", s); if (modal.end <= s) set("end", s + 0.5); }}>
              {times.filter((t) => t < HOUR_END).map((t) => <option key={t} value={t}>{fmtHour(t)}</option>)}
            </select>
          </div>
          <div style={{ flex: 1 }}>
            <label className="field-label">To</label>
            <select className="input focusable" value={modal.end} onChange={(e) => set("end", Number(e.target.value))}>
              {endOpts.map((t) => <option key={t} value={t}>{fmtHour(t)}</option>)}
            </select>
          </div>
        </div>
        <label className="field-label">Booked by</label>
        <input className="input focusable" value={modal.who} onChange={(e) => set("who", e.target.value)} style={{ marginBottom: 8 }} />
        {!slotFree(modal.room, modal.start, modal.end) && (
          <div style={{ display: "flex", alignItems: "center", gap: 7, fontSize: 12.5, color: "var(--rose)", marginBottom: 10 }}><Icon name="bell" size={14} /> This overlaps an existing booking.</div>
        )}
        <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
          <button className="btn btn-primary" style={{ flex: 1, justifyContent: "center" }} onClick={onConfirm}><Icon name="check" size={15} /> Confirm booking</button>
          <button className="btn" onClick={() => setModal(null)}>Cancel</button>
        </div>
      </div>
    </Overlay>
  );
}

/* ---- public booking page preview ---- */
function PublicBookingModal({ onClose, url, accept, setAccept, bookings, today, slotFree }) {
  const [copied, setCopied] = React.useState(false);
  const [catering, setCatering] = React.useState("none");
  const [attendees, setAttendees] = React.useState("");
  const copy = () => { try { navigator.clipboard.writeText("https://" + url); } catch (e) {} setCopied(true); setTimeout(() => setCopied(false), 1600); };
  const span = HOUR_END - HOUR_START;
  const dk = dayKey(today);
  // next 2 free slots per room for the public preview
  const avail = (rid) => { const out = []; for (let h = HOUR_START; h <= HOUR_END - 1 && out.length < 3; h++) { if (!bookings.some((b) => b.room === rid && b.day === dk && h < b.end && h + 1 > b.start)) out.push(h); } return out; };
  return (
    <Overlay onClose={onClose} width={560}>
      <div style={{ padding: "20px 22px", borderBottom: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 10 }}>
        <span style={{ width: 32, height: 32, flex: "none", borderRadius: 9, display: "grid", placeItems: "center", background: "var(--accent-soft)", color: "var(--accent)" }}><Icon name="external" size={17} /></span>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 15.5, fontWeight: 700 }}>Public booking page</div>
          <div style={{ fontSize: 12.5, color: "var(--text-muted)" }}>Share this link so partners can request a room.</div>
        </div>
        <button className="btn btn-icon btn-ghost" onClick={onClose}><Icon name="x" size={17} /></button>
      </div>
      <div style={{ padding: 22 }}>
        {/* shareable link */}
        <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "10px 12px", border: "1px solid var(--border)", borderRadius: 11, background: "var(--surface-2)", marginBottom: 14 }}>
          <Icon name="link" size={15} style={{ color: "var(--text-muted)", flex: "none" }} />
          <span className="mono" style={{ flex: 1, fontSize: 12.5, color: "var(--accent)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{url}</span>
          <button className="btn btn-sm" onClick={copy}>{copied ? <React.Fragment><Icon name="check" size={14} /> Copied</React.Fragment> : <React.Fragment><Icon name="receipt" size={14} /> Copy</React.Fragment>}</button>
        </div>
        {/* accept toggle */}
        <div style={{ display: "flex", alignItems: "center", gap: 11, padding: "11px 13px", border: "1px solid var(--border)", borderRadius: 11, marginBottom: 18 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 13, fontWeight: 600 }}>Accept public requests</div>
            <div style={{ fontSize: 11.5, color: "var(--text-muted)" }}>Requests land in your inbox to approve.</div>
          </div>
          <button onClick={() => setAccept(!accept)} className="focusable" style={{ width: 44, height: 26, flex: "none", borderRadius: 999, border: "none", cursor: "pointer", background: accept ? "var(--accent)" : "var(--surface-3)", position: "relative" }}>
            <span style={{ position: "absolute", top: 3, left: accept ? 21 : 3, width: 20, height: 20, borderRadius: 999, background: "#fff", transition: ".15s", boxShadow: "var(--shadow-sm)" }} />
          </button>
        </div>

        {/* preview frame */}
        <div className="t-eyebrow" style={{ marginBottom: 8 }}>Preview</div>
        <div style={{ border: "1px solid var(--border)", borderRadius: 14, overflow: "hidden", background: "var(--bg)" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 6, padding: "8px 12px", background: "var(--surface-2)", borderBottom: "1px solid var(--border)" }}>
            <span style={{ width: 8, height: 8, borderRadius: 999, background: "var(--border-strong)" }} /><span style={{ width: 8, height: 8, borderRadius: 999, background: "var(--border-strong)" }} /><span style={{ width: 8, height: 8, borderRadius: 999, background: "var(--border-strong)" }} />
            <span className="mono" style={{ fontSize: 10.5, color: "var(--text-faint)", marginLeft: 8 }}>{url}</span>
          </div>
          <div style={{ padding: 18 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 4 }}>
              <Logo size={22} />
              <div className="display" style={{ fontSize: 18 }}>Book a space at the Sanctuary</div>
            </div>
            <div style={{ fontSize: 12.5, color: "var(--text-muted)", marginBottom: 14 }}>Pick a room and an available time - we'll confirm by email.</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
              {SANCTUARY_ROOMS.slice(0, 4).map((room) => {
                const slots = avail(room.id);
                return (
                  <div key={room.id} style={{ display: "flex", alignItems: "center", gap: 11, padding: "10px 12px", border: "1px solid var(--border)", borderRadius: 10, background: "var(--surface)" }}>
                    <span style={{ width: 4, alignSelf: "stretch", borderRadius: 3, background: room.color, minHeight: 26 }} />
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 12.5, fontWeight: 600 }}>{room.name}</div>
                      <div style={{ fontSize: 11, color: "var(--text-faint)" }}>Up to {room.cap} · {room.amen.map((a) => AMEN_LABEL[a]).join(" · ")}</div>
                    </div>
                    <div style={{ display: "flex", gap: 5 }}>
                      {slots.length ? slots.map((h) => <span key={h} className="mono" style={{ fontSize: 10.5, padding: "4px 8px", borderRadius: 7, background: "var(--accent-soft)", color: "var(--accent)", fontWeight: 600 }}>{fmtHour(h)}</span>) : <span style={{ fontSize: 11, color: "var(--text-faint)" }}>Fully booked</span>}
                    </div>
                  </div>
                );
              })}
            </div>
            <div style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--border)", display: "flex", flexDirection: "column", gap: 10 }}>
              <div className="t-eyebrow">Your request</div>
              <div style={{ display: "flex", gap: 10 }}>
                <div style={{ flex: 1 }}>
                  <label className="field-label">Attendees</label>
                  <input className="input focusable" type="number" min="1" placeholder="e.g. 12" value={attendees} onChange={(e) => setAttendees(e.target.value)} style={{ height: 38 }} />
                </div>
                <div style={{ flex: 1.4 }}>
                  <label className="field-label">Catering required?</label>
                  <select className="input focusable" value={catering} onChange={(e) => setCatering(e.target.value)} style={{ height: 38 }}>
                    <option value="none">No catering needed</option>
                    <option value="tea">Tea &amp; coffee</option>
                    <option value="lunch">Working lunch</option>
                    <option value="full">Full catering</option>
                  </select>
                </div>
              </div>
              <div>
                <label className="field-label">Notes / dietary requirements</label>
                <input className="input focusable" placeholder="Allergies, AV needs, accessibility…" style={{ height: 38 }} />
              </div>
              {catering !== "none" && <div style={{ display: "flex", alignItems: "center", gap: 7, fontSize: 11.5, color: "var(--accent)" }}><Icon name="coffee" size={13} /> Catering team will be notified to confirm {catering === "tea" ? "tea & coffee" : catering === "lunch" ? "a working lunch" : "full catering"}.</div>}
            </div>
            <button className="btn btn-primary" style={{ width: "100%", justifyContent: "center", marginTop: 12 }} disabled><Icon name="calendar" size={15} /> Request booking</button>
          </div>
        </div>
        <div style={{ fontSize: 11.5, color: "var(--text-faint)", marginTop: 10, textAlign: "center" }}>This is a preview of what partners see at your public link.</div>
      </div>
    </Overlay>
  );
}

window.RoomBooking = RoomBooking;
