/* global React, ReactDOM */
const { useState, useMemo, useEffect, useRef, useCallback } = React;

const AGENDA = window.AGENDA;

// Day 1 13:00–13:30 — each team runs its own kickoff
const KICKOFFS = [
  { id: "d1-kick-ent", start: "13:00", end: "13:30", track: "plenary", room: "Ent",
    title: "Enterprise kickoff", location: "Southwark Suite", tags: ["Enterprise"] },
  { id: "d1-kick-mm",  start: "13:00", end: "13:30", track: "plenary", room: "MM",
    title: "Mid-market kickoff", location: "Tower Suite", tags: ["Mid-Market"] },
  { id: "d1-kick-se",  start: "13:00", end: "13:30", track: "plenary", room: "SE",
    title: "SE kickoff", location: "Shard Suite", tags: ["SE"] },
];

// ── helpers ─────────────────────────────────────────────────────────────
const toMin = (t) => { const [h, m] = t.split(":").map(Number); return h * 60 + m; };
const fmtRange = (a, b) => `${a} – ${b}`;
const fmtDur = (a, b) => {
  const d = toMin(b) - toMin(a);
  if (d < 60) return `${d}m`;
  const h = Math.floor(d / 60), m = d % 60;
  return m ? `${h}h ${m}m` : `${h}h`;
};
const trackById = (id) => AGENDA.tracks.find(t => t.id === id) || AGENDA.tracks[0];
const roomById  = (id) => AGENDA.rooms.find(r => r.id === id);
const isNow = (s, sim) => {
  if (!sim || s.iso !== sim.iso) return false;
  const m = sim.minutes;
  return m >= toMin(s.start) && m < toMin(s.end);
};

// ── App ─────────────────────────────────────────────────────────────────
function App() {
  const [dayId, setDayId] = useState(AGENDA.days[0].id);
  const [hovered, setHovered] = useState(null);
  const [pinned, setPinned] = useState(null);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [trackFilter, setTrackFilter] = useState("all");

  const SIM_NOW = useMemo(() => {
    const now = new Date();
    const iso = now.toISOString().slice(0, 10);
    const minutes = now.getHours() * 60 + now.getMinutes();
    return { iso, minutes };
  }, []);

  const days = useMemo(() => {
    return AGENDA.days.map(d => {
      if (d.id !== "day1") return d;
      const filtered = d.sessions.filter(s =>
        s.id !== "d1-gen" && s.id !== "d1-kick-ent" && s.id !== "d1-kick-mm" && s.id !== "d1-kick-se"
      );
      return { ...d, sessions: [...KICKOFFS, ...filtered] };
    });
  }, []);

  const day = useMemo(() => days.find(d => d.id === dayId), [days, dayId]);
  const dayWithIso = useMemo(() => ({ ...day, sessions: day.sessions.map(s => ({ ...s, iso: day.iso })) }), [day]);

  const active = pinned || hovered;

  const selectSession = useCallback((s, opts = {}) => {
    if (opts.pin) { setPinned(s); setDrawerOpen(true); }
    else { setHovered(s); }
  }, []);

  const closeDrawer = useCallback(() => { setDrawerOpen(false); setPinned(null); }, []);

  useEffect(() => { setHovered(null); setPinned(null); }, [dayId]);

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") { closeDrawer(); setHovered(null); } };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [closeDrawer]);

  return (
    <div className="app">
      <Masthead />
      <Toolbar
        dayId={dayId} setDayId={setDayId}
        trackFilter={trackFilter} setTrackFilter={setTrackFilter}
      />
      <div className="stage">
        <ScheduleColumn
          day={dayWithIso}
          activeId={active?.id}
          onHover={(s) => selectSession(s)}
          onLeave={() => setHovered(null)}
          onSelect={(s) => selectSession(s, { pin: true })}
          simNow={SIM_NOW}
          trackFilter={trackFilter}
        />
        <DetailPane
          session={active}
          isOpen={drawerOpen}
          onClose={closeDrawer}
          simNow={SIM_NOW}
        />
      </div>
      <Footer />
    </div>
  );
}

// ── Wordmark ────────────────────────────────────────────────────────────
function Wordmark({ className }) {
  const [svg, setSvg] = useState(null);
  useEffect(() => {
    fetch("ht/assets/wordmark.svg")
      .then(r => r.text())
      .then(setSvg)
      .catch(() => setSvg(""));
  }, []);
  if (!svg) return <span className={className} style={{ display: "inline-block", width: 200, height: 36 }} />;
  return <span className={className} dangerouslySetInnerHTML={{ __html: svg }} />;
}

