/* global React, Icon, money, Dial, PageSkeleton, sbx, useRcCourses,
   CourseEditor, RcEditor, TierPill, AlertDot, PARTNER_TIERS,
   saveCourseLocation, saveCourseBasics, placeFromAddress, addressQuery, DADE,
   OnboardingPanel, useOnboarding, useRcTeeCourseIds, teesFor, onboardingProgress, isOnboarding,
   ProgressBar, addBasemap, StickySave */
// The admin course page — one course, everything about it, behind tabs.
//
// "Full course" and "SBX course" are genuinely two different records: the
// real 18-hole layout with tees, rating and slope lives in rc_courses, and
// the Sandbox-9 pitch-and-putt setup lives in courses. They were reached
// from two separate buttons on a list; here they are two tabs on one page,
// which is what they always were conceptually.
//
// The editors themselves are the existing ones, mounted with `embedded` so
// they drop their own back button. Nothing about how a course is saved
// changes — this is a container, not a rewrite.

// Location used to be its own tab; it now lives inside Overview (below the
// stats/partnership cards) since "how is this course doing" and "where is
// it" are both things you'd check on the same first glance, not two clicks.
const COURSE_TABS = [
  { id: 'overview',   label: 'Overview',       hint: 'How this course is doing, and where it is' },
  { id: 'onboarding', label: 'Onboarding',     hint: 'Everything this course still needs, and the way to go live' },
  { id: 'sbx',        label: 'SBX Course',     hint: 'Sandbox-9 layout, pricing & status' },
  { id: 'full',       label: 'Regular Course', hint: 'Real tees, yardage, rating & slope' },
];

function TabBar({ tabs, value, onChange }) {
  return (
    <div role="tablist" style={{
      display: 'flex', gap: 2, padding: 3, borderRadius: 'var(--r-sm)',
      background: 'var(--surface-sunken)', border: '1px solid var(--line)',
      overflowX: 'auto', maxWidth: '100%',
    }} className="no-scrollbar">
      {tabs.map(t => {
        const on = t.id === value;
        return (
          <button key={t.id} role="tab" aria-selected={on} onClick={() => onChange(t.id)}
            title={t.hint}
            style={{
              padding: '8px 15px', borderRadius: 'calc(var(--r-sm) - 2px)', border: 'none',
              cursor: 'pointer', font: 'inherit', fontSize: 13, fontWeight: on ? 700 : 600,
              whiteSpace: 'nowrap',
              background: on ? 'var(--cream)' : 'transparent',
              color: on ? 'var(--forest)' : 'var(--ink-muted)',
              transition: 'background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease)',
            }}>
            {t.label}
          </button>
        );
      })}
    </div>
  );
}

