/* ============================================================
   Tectus — Book a Demo scheduler (front-end flow).
   Timezone-aware date/time picker + form + validation +
   loading / success / error / retry states. Submits to a
   configurable backend endpoint (window.TECTUS_BOOKING_ENDPOINT);
   backend logic, Google Calendar + email are in
   backend/booking-backend.js. Internal notices → demo@tectusapp.com
   ============================================================ */
const { Button: ScButton, Field: ScField, Input: ScInput, Select: ScSelect, Textarea: ScTextarea } = window.TectusDesignSystem_c42b34;

const DEMO_TYPES = ['Platform walkthrough', 'Client onboarding (Tectus)', 'Vendor onboarding (Tectus GO)', 'Enterprise / multi-site', 'Other'];
/* Business hours offered, in US Eastern time (24h) */
const SLOT_HOURS = [9, 10, 11, 13, 14, 15, 16];
const BOOKING_KEY = 'tectus_booked_slots_v1';
const DEMO_TZ = 'America/Denver'; /* all demo times are Denver / Mountain Time */

/* ---- timezone helpers (fixed to US Eastern) ---- */
function localTZ() { return DEMO_TZ; }
/* offset (minutes) of DEMO_TZ at a given instant */
function tzOffsetMin(date) {
  try {
    const dtf = new Intl.DateTimeFormat('en-US', { timeZone: DEMO_TZ, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' });
    const p = dtf.formatToParts(date).reduce((a, x) => { a[x.type] = x.value; return a; }, {});
    const asUTC = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
    return Math.round((asUTC - date.getTime()) / 60000);
  } catch (e) { return -300; }
}
function tzAbbr() {
  try {
    const parts = new Intl.DateTimeFormat('en-US', { timeZone: DEMO_TZ, timeZoneName: 'short' }).formatToParts(new Date());
    return (parts.find((x) => x.type === 'timeZoneName') || {}).value || 'ET';
  } catch (e) { return 'ET'; }
}
function fmtHour(h) {
  const am = h < 12; const hr = h % 12 === 0 ? 12 : h % 12;
  return `${hr}:00 ${am ? 'AM' : 'PM'}`;
}
function dayKey(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }
function slotId(d, h) { return `${dayKey(d)}T${String(h).padStart(2, '0')}`; }
/* next N selectable weekdays starting tomorrow */
function upcomingDays(n) {
  const out = []; const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + 1);
  while (out.length < n) { const day = d.getDay(); if (day !== 0 && day !== 6) out.push(new Date(d)); d.setDate(d.getDate() + 1); }
  return out;
}
function readBooked() {
  try { return new Set(JSON.parse(localStorage.getItem(BOOKING_KEY) || '[]')); } catch (e) { return new Set(); }
}
function writeBooked(set) {
  try { localStorage.setItem(BOOKING_KEY, JSON.stringify([...set])); } catch (e) {}
}
/* ISO datetime for a day+hour interpreted as US Eastern wall-clock */
function isoWithOffset(d, h) {
  const off = tzOffsetMin(new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), h))); // ET offset (e.g. -240/-300)
  const sign = off >= 0 ? '+' : '-'; const a = Math.abs(off);
  const pad = (n) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(h)}:00:00${sign}${pad(Math.floor(a / 60))}:${pad(a % 60)}`;
}

function validEmail(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v); }

function startOfMonth(d) { return new Date(d.getFullYear(), d.getMonth(), 1); }
function sameDay(a, b) { return a && b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate(); }
function isSelectable(d) {
  const t = new Date(); t.setHours(0, 0, 0, 0);
  const wd = d.getDay();
  return d > t && wd !== 0 && wd !== 6; // future weekdays only
}

function DemoScheduler() {
  const today = React.useMemo(() => { const t = new Date(); t.setHours(0, 0, 0, 0); return t; }, []);
  const firstPick = React.useMemo(() => upcomingDays(1)[0], []);
  const [booked, setBooked] = useState(() => readBooked());
  const [viewMonth, setViewMonth] = useState(() => startOfMonth(firstPick));
  const [selDate, setSelDate] = useState(firstPick);
  const [hour, setHour] = useState(null);
  const [form, setForm] = useState({ name: '', email: '', company: '', phone: '', type: DEMO_TYPES[0], notes: '' });
  const [errors, setErrors] = useState({});
  const [status, setStatus] = useState('idle'); // idle | submitting | success | error
  const [errMsg, setErrMsg] = useState('');
  const [result, setResult] = useState(null);
  const submitting = useRef(false);
  const tz = localTZ(); const abbr = tzAbbr();
  const day = selDate;

  const set = (k, v) => { setForm((f) => ({ ...f, [k]: v })); if (errors[k]) setErrors((e) => ({ ...e, [k]: null })); };

  function validate() {
    const e = {};
    if (!form.name.trim()) e.name = 'Enter your full name';
    if (!form.email.trim()) e.email = 'Enter your work email'; else if (!validEmail(form.email)) e.email = 'Enter a valid email';
    if (!form.company.trim()) e.company = 'Enter your company';
    if (hour == null) e.slot = 'Select a date and time';
    setErrors(e);
    return Object.keys(e).length === 0;
  }

  async function submit(e) {
    if (e) e.preventDefault();
    if (submitting.current) return;            // guard double-click
    if (!validate()) return;
    const id = slotId(day, hour);
    // client-side double-booking guard (backend rechecks authoritatively)
    const fresh = readBooked();
    if (fresh.has(id)) {
      setBooked(fresh); setHour(null);
      setErrors((x) => ({ ...x, slot: 'That time was just taken — please choose another.' }));
      return;
    }
    submitting.current = true; setStatus('submitting'); setErrMsg('');

    const payload = {
      name: form.name.trim(), email: form.email.trim(), company: form.company.trim(),
      phone: form.phone.trim(), demoType: form.type, notes: form.notes.trim(),
      slotId: id, startISO: isoWithOffset(day, hour), endISO: isoWithOffset(day, hour + 1),
      timezone: tz, timezoneLabel: abbr, source: 'website:book-a-demo',
      internalEmail: 'demo@tectusapp.com',
    };

    try {
      const endpoint = window.TECTUS_BOOKING_ENDPOINT || '/api/book-demo';
      let ok = false, data = {};
      const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
      data = await res.json().catch(() => ({}));
      if (res.status === 409) {
        const nb = readBooked(); nb.add(id); writeBooked(nb); setBooked(nb); setHour(null);
        setStatus('idle'); submitting.current = false;
        setErrors((x) => ({ ...x, slot: 'That time was just booked. Please pick another slot.' }));
        return;
      }
      ok = res.ok && data && data.status !== 'error';
      if (!ok) throw new Error((data && data.message) || 'We could not complete the booking.');

      const nb = readBooked(); nb.add(id); writeBooked(nb); setBooked(nb);
      setResult({ ...payload, ...data });
      setStatus('success');
    } catch (err) {
      setErrMsg(err.message || 'Something went wrong. Please try again.');
      setStatus('error');
    } finally {
      submitting.current = false;
    }
  }

  function reset() {
    setStatus('idle'); setHour(null); setResult(null); setErrMsg('');
    setForm({ name: '', email: '', company: '', phone: '', type: DEMO_TYPES[0], notes: '' });
  }

  /* ---------- SUCCESS ---------- */
  if (status === 'success' && result) {
    const start = new Date(result.startISO);
    const dOpt = { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric', timeZone: result.timezone };
    const tOpt = { hour: 'numeric', minute: '2-digit', timeZone: result.timezone };
    const dateStr = start.toLocaleDateString('en-US', dOpt);
    const timeStr = `${start.toLocaleTimeString('en-US', tOpt)} – ${new Date(result.endISO).toLocaleTimeString('en-US', tOpt)}`;
    return (
      <div style={{ maxWidth: 640, margin: '0 auto', background: 'var(--color-surface)', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-xl)', padding: 40, boxShadow: 'var(--shadow-lg)' }}>
        <div style={{ textAlign: 'center' }}>
          <span style={{ width: 68, height: 68, borderRadius: '50%', background: 'var(--color-success-soft)', color: 'var(--color-success)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginBottom: 22 }}><Icon name="calendar-check" size={32} /></span>
          <h2 style={{ fontFamily: 'var(--font-display)', fontSize: 28, fontWeight: 700, margin: '0 0 10px' }}>Your demo is booked</h2>
          <p style={{ fontSize: 15.5, color: 'var(--color-text-muted)', lineHeight: 1.6, maxWidth: 420, margin: '0 auto' }}>A calendar invite and confirmation email are on the way to <strong style={{ color: 'var(--color-text)' }}>{result.email}</strong>.</p>
        </div>
        <div style={{ marginTop: 26, background: 'var(--color-bg)', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-lg)', padding: 24 }}>
          {[
            ['calendar', 'Date', dateStr],
            ['clock', 'Time', `${timeStr}`],
            ['globe', 'Timezone', `US Eastern${result.timezoneLabel ? ' · ' + result.timezoneLabel : ''}`],
            ['briefcase', 'Demo type', result.demoType],
            ['building-2', 'Company', result.company],
          ].map(([ic, k, v]) => (
            <div key={k} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '11px 0', borderBottom: '1px solid var(--color-divider)' }}>
              <Icon name={ic} size={17} color="var(--color-primary)" style={{ flex: '0 0 auto' }} />
              <span style={{ fontSize: 12.5, color: 'var(--color-text-faint)', width: 92, flex: '0 0 auto' }}>{k}</span>
              <span style={{ fontSize: 14.5, color: 'var(--color-text)', fontWeight: 500 }}>{v}</span>
            </div>
          ))}
          <div style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '11px 0' }}>
            <Icon name="hash" size={17} color="var(--color-primary)" style={{ flex: '0 0 auto' }} />
            <span style={{ fontSize: 12.5, color: 'var(--color-text-faint)', width: 92, flex: '0 0 auto' }}>Reference</span>
            <span style={{ fontSize: 13, color: 'var(--color-text-muted)', fontFamily: 'var(--font-mono)' }}>{result.bookingId || result.slotId}</span>
          </div>
        </div>
        <div style={{ marginTop: 22 }}>
          <div style={{ fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--color-text-faint)', fontWeight: 700, marginBottom: 12 }}>What happens next</div>
          <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 10 }}>
            {['Check your inbox for the calendar invite — accept it to confirm.', 'A Tectus advisor will join at the scheduled time.', 'Need to reschedule? Reply to the confirmation email.'].map((t) => (
              <li key={t} style={{ display: 'flex', gap: 10, alignItems: 'flex-start', fontSize: 14, color: 'var(--color-text-muted)', lineHeight: 1.5 }}><Icon name="check" size={16} color="var(--color-primary)" style={{ marginTop: 1, flex: '0 0 auto' }} />{t}</li>
            ))}
          </ul>
        </div>
        <div style={{ marginTop: 24, display: 'flex', gap: 10, justifyContent: 'center', flexWrap: 'wrap' }}>
          <a href="#/"><ScButton variant="secondary">Back to home</ScButton></a>
          <ScButton variant="primary" onClick={reset} iconLeft={<Icon name="plus" size={15} />}>Book another</ScButton>
        </div>
      </div>
    );
  }

  /* ---------- SCHEDULER ---------- */
  const slotErr = errors.slot;
  const monthLabel = viewMonth.toLocaleDateString('en-US', { month: 'long' });
  const yearLabel = viewMonth.getFullYear();
  // build calendar cells (leading blanks + days of month)
  const firstDow = viewMonth.getDay();
  const daysInMonth = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < firstDow; i++) cells.push(null);
  for (let dnum = 1; dnum <= daysInMonth; dnum++) cells.push(new Date(viewMonth.getFullYear(), viewMonth.getMonth(), dnum));
  const canPrev = startOfMonth(viewMonth) > startOfMonth(today);
  const dowLabels = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];

  return (
    <div style={{ maxWidth: 1000, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 20 }}>
      {/* calendar + time list */}
      <div className="tt-sched" style={{ display: 'grid', gridTemplateColumns: '1.35fr 1fr', gap: 0, background: 'var(--color-surface)', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-xl)', overflow: 'hidden', alignItems: 'stretch' }}>
        {/* calendar */}
        <div style={{ minWidth: 0, padding: 28, borderRight: '1px solid var(--color-divider)' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18 }}>
            <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 20, fontWeight: 700, margin: 0 }}>{monthLabel} <span style={{ color: 'var(--color-text-faint)', fontWeight: 500 }}>{yearLabel}</span></h3>
            <div style={{ display: 'flex', gap: 6 }}>
              <button type="button" aria-label="Previous month" disabled={!canPrev} onClick={() => canPrev && setViewMonth(new Date(viewMonth.getFullYear(), viewMonth.getMonth() - 1, 1))}
                style={{ width: 34, height: 34, borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border)', background: 'var(--color-bg)', color: canPrev ? 'var(--color-text)' : 'var(--color-text-faint)', cursor: canPrev ? 'pointer' : 'not-allowed', opacity: canPrev ? 1 : 0.4, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="chevron-left" size={17} /></button>
              <button type="button" aria-label="Next month" onClick={() => setViewMonth(new Date(viewMonth.getFullYear(), viewMonth.getMonth() + 1, 1))}
                style={{ width: 34, height: 34, borderRadius: 'var(--radius-md)', border: '1px solid var(--color-border)', background: 'var(--color-bg)', color: 'var(--color-text)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="chevron-right" size={17} /></button>
            </div>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4, marginBottom: 6 }}>
            {dowLabels.map((l) => <div key={l} style={{ textAlign: 'center', fontSize: 10.5, letterSpacing: '0.06em', color: 'var(--color-text-faint)', fontWeight: 700, padding: '4px 0' }}>{l}</div>)}
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4 }}>
            {cells.map((d, i) => {
              if (!d) return <div key={i} />;
              const selectable = isSelectable(d);
              const full = selectable && SLOT_HOURS.every((h) => booked.has(slotId(d, h)));
              const on = sameDay(d, selDate);
              const usable = selectable && !full;
              return (
                <button key={i} type="button" disabled={!usable} onClick={() => { setSelDate(d); setHour(null); if (slotErr) setErrors((e) => ({ ...e, slot: null })); }}
                  style={{ aspectRatio: '1 / 1', borderRadius: 'var(--radius-md)', border: '1px solid ' + (on ? 'var(--color-primary)' : 'transparent'),
                    background: on ? 'var(--color-primary)' : usable ? 'var(--color-surface-2)' : 'transparent',
                    color: on ? 'var(--color-on-primary)' : usable ? 'var(--color-text)' : 'var(--color-text-faint)',
                    cursor: usable ? 'pointer' : 'default', opacity: usable ? 1 : 0.35, fontSize: 14, fontWeight: 600, fontFamily: 'var(--font-mono)',
                    display: 'flex', alignItems: 'center', justifyContent: 'center', font: 'inherit',
                    textDecoration: full ? 'line-through' : 'none', transition: 'background var(--dur-base), border-color var(--dur-base)' }}
                  className={usable && !on ? 'tt-cal-day' : ''}>
                  {d.getDate()}
                </button>
              );
            })}
          </div>
        </div>

        {/* time list */}
        <div style={{ minWidth: 0, padding: 28, display: 'flex', flexDirection: 'column' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
            <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 18, fontWeight: 600, margin: 0 }}>{selDate.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' })}</h3>
          </div>
          <p style={{ fontSize: 12, color: 'var(--color-text-faint)', margin: '0 0 16px', display: 'flex', alignItems: 'center', gap: 6 }}><Icon name="globe" size={13} />Denver time{abbr ? ` · ${abbr}` : ''}</p>
          <div className="tt-time-list" style={{ display: 'flex', flexDirection: 'column', gap: 10, overflowY: 'auto', maxHeight: 320 }}>
            {SLOT_HOURS.map((h) => {
              const taken = booked.has(slotId(selDate, h));
              const on = hour === h;
              return (
                <button key={h} type="button" disabled={taken} onClick={() => { setHour(h); if (slotErr) setErrors((e) => ({ ...e, slot: null })); }}
                  title={taken ? 'Unavailable' : ''}
                  style={{ height: 48, borderRadius: 'var(--radius-md)', border: '1px solid ' + (on ? 'var(--color-primary)' : 'var(--color-border)'), background: on ? 'var(--color-primary)' : taken ? 'var(--color-bg)' : 'var(--color-surface-2)', color: on ? 'var(--color-on-primary)' : taken ? 'var(--color-text-faint)' : 'var(--color-text)', cursor: taken ? 'not-allowed' : 'pointer', fontSize: 14.5, fontWeight: 600, fontFamily: 'var(--font-mono)', textDecoration: taken ? 'line-through' : 'none', opacity: taken ? 0.5 : 1, transition: 'background var(--dur-base), border-color var(--dur-base)' }}>
                  {fmtHour(h)}
                </button>
              );
            })}
          </div>
          {slotErr && <div style={{ marginTop: 12, fontSize: 13, color: 'var(--color-danger)', display: 'flex', alignItems: 'center', gap: 7 }}><Icon name="alert-circle" size={15} />{slotErr}</div>}
        </div>
      </div>

      {/* form */}
      <form onSubmit={submit} noValidate style={{ minWidth: 0, background: 'var(--color-surface)', border: '1px solid var(--color-border)', borderRadius: 'var(--radius-xl)', padding: 28, display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
          <Icon name="user" size={18} color="var(--color-primary)" />
          <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 18, fontWeight: 600, margin: 0 }}>Your details</h3>
        </div>
        <div className="tt-form-row" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
          <ScField label="Full name" required error={errors.name}><ScInput value={form.name} invalid={!!errors.name} onChange={(e) => set('name', e.target.value)} placeholder="Jordan Avery" /></ScField>
          <ScField label="Work email" required error={errors.email}><ScInput type="email" value={form.email} invalid={!!errors.email} onChange={(e) => set('email', e.target.value)} placeholder="you@company.com" /></ScField>
          <ScField label="Company" required error={errors.company}><ScInput value={form.company} invalid={!!errors.company} onChange={(e) => set('company', e.target.value)} placeholder="Company" /></ScField>
        </div>
        <div className="tt-form-row" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <ScField label="Phone" helper="Optional"><ScInput type="tel" value={form.phone} onChange={(e) => set('phone', e.target.value)} placeholder="(555) 000-0000" /></ScField>
          <ScField label="Demo type"><ScSelect value={form.type} onChange={(e) => set('type', e.target.value)}>{DEMO_TYPES.map((o) => <option key={o}>{o}</option>)}</ScSelect></ScField>
        </div>
        <ScField label="Notes" helper="Anything you'd like us to prepare for"><ScTextarea rows={3} value={form.notes} onChange={(e) => set('notes', e.target.value)} placeholder="Team size, use case, sites…" /></ScField>

        {status === 'error' && (
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, padding: '12px 14px', background: 'var(--color-danger-soft, rgba(239,68,68,0.12))', border: '1px solid rgba(239,68,68,0.3)', borderRadius: 'var(--radius-md)' }}>
            <Icon name="alert-triangle" size={17} color="var(--color-danger)" style={{ marginTop: 1, flex: '0 0 auto' }} />
            <div style={{ fontSize: 13.5, color: 'var(--color-text)', lineHeight: 1.5 }}>{errMsg} <button type="button" onClick={submit} style={{ background: 'none', border: 'none', color: 'var(--color-primary-light)', font: 'inherit', fontWeight: 600, cursor: 'pointer', padding: 0 }}>Retry</button></div>
          </div>
        )}

        <div style={{ borderTop: '1px solid var(--color-divider)', paddingTop: 16, marginTop: 2 }}>
          {hour != null && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: 'var(--color-text-muted)', marginBottom: 12 }}>
              <Icon name="calendar-check" size={15} color="var(--color-primary)" />
              {day.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' })} · {fmtHour(hour)}–{fmtHour(hour + 1)} · Denver{abbr ? ` (${abbr})` : ''}
            </div>
          )}
          <ScButton variant="primary" size="lg" type="submit" block disabled={status === 'submitting'} iconRight={status === 'submitting' ? null : <Icon name="arrow-right" size={17} />}>
            {status === 'submitting' ? 'Booking…' : 'Confirm booking'}
          </ScButton>
          <p style={{ fontSize: 12, color: 'var(--color-text-faint)', margin: '12px 0 0', display: 'flex', alignItems: 'center', gap: 7, justifyContent: 'center' }}><Icon name="shield-check" size={13} color="var(--color-primary)" />You'll receive a confirmation email immediately after booking.</p>
        </div>
      </form>
    </div>
  );
}

window.DemoScheduler = DemoScheduler;