// ── Masthead ────────────────────────────────────────────────────────────
function Masthead() {
  const m = AGENDA.meta;
  return (
    <header className="masthead">
      <Wordmark className="logo-mark" />
      <div className="masthead-inner">
        <div>
          <div className="eyebrow">
            <span className="pulse" /> {m.hashtag}
          </div>
          <h1 className="ht-hero">
            EMEA <span className="accent">QBR</span>
          </h1>
          <p className="subtitle">{m.subtitle}</p>
        </div>
        <div className="masthead-meta">
          <div className="item">
            <div className="label">Dates</div>
            <div className="value">{m.dates}</div>
          </div>
          <div className="item">
            <div className="label">Venue</div>
            <div className="value">{m.venue}</div>
          </div>
          <div className="item">
            <div className="label">Timezone</div>
            <div className="value">{m.timezone}</div>
          </div>
        </div>
      </div>
    </header>
  );
}

// ── Toolbar ─────────────────────────────────────────────────────────────
function Toolbar({ dayId, setDayId, trackFilter, setTrackFilter }) {
  const visibleTracks = ["plenary", "qbr", "workshop", "activity", "social"];
  return (
    <div className="toolbar">
      <div className="day-tabs">
        {AGENDA.days.map(d => (
          <button
            key={d.id}
            className={`day-tab ${dayId === d.id ? "active" : ""}`}
            onClick={() => setDayId(d.id)}
          >
            <span className="num">{d.label}</span>
            <span className="date">{d.date}</span>
          </button>
        ))}
      </div>
      <div className="chips">
        <button
          className={`chip ${trackFilter === "all" ? "active" : ""}`}
          onClick={() => setTrackFilter("all")}
        >All</button>
        {visibleTracks.map(tid => {
          const t = trackById(tid);
          return (
            <button
              key={tid}
              className={`chip ${trackFilter === tid ? "active" : ""}`}
              onClick={() => setTrackFilter(trackFilter === tid ? "all" : tid)}
              style={{ "--track-color": `var(--tr-${tid})` }}
            >
              <span className="swatch" /> {t.name}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── Schedule (3-column grid) ────────────────────────────────────────────
const ROOM_ORDER = ["Ent", "MM", "SE"];
const ROW_HEIGHT = 9; // px per 5 min — 30min = 54px, 1h = 108px
const SLOT_MIN = 5;

function ScheduleColumn({ day, activeId, onHover, onLeave, onSelect, simNow, trackFilter }) {
  const containerRef = useRef(null);
  const [parentWidth, setParentWidth] = useState(900);
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;
    const ro = new ResizeObserver(entries => {
      setParentWidth(entries[0].contentRect.width);
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  const sessions = day.sessions;
  const minStart = Math.min(...sessions.map(s => toMin(s.start)));
  const maxEnd   = Math.max(...sessions.map(s => toMin(s.end)));
  const yStart = Math.floor(minStart / 60) * 60;
  const yEnd   = Math.ceil(maxEnd / 60) * 60;
  const totalSlots = (yEnd - yStart) / SLOT_MIN;
  const totalHeight = totalSlots * ROW_HEIGHT;

  const yFor = (t) => ((toMin(t) - yStart) / SLOT_MIN) * ROW_HEIGHT;

  const hours = [];
  for (let h = yStart; h <= yEnd; h += 60) hours.push(h);

  const byRoom = { Ent: [], MM: [], SE: [] };
  const allRoom = [];
  for (const s of sessions) {
    const rooms = s.rooms || (s.room ? [s.room] : []);
    if (rooms.length >= 3 || (rooms.length >= 2 && (s.track === "plenary" || s.track === "break" || s.track === "social" || s.track === "travel" || s.track === "activity"))) {
      allRoom.push({ ...s, rooms });
    } else {
      for (const r of rooms) {
        if (byRoom[r]) byRoom[r].push(s);
      }
    }
  }

  return (
    <section className="schedule">
      <header className="schedule-header">
        <div>
          <div className="title">{day.date} — <em>{day.theme}</em></div>
        </div>
        <div className="count">{day.sessions.length} sessions</div>
      </header>
      <div className="room-headers">
        <div className="gutter-spacer" />
        {ROOM_ORDER.map((rid, idx) => {
          const r = roomById(rid);
          return (
            <div className="room-col" key={rid}>
              <div className="name">{r.name}</div>
              <div className="suite">{r.suite}</div>
            </div>
          );
        })}
      </div>
      <div ref={containerRef} className="grid-canvas" style={{ height: totalHeight, "--row-h": `${ROW_HEIGHT}px` }}>
        {/* time gutter */}
        <div className="time-gutter">
          {hours.map(h => {
            const top = ((h - yStart) / SLOT_MIN) * ROW_HEIGHT;
            const hh = String(Math.floor(h / 60)).padStart(2, "0");
            const mm = String(h % 60).padStart(2, "0");
            return (
              <div key={h} className="hour" style={{ top }}>
                {hh}:{mm}
              </div>
            );
          })}
        </div>

        {/* now line */}
        {day.iso === simNow.iso && simNow.minutes >= yStart && simNow.minutes <= yEnd && (
          <div
            className="now-line"
            style={{ top: ((simNow.minutes - yStart) / SLOT_MIN) * ROW_HEIGHT, left: 64 }}
          >
            <span className="now-label">Now</span>
          </div>
        )}

        {/* per-room columns */}
        <div className="columns" style={{
          position: "absolute",
          top: 0, bottom: 0, left: 64, right: 0,
          display: "grid",
          gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
        }}>
          {ROOM_ORDER.map((rid, idx) => (
            <div className="col" key={rid}>
              {byRoom[rid].map(s => (
                <SessionBlock
                  key={s.id}
                  session={s}
                  top={yFor(s.start)}
                  height={yFor(s.end) - yFor(s.start)}
                  active={activeId === s.id}
                  muted={trackFilter !== "all" && s.track !== trackFilter && s.track !== "break"}
                  onHover={() => onHover(s)}
                  onLeave={onLeave}
                  onSelect={() => onSelect(s)}
                  live={isNow(s, simNow)}
                />
              ))}
            </div>
          ))}
        </div>

        {/* span-all sessions overlay */}
        {allRoom.map(s => {
          const cols = ROOM_ORDER.map(r => s.rooms.includes(r));
          const firstIdx = cols.indexOf(true);
          const lastIdx  = cols.lastIndexOf(true);
          return (
            <SessionBlockSpan
              key={s.id}
              session={s}
              top={yFor(s.start)}
              height={yFor(s.end) - yFor(s.start)}
              active={activeId === s.id}
              muted={trackFilter !== "all" && s.track !== trackFilter && s.track !== "break"}
              onHover={() => onHover(s)}
              onLeave={onLeave}
              onSelect={() => onSelect(s)}
              live={isNow(s, simNow)}
              firstCol={firstIdx}
              lastCol={lastIdx}
              parentWidth={parentWidth}
            />
          );
        })}
      </div>
    </section>
  );
}

function SessionBlock({ session, top, height, active, muted, onHover, onLeave, onSelect, live }) {
  const t = trackById(session.track);
  const isBreak = session.track === "break";
  const isTravel = session.track === "travel";
  const isGhost = session.ghost;
  const small = height < 50;

  return (
    <div
      className={[
        "block",
        isBreak && "is-break",
        isTravel && "is-travel",
        isGhost && "is-ghost",
        active && "is-active",
        muted && "is-muted",
      ].filter(Boolean).join(" ")}
      style={{
        top, height: height - 4,
        "--track-color": `var(--tr-${session.track})`,
      }}
      onMouseEnter={onHover}
      onMouseLeave={onLeave}
      onFocus={onHover}
      onClick={onSelect}
      tabIndex={0}
      role="button"
      aria-label={`${session.title}, ${session.start} to ${session.end}`}
    >
      {live && <span className="blk-now">Now</span>}
      {!live && session.tbd && <span className="blk-tbd">TBD</span>}
      {!isBreak && !small && (
        <div className="blk-track">{t.name}</div>
      )}
      <div className="blk-title">{session.title}</div>
      {!isBreak && !small && session.location && (
        <div className="blk-loc">{session.location}</div>
      )}
      {!isBreak && !small && (
        <div className="blk-time">{session.start}–{session.end}</div>
      )}
    </div>
  );
}

function SessionBlockSpan({ session, top, height, active, muted, onHover, onLeave, onSelect, live, firstCol, lastCol, parentWidth }) {
  const t = trackById(session.track);
  const isBreak = session.track === "break";
  const isTravel = session.track === "travel";
  const isSocial = session.track === "social";
  const small = height < 50;

  const roomAreaWidth = Math.max(0, parentWidth - 64);
  const colWidth = roomAreaWidth / 3;
  const leftPx = 64 + firstCol * colWidth + 6;
  const widthPx = (lastCol - firstCol + 1) * colWidth - 12;

  return (
    <div
      className={[
        "block", "span-all",
        isBreak && "is-break",
        isTravel && "is-travel",
        active && "is-active",
        muted && "is-muted",
      ].filter(Boolean).join(" ")}
      style={{
        position: "absolute",
        top,
        height: height - 4,
        left: leftPx,
        width: widthPx,
        "--track-color": `var(--tr-${session.track})`,
      }}
      onMouseEnter={onHover}
      onMouseLeave={onLeave}
      onFocus={onHover}
      onClick={onSelect}
      tabIndex={0}
      role="button"
      aria-label={`${session.title}, ${session.start} to ${session.end}`}
    >
      {live && <span className="blk-now">Now</span>}
      {!live && session.tbd && <span className="blk-tbd">TBD</span>}
      {!isBreak && !small && (
        <div className="blk-track">
          {t.name}{isSocial ? " · Dinner" : ""}
        </div>
      )}
      <div className="blk-title">{session.title}</div>
      {!isBreak && !small && session.location && (
        <div className="blk-loc">{session.location}</div>
      )}
      {!isBreak && !small && (
        <div className="blk-time">{session.start}–{session.end}</div>
      )}
    </div>
  );
}

// ── Detail Pane ────────────────────────────────────────────────────────
function DetailPane({ session, isOpen, onClose, simNow }) {
  if (!session) {
    return (
      <aside className="detail-pane is-empty">
        <div>
          <div className="detail-empty-icon">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round">
              <circle cx="12" cy="12" r="9" /><path d="M12 7v5l3 2" />
            </svg>
          </div>
          <div className="detail-empty">
            <h4>Hover any session to read the brief</h4>
            <p>Click to pin it open. Press <kbd>Esc</kbd> to dismiss.</p>
          </div>
        </div>
        <div className="hint">
          <kbd>Hover</kbd> Preview
          <span style={{ width: 8 }} />
          <kbd>Click</kbd> Pin
          <span style={{ width: 8 }} />
          <kbd>Esc</kbd> Close
        </div>
      </aside>
    );
  }

  const t = trackById(session.track);
  const rooms = session.rooms || (session.room ? [session.room] : []);
  const live = isNow(session, simNow);

  return (
    <aside
      className={`detail-pane ${isOpen ? "is-open" : ""}`}
      style={{ "--track-color": `var(--tr-${session.track})` }}
    >
      <button className="detail-close" onClick={onClose} aria-label="Close">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <path d="M6 6l12 12M18 6L6 18" />
        </svg>
      </button>

      <div className="detail-content">
        <div>
          <div className="detail-track">
            <span className="dot" /> {t.name}
            {rooms.length > 0 && rooms.map(r => {
              const room = roomById(r); if (!room) return null;
              return <span key={r} style={{ color: "var(--ink-3)", marginLeft: 8, letterSpacing: 0, textTransform: "none", fontFamily: "var(--ht-font-meta)" }}>· {room.name}</span>;
            })}
          </div>
          <h2 className="detail-title">{session.title}</h2>
          <div className="detail-when">
            <span>{fmtRange(session.start, session.end)}</span>
            <span className="duration">{fmtDur(session.start, session.end)}</span>
            {live && <span className="now-pill">Live now</span>}
          </div>
        </div>

        {session.summary && !session.outcomes && (
          <div className="detail-section">
            <p className="detail-summary">{session.summary}</p>
          </div>
        )}

        {session.outcomes && session.outcomes.length > 0 && (
          <div className="detail-section">
            <h5>By the end of this session, you'll be able to</h5>
            <ol className="outcomes">
              {session.outcomes.map(o => (
                <li key={o.n} className="outcome">
                  <span className="outcome-n">{o.n}</span>
                  <div className="outcome-body">
                    <div className="outcome-title">{o.title}</div>
                    <div className="outcome-text">{o.body}</div>
                  </div>
                </li>
              ))}
            </ol>
          </div>
        )}

        <div className="logistics">
          {session.location && (
            <div>
              <div className="label">Location</div>
              <div className="value">{session.location}</div>
            </div>
          )}
          <div>
            <div className="label">When</div>
            <div className="value">{fmtRange(session.start, session.end)}</div>
          </div>
          <div>
            <div className="label">Track</div>
            <div className="value">{t.name}</div>
          </div>
          <div>
            <div className="label">Duration</div>
            <div className="value">{fmtDur(session.start, session.end)}</div>
          </div>
        </div>

        {session.tags && session.tags.length > 0 && (
          <div className="detail-section">
            <h5>Tags</h5>
            <div className="tag-list">
              {session.tags.map(tag => <span key={tag} className="tag">{tag}</span>)}
            </div>
          </div>
        )}
      </div>
    </aside>
  );
}

function Footer() {
  return (
    <footer className="footer">
      <div>EMEA QBR · {AGENDA.meta.dates} · {AGENDA.meta.venue}</div>
      <div>
        {AGENDA.roster.length} attendees · {AGENDA.rooms.length} rooms · {AGENDA.days.reduce((a,d)=>a+d.sessions.length,0)} sessions
      </div>
    </footer>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