// ─── Location section (lives under Overview) ──────────────────────────
// City/state/address plus a coordinate, all in one place — they used to be
// split across the SBX Course tab (city/state/address, plain text) and a
// separate Location tab (lat/lng, on a map), which meant "where is this
// course" had two different answers to maintain in two different places.
// Address-first ordering here matches the coordinate picker below it: look
// it up from the address already on file, drag the pin, or type the numbers.
function LocationSection({ course, onSaved }) {
  const [city, setCity] = React.useState(course.city || '');
  const [state, setState] = React.useState(course.state || '');
  const [address, setAddress] = React.useState(course.address || '');
  const [basicsBusy, setBasicsBusy] = React.useState(false);
  const [basicsErr, setBasicsErr] = React.useState('');
  const [basicsMsg, setBasicsMsg] = React.useState('');

  // Opening a different course re-renders this component rather than
  // remounting it, so without this the previous course's address would
  // stay in the boxes — and worse, could be saved onto the new one.
  React.useEffect(() => {
    setCity(course.city || ''); setState(course.state || ''); setAddress(course.address || '');
    setBasicsErr(''); setBasicsMsg('');
  }, [course.id]); // eslint-disable-line react-hooks/exhaustive-deps

  const dirty = (city || '') !== (course.city || '')
    || (state || '') !== (course.state || '')
    || (address || '') !== (course.address || '');

  async function saveBasics() {
    setBasicsBusy(true); setBasicsErr(''); setBasicsMsg('');
    try {
      await saveCourseBasics(course.id, { city, state, address });
      setBasicsMsg('Saved.');
      onSaved();
    } catch (e) { setBasicsErr(e.message || 'Could not save.'); }
    setBasicsBusy(false);
  }

  const holder = React.useRef(null);
  const mapRef = React.useRef(null);
  const markerRef = React.useRef(null);
  const [lat, setLat] = React.useState(course.lat != null ? String(course.lat) : '');
  const [lng, setLng] = React.useState(course.lng != null ? String(course.lng) : '');
  const [busy, setBusy] = React.useState('');
  const [err, setErr] = React.useState('');
  const [note, setNote] = React.useState('');
  const hasLeaflet = typeof window.L !== 'undefined';
  // Built from what's in the boxes, not from the saved row — the address
  // fields sit directly above the lookup button now, so the hint has to
  // describe what you're about to look up rather than what was last saved.
  const query = addressQuery({ ...course, city, state, address });

  const place = React.useCallback((la, ln) => {
    setLat(String(la)); setLng(String(ln));
    if (mapRef.current) {
      mapRef.current.setView([la, ln], Math.max(mapRef.current.getZoom(), 15));
      if (markerRef.current) markerRef.current.setLatLng([la, ln]);
    }
  }, []);

  React.useEffect(() => {
    if (!hasLeaflet || !holder.current || mapRef.current) return undefined;
    const L = window.L;
    const start = [
      course.lat != null ? Number(course.lat) : DADE.lat,
      course.lng != null ? Number(course.lng) : DADE.lng,
    ];
    const map = L.map(holder.current, { zoomControl: false })
      .setView(start, course.lat != null ? 15 : 10);
    const basemap = addBasemap(map, { maxZoom: 19 });
    L.control.zoom({ position: 'bottomright' }).addTo(map);

    const icon = L.divIcon({
      className: 'sbx-pin-wrap',
      html: '<div class="sbx-pin"><span class="sbx-pin__disc"><img src="assets/monogram-forest.svg" alt=""/></span></div>',
      iconSize: [34, 34], iconAnchor: [17, 34],
    });
    const marker = L.marker(start, { icon, draggable: true }).addTo(map);
    marker.on('dragend', () => {
      const p = marker.getLatLng();
      setLat(p.lat.toFixed(6)); setLng(p.lng.toFixed(6)); setNote(''); setErr('');
    });
    map.on('click', (e) => {
      marker.setLatLng(e.latlng);
      setLat(e.latlng.lat.toFixed(6)); setLng(e.latlng.lng.toFixed(6)); setNote(''); setErr('');
    });
    mapRef.current = map; markerRef.current = marker;
    return () => { basemap.destroy(); map.remove(); mapRef.current = null; markerRef.current = null; };
  }, [hasLeaflet, course.lat, course.lng]);

  async function fromAddress() {
    setBusy('geo'); setErr(''); setNote(''); setBasicsErr(''); setBasicsMsg('');
    try {
      // Persist any unsaved edits first, then geocode those same values.
      // Skipping this would look up the OLD address while the new one is
      // on screen — a trap that only appeared once these two controls were
      // put in the same card.
      if (dirty) await saveCourseBasics(course.id, { city, state, address });
      const hit = await placeFromAddress({ ...course, city, state, address });
      place(hit.lat, hit.lng);
      setNote(`Matched "${hit.label}". Drag the pin if it's not exactly right.`);
      onSaved();
    } catch (e) { setErr(e.message); }
    setBusy('');
  }

  async function save() {
    setBusy('save'); setErr(''); setNote('');
    try {
      const la = Number(lat), ln = Number(lng);
      if (!Number.isFinite(la) || !Number.isFinite(ln)) throw new Error('Latitude and longitude both need to be numbers.');
      if (la < -90 || la > 90) throw new Error('Latitude has to be between -90 and 90.');
      if (ln < -180 || ln > 180) throw new Error('Longitude has to be between -180 and 180.');
      await saveCourseLocation(course.id, la, ln);
      setNote('Location saved.');
      onSaved();
    } catch (e) { setErr(e.message); }
    setBusy('');
  }

  async function clear() {
    setBusy('clear'); setErr(''); setNote('');
    try {
      await saveCourseLocation(course.id, null, null);
      setLat(''); setLng('');
      setNote('Location cleared. This course is back in the unplaced list.');
      onSaved();
    } catch (e) { setErr(e.message); }
    setBusy('');
  }

  const inputStyle = { width: 130, padding: '8px 10px', fontSize: 13, fontFamily: 'var(--font-mono)' };

  return (<>
    {/* Only the address gets a bar. The coordinate save sits beside the two
        boxes it writes, and those change on every drag of the pin — a bar
        tracking them would spend the whole session flickering in and out. */}
    <StickySave dirty={dirty} saving={basicsBusy} error={basicsErr}
      message={!dirty && basicsMsg ? basicsMsg : ''}
      label="Save address" note="the pin does not move"
      onSave={saveBasics}
      onDiscard={() => {
        setCity(course.city || ''); setState(course.state || '');
        setAddress(course.address || ''); setBasicsErr('');
      }}/>
    <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(260px, 340px)', gap: 16, alignItems: 'start' }}>
      <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
        {hasLeaflet
          ? <div ref={holder} className="sbx-map" style={{ height: 'min(58vh, 480px)', width: '100%' }}/>
          : <div style={{ padding: 40, textAlign: 'center', color: 'var(--ink-muted)' }}>The map library didn&rsquo;t load.</div>}
      </div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div className="card" style={{ padding: 18 }}>
          <div className="eyebrow" style={{ marginBottom: 12 }}>Address</div>
          {/* Not <Row>/<Field> here: those split evenly with a 140px floor
              each, which in this ~340px column forces City and State onto
              separate lines. A two-letter state never needed half the width
              of a city name anyway. */}
          <div style={{ display: 'flex', gap: 10, marginBottom: 12 }}>
            <div style={{ flex: '1 1 auto', minWidth: 0 }}>
              <label className="label">City</label>
              <input className="input" value={city} onChange={e => setCity(e.target.value)} placeholder="Miami"/>
            </div>
            <div style={{ flex: '0 0 76px' }}>
              <label className="label">State</label>
              <input className="input" value={state} onChange={e => setState(e.target.value)} placeholder="FL"
                maxLength={2} style={{ textTransform: 'uppercase' }}/>
            </div>
          </div>
          <div style={{ marginBottom: 12 }}>
            <label className="label">Street</label>
            <input className="input" value={address} onChange={e => setAddress(e.target.value)} placeholder="1802 NW 37th Ave"/>
          </div>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <button className="btn btn-forest" onClick={fromAddress} disabled={!query || !!busy} style={{ flex: 1, minWidth: 130 }}>
              {busy === 'geo' ? 'Looking it up…' : 'Place from address'}
            </button>
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-muted)', marginTop: 10, lineHeight: 1.5 }}>
            {query
              ? <>Drops the pin on <span style={{ color: 'var(--ink-soft)' }}>{query}</span>{dirty ? ', saving these edits first' : ''}.</>
              : 'Fill in an address and this will place the pin for you.'}
          </div>
        </div>

        <div className="card" style={{ padding: 18 }}>
          <div className="eyebrow">Coordinates</div>
          <div style={{ fontSize: 12.5, color: 'var(--ink-muted)', marginTop: 7, lineHeight: 1.5 }}>
            Click or drag on the map, or type them in.
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: 12, flexWrap: 'wrap' }}>
            <label style={{ flex: 1, minWidth: 110 }}>
              <span className="eyebrow" style={{ fontSize: 9, display: 'block', marginBottom: 4 }}>Latitude</span>
              <input className="input" value={lat} onChange={e => setLat(e.target.value)} placeholder="25.761700" style={inputStyle}/>
            </label>
            <label style={{ flex: 1, minWidth: 110 }}>
              <span className="eyebrow" style={{ fontSize: 9, display: 'block', marginBottom: 4 }}>Longitude</span>
              <input className="input" value={lng} onChange={e => setLng(e.target.value)} placeholder="-80.191800" style={inputStyle}/>
            </label>
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
            <button className="btn btn-forest" onClick={save} disabled={!!busy || !lat || !lng} style={{ flex: 1 }}>
              {busy === 'save' ? 'Saving…' : 'Save location'}
            </button>
            {course.lat != null && (
              <button className="btn btn-ghost" onClick={clear} disabled={!!busy}>Clear</button>
            )}
          </div>
        </div>

        {(err || note) && (
          <div className="card" style={{ padding: '13px 16px', borderLeft: `3px solid ${err ? 'var(--loss)' : 'var(--cream)'}` }}>
            <div style={{ fontSize: 12.5, color: 'var(--ink-soft)', lineHeight: 1.5 }}>{err || note}</div>
          </div>
        )}
      </div>
    </div>
  </>);
}

// ─── Overview tab ─────────────────────────────────────────────────────
function OverviewTab({ course, onChanged }) {
  const s = course.stat || {};
  const cell = { padding: '13px 16px', borderRight: '1px solid var(--line)' };
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div className="card" style={{ padding: 0, display: 'flex', flexWrap: 'wrap' }}>
        <div style={{ ...cell, flex: '1 1 150px' }}>
          <div className="eyebrow">Revenue MTD</div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--paper)', marginTop: 3 }}>{money(s.grossMtd || 0)}</div>
        </div>
        <div style={{ ...cell, flex: '1 1 150px' }}>
          <div className="eyebrow">Sandbox Take</div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--paper)', marginTop: 3 }}>{money(s.takeMtd || 0)}</div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-muted)' }}>{course.sandbox_take_pct != null ? course.sandbox_take_pct : 15}% split</div>
        </div>
        <div style={{ ...cell, flex: '1 1 150px' }}>
          <div className="eyebrow">Rounds Today</div>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 24, color: 'var(--paper)', marginTop: 3 }}>{s.roundsToday || 0}</div>
        </div>
        <div style={{ ...cell, flex: '0 0 auto', borderRight: 'none', display: 'flex', alignItems: 'center' }}>
          <Dial value={s.utilization != null ? s.utilization : 0} size={64} label="Utilization"
            color="var(--paper)" track="rgba(234,226,206,0.16)"/>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 16 }}>
        <div className="card" style={{ padding: 20 }}>
          <div className="eyebrow">Partnership</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 12 }}>
            <TierPill tier={course.tier} founding={course.founding}/>
            <span style={{ fontSize: 13, color: 'var(--ink-muted)' }}>
              {(PARTNER_TIERS[course.tier] || {}).hint}
            </span>
          </div>
          <dl style={{ margin: '16px 0 0', display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '8px 16px', fontSize: 13 }}>
            <dt style={{ color: 'var(--ink-muted)' }}>Revenue split</dt>
            <dd style={{ margin: 0, fontFamily: 'var(--font-mono)' }}>{course.sandbox_take_pct != null ? course.sandbox_take_pct : 15}%</dd>
            <dt style={{ color: 'var(--ink-muted)' }}>Founding rate</dt>
            <dd style={{ margin: 0 }}>{course.founding ? 'Locked' : 'No'}</dd>
            <dt style={{ color: 'var(--ink-muted)' }}>Contract</dt>
            <dd style={{ margin: 0 }}>{course.contract_start || 'Not recorded'}{course.contract_end ? ` → ${course.contract_end}` : ''}</dd>
            <dt style={{ color: 'var(--ink-muted)' }}>Status</dt>
            <dd style={{ margin: 0 }}>{String(course.status || 'unknown').replace('_', ' ')}</dd>
          </dl>
        </div>

        <div className="card" style={{ padding: 20 }}>
          <div className="eyebrow">Needs Attention</div>
          {!course.alerts.length ? (
            <div style={{ fontSize: 13.5, color: 'var(--ink-muted)', marginTop: 12, lineHeight: 1.5 }}>
              Nothing flagged for this course.
            </div>
          ) : (
            <div style={{ marginTop: 10 }}>
              {course.alerts.map((a, i) => (
                <div key={a.code} style={{
                  display: 'flex', alignItems: 'center', gap: 10, padding: '10px 0',
                  borderTop: i ? '1px solid var(--line)' : 'none',
                }}>
                  <AlertDot severity={a.severity}/>
                  <span style={{ fontSize: 13, color: 'var(--ink-soft)', flex: 1 }}>{a.text}</span>
                  {a.code === 'no-location' && (
                    <button className="btn btn-ghost"
                      onClick={() => document.getElementById('course-location')?.scrollIntoView({ behavior: 'smooth', block: 'start' })}
                      style={{ padding: '4px 10px', fontSize: 12 }}>Fix</button>
                  )}
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      <div id="course-location">
        <div className="eyebrow" style={{ marginBottom: 10 }}>Location</div>
        <LocationSection course={course} onSaved={onChanged}/>
      </div>
    </div>
  );
}

// ─── AdminCourseDetail ────────────────────────────────────────────────
// ─── CourseBanner ─────────────────────────────────────────────────────
// A wide strip of the course at the top of its page. Short on purpose: it
// is there to say "this is the place", not to be the page. The name sits on
// it so the picture carries the heading rather than pushing it down the
// screen, and a wash underneath keeps that text readable over whatever the
// photograph happens to be doing.
function CourseBanner({ src, course }) {
  const [failed, setFailed] = React.useState(false);
  if (failed) return null;   // a broken image is worse than no banner
  return (
    <div className="card" style={{
      padding: 0, overflow: 'hidden', position: 'relative',
      height: 'clamp(120px, 18vw, 190px)', marginBottom: 16,
    }}>
      <img src={src} alt="" onError={() => setFailed(true)}
        style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'linear-gradient(to top, rgba(14,28,19,0.86) 0%, rgba(14,28,19,0.15) 55%, rgba(14,28,19,0.05) 100%)',
      }}/>
      <div style={{ position: 'absolute', left: 20, right: 20, bottom: 14 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 'clamp(20px, 2.4vw, 28px)', color: 'var(--paper)', lineHeight: 1.05 }}>
          {course.short_name || course.name}
        </div>
        <div style={{
          fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'rgba(234,226,206,0.8)',
          marginTop: 4, textTransform: 'uppercase', letterSpacing: '0.06em',
        }}>
          {[course.city, course.state].filter(Boolean).join(', ') || 'Location not set'}
        </div>
      </div>
    </div>
  );
}

// Shown in place of Overview for a course we hold a scorecard for and have
// not onboarded. There is no revenue, no split and no contract to report, so
// the tab says what it is and offers the one thing you would want to do.
function NotOnboarded({ course, rc, onOnboard }) {
  const tees = rc && rc.holes ? `${rc.holes} holes` : null;
  return (
    <div className="card" style={{ padding: 28 }}>
      <div className="eyebrow">Not on Sandbox</div>
      <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, color: 'var(--paper)', margin: '8px 0 6px' }}>
        We hold a scorecard for this course, nothing more
      </div>
      <div style={{ fontSize: 13.5, color: 'var(--ink-muted)', maxWidth: 560, lineHeight: 1.6 }}>
        {[course.city, course.state].filter(Boolean).join(', ') || 'No location on file'}
        {tees ? ` · ${tees}` : ''}
        . Its real tees and yardages are on the Regular Course tab. Onboarding
        it creates the Sandbox record — pricing, split, and the Sandbox 9 laid
        over it — and it starts as a draft until the readiness gate passes.
      </div>
      <div style={{ display: 'flex', gap: 8, marginTop: 20 }}>
        <button className="btn btn-forest" onClick={onOnboard}>Onboard to Sandbox</button>
      </div>
    </div>
  );
}

// The percentage, wherever you are on the course. Its own small loader rather
// than lifting state up: the header should not wait on a tab it may never open.
function HeaderProgress({ course, rc }) {
  const [loaded] = useOnboarding(course.id);
  const [rcTeeIds] = useRcTeeCourseIds();
  if (!loaded) return null;
  const p = onboardingProgress({ course, rc, rcTees: teesFor(rc, rcTeeIds), ...loaded });
  if (!isOnboarding(course, p.pct)) return null;
  return (
    <div style={{ minWidth: 150, maxWidth: 240, flex: '0 1 200px' }}
      title={`${p.done} of ${p.total} onboarding steps done`}>
      <div style={{ fontSize: 10.5, color: 'var(--ink-muted)', fontFamily: 'var(--font-mono)', marginBottom: 3 }}>
        Onboarding {p.pct}%
      </div>
      <ProgressBar pct={p.pct} height={5}/>
    </div>
  );
}

function AdminCourseDetail({ course, onBack, onChanged, onOnboarded, adminId }) {
  // A course reached from the list may have no `courses` row at all — it is
  // a scorecard we hold and have not onboarded. Everything downstream keys
  // off that: a null id means there is nothing to show revenue, partnership
  // or a readiness gate for, and the Sandbox tab is a create form.
  const onboarded = !!course.id;
  // Opened from "start onboarding", or opened mid-onboarding: land on the
  // work rather than on a page of zeroes.
  const [tab, setTab] = React.useState(
    course.onboarding ? 'onboarding' : onboarded ? 'overview' : 'full');
  const [rcCourses] = useRcCourses();

  // The full-course record is a different table with no foreign key to the
  // SBX one, so they are matched by name — the same join the courses list
  // has always done. The list has usually done it already; take its answer
  // when it has one rather than waiting on a second fetch.
  const rc = React.useMemo(() => {
    if (course.rc !== undefined) return course.rc;
    if (!rcCourses) return undefined;
    const key = (course.name || '').trim().toLowerCase();
    return rcCourses.find(c => (c.name || '').trim().toLowerCase() === key) || null;
  }, [rcCourses, course.rc, course.name]);

  // The banner is the *secondary* picture — render_img, the drawn flyover —
  // deliberately not the hero. The hero is already doing its job on the card
  // that got you here; repeating it makes the detail page look like the tile
  // you just clicked. Falls back to the hero only when there is no second
  // image, since a banner is better than a gap.
  const banner = course.render_img || course.hero_img || null;

  return (
    <div style={{ maxWidth: 1240, margin: '0 auto' }}>
      {banner && <CourseBanner src={banner} course={course}/>}

      <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', marginBottom: 16 }}>
        <button className="btn btn-ghost" onClick={onBack} style={{ padding: '6px 12px' }}>← Network</button>
        <div style={{ flex: 1, minWidth: 180 }}>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, color: 'var(--paper)', lineHeight: 1.1 }}>
            {course.name}
          </div>
          <div style={{ fontSize: 12.5, color: 'var(--ink-muted)', marginTop: 2 }}>
            {[course.city, course.state].filter(Boolean).join(', ') || 'No location on file'}
            {course.address ? ` · ${course.address}` : ''}
          </div>
        </div>
        {onboarded && course.status !== 'active' && <HeaderProgress course={course} rc={rc}/>}
        {onboarded
          ? <TierPill tier={course.tier} founding={course.founding}/>
          : (
            // No tier to show — an empty pill would just read as a fault.
            <span className="pill-mono" title="Not onboarded to Sandbox" style={{
              fontSize: 9.5, padding: '3px 8px',
              background: 'transparent', color: 'var(--ink-muted)',
              border: '1px dashed var(--ink-faint)',
            }}>Not on Sandbox</span>
          )}
      </div>

      <TabBar tabs={COURSE_TABS} value={tab} onChange={setTab}/>

      <div key={tab} className="rise-in" style={{ marginTop: 18 }}>
        {tab === 'overview' && (
          onboarded
            ? <OverviewTab course={course} onChanged={onChanged}/>
            : <NotOnboarded course={course} rc={rc} onOnboard={() => setTab('sbx')}/>
        )}

        {tab === 'onboarding' && (
          onboarded
            ? <OnboardingPanel course={course} rc={rc} adminId={adminId} onChanged={onChanged}/>
            : <NotOnboarded course={course} rc={rc} onOnboard={() => setTab('sbx')}/>
        )}

        {tab === 'sbx' && (
          <CourseEditor embedded
            course={onboarded ? course : null}
            prefill={onboarded ? null : { name: course.name, city: course.city, state: course.state }}
            onClose={() => setTab(onboarded ? 'overview' : 'full')}
            onSaved={(savedId) => {
              onChanged();
              if (!onboarded && savedId && onOnboarded) onOnboarded(savedId, { name: course.name, city: course.city, state: course.state });
              setTab('overview');
            }}/>
        )}

        {tab === 'full' && (
          rc === undefined ? <PageSkeleton/> : (
            <RcEditor embedded course={rc}
              prefill={rc ? null : { name: course.name, city: course.city, state: course.state }}
              onClose={() => setTab('overview')}
              onSaved={() => { onChanged(); setTab('overview'); }}/>
          )
        )}
      </div>
    </div>
  );
}

Object.assign(window, { AdminCourseDetail, TabBar, COURSE_TABS, LocationSection, OverviewTab });
