/* global React, Icon, initials, fmtDate, fmtTime, fmtPhone, relTime, serviceLabel, serviceChip, Drawer, toast, api, useApi */

/* ====================================================================
   Appointment detail drawer — opens when a row is clicked.

   Shows everything the database has on the appointment, plus action
   buttons to mark complete / cancel / no-show, change the time, edit
   notes, and jump to the customer profile. Real bug 2026-05-02:
   appointment rows had no onClick handler at all, so the only way to
   "see" an appointment was to read the cramped one-line row.
   ==================================================================== */
const AppointmentDrawer = ({ appointment, onClose, onOpenCustomer }) => {
  const [editingNotes, setEditingNotes] = React.useState(false);
  const [notesValue, setNotesValue] = React.useState(appointment?.notes || '');
  const [reschedulingTime, setReschedulingTime] = React.useState(false);
  const [newTimeValue, setNewTimeValue] = React.useState('');
  const [editingTech, setEditingTech] = React.useState(false);
  const [techValue, setTechValue] = React.useState(appointment?.assigned_tech || '');
  React.useEffect(() => {
    setNotesValue(appointment?.notes || '');
    setEditingNotes(false);
    setReschedulingTime(false);
    setNewTimeValue('');
    setEditingTech(false);
    setTechValue(appointment?.assigned_tech || '');
  }, [appointment?.id]);

  if (!appointment) return null;

  const a = appointment;
  const past = new Date(a.scheduled_at) < new Date();
  const statusLabel = {
    scheduled: 'Scheduled',
    completed: 'Completed',
    cancelled: 'Cancelled',
    no_show: 'No-show',
  }[a.status] || a.status;
  const statusChipClass = {
    scheduled: 'pool',
    completed: 'sage',
    cancelled: '',
    no_show: 'clay',
  }[a.status] || '';

  const updateStatus = async (newStatus) => {
    try {
      await api.updateAppointment(a.id, { status: newStatus });
      toast(`Marked ${newStatus.replace('_', ' ')}`);
      onClose();
    } catch (e) { toast('Error: ' + e.message); }
  };

  const saveNotes = async () => {
    try {
      await api.updateAppointment(a.id, { notes: notesValue });
      toast('Notes saved');
      setEditingNotes(false);
      // Mutate locally so the drawer reflects the new value without a refetch round-trip
      a.notes = notesValue;
    } catch (e) { toast('Error: ' + e.message); }
  };

  const saveNewTime = async () => {
    if (!newTimeValue) return;
    try {
      const iso = new Date(newTimeValue).toISOString();
      await api.updateAppointment(a.id, { scheduled_at: iso });
      toast('Rescheduled');
      a.scheduled_at = iso;
      setReschedulingTime(false);
    } catch (e) { toast('Error: ' + e.message); }
  };

  const saveTech = async () => {
    try {
      await api.updateAppointment(a.id, { assigned_tech: techValue || null });
      toast(techValue ? `Assigned to ${techValue}` : 'Tech cleared');
      a.assigned_tech = techValue;
      setEditingTech(false);
    } catch (e) { toast('Error: ' + e.message); }
  };

  // Format the scheduled time for the datetime-local input — needs
  // local YYYY-MM-DDTHH:MM with no Z suffix
  const datetimeLocalValue = (() => {
    const d = new Date(a.scheduled_at);
    const pad = (n) => String(n).padStart(2, '0');
    return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
  })();

  const actions = [];
  if (a.status === 'scheduled') {
    actions.push({ label: 'Mark complete', primary: true, onClick: () => updateStatus('completed') });
    actions.push({ label: 'Cancel', onClick: () => updateStatus('cancelled') });
    actions.push({ label: 'No-show', onClick: () => updateStatus('no_show') });
  } else {
    actions.push({ label: 'Re-open', primary: true, onClick: () => updateStatus('scheduled') });
  }

  return (
    <Drawer
      title={a.customer_name || fmtPhone(a.customer_phone) || 'Appointment'}
      subtitle={`${serviceLabel ? serviceLabel(a.service) : (a.service || 'Service')} · ${fmtDate(a.scheduled_at)} ${fmtTime(a.scheduled_at)}`}
      onClose={onClose}
      actions={actions}
    >
      <div className="intake-grid">
        <div className="intake-field">
          <div className="if-label">Status</div>
          <div className="if-value">
            <span className={`chip ${statusChipClass}`}>{statusLabel}</span>
            {past && a.status === 'scheduled' && <span className="chip clay" style={{marginLeft: 6}}>Past due</span>}
          </div>
        </div>
        <div className="intake-field">
          <div className="if-label">Service</div>
          <div className="if-value">{serviceLabel ? serviceLabel(a.service) : (a.service || '—')}</div>
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label" style={{display:'flex', justifyContent:'space-between', alignItems:'center'}}>
            <span>Assigned tech</span>
            {!editingTech && a.status === 'scheduled' && (
              <button className="btn ghost xs" onClick={() => { setTechValue(a.assigned_tech || ''); setEditingTech(true); }}>
                {a.assigned_tech ? 'Change' : 'Assign'}
              </button>
            )}
          </div>
          {!editingTech ? (
            <div className="if-value">
              {a.assigned_tech || <span style={{color:'var(--ink-3)'}}>(unassigned)</span>}
            </div>
          ) : (
            <div style={{display:'flex', gap:6, alignItems:'center'}}>
              <input
                className="if-value"
                value={techValue}
                onChange={e => setTechValue(e.target.value)}
                placeholder="Bill, Tech 2, etc."
                list="tech-roster-drawer"
                style={{flex:1}}
                autoFocus
              />
              <datalist id="tech-roster-drawer">
                <option value="Bill" />
                <option value="Tech 2" />
              </datalist>
              <button className="btn primary xs" onClick={saveTech}>Save</button>
              <button className="btn ghost xs" onClick={() => setEditingTech(false)}>Cancel</button>
            </div>
          )}
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label">When</div>
          {!reschedulingTime ? (
            <div className="if-value" style={{display:'flex', justifyContent:'space-between', alignItems:'center'}}>
              <span>{fmtDate(a.scheduled_at)} at {fmtTime(a.scheduled_at)} · {a.duration_min || 60} min</span>
              {a.status === 'scheduled' && (
                <button className="btn ghost xs" onClick={() => { setNewTimeValue(datetimeLocalValue); setReschedulingTime(true); }}>Reschedule</button>
              )}
            </div>
          ) : (
            <div style={{display:'flex', gap:6, alignItems:'center'}}>
              <input
                className="if-value"
                type="datetime-local"
                value={newTimeValue}
                onChange={e => setNewTimeValue(e.target.value)}
                style={{flex:1}}
              />
              <button className="btn primary xs" onClick={saveNewTime}>Save</button>
              <button className="btn ghost xs" onClick={() => setReschedulingTime(false)}>Cancel</button>
            </div>
          )}
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label">Customer</div>
          <div className="if-value" style={{display:'flex', justifyContent:'space-between', alignItems:'center'}}>
            <span>
              {a.customer_name || '(no name on file)'}
              <span style={{color:'var(--ink-3)', marginLeft:8}}>{fmtPhone(a.customer_phone)}</span>
            </span>
            {a.customer_phone && onOpenCustomer && (
              <button className="btn ghost xs" onClick={() => onOpenCustomer({ phone: a.customer_phone, name: a.customer_name, address: a.address })}>Open profile</button>
            )}
          </div>
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label">Address</div>
          <div className="if-value">
            <Icon name="pin" size={11} /> {a.address || '—'}
          </div>
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label">Notes</div>
          {!editingNotes ? (
            <div className="if-value" style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', gap:8, whiteSpace:'pre-wrap'}}>
              <span style={{flex:1}}>{a.notes || <span style={{color:'var(--ink-3)'}}>—</span>}</span>
              <button className="btn ghost xs" onClick={() => setEditingNotes(true)}>Edit</button>
            </div>
          ) : (
            <div style={{display:'flex', flexDirection:'column', gap:6}}>
              <textarea
                className="if-value"
                value={notesValue}
                onChange={e => setNotesValue(e.target.value)}
                rows={3}
                placeholder="Gate code, dog, equipment notes, what the tech needs to know…"
              />
              <div style={{display:'flex', gap:6}}>
                <button className="btn primary xs" onClick={saveNotes}>Save</button>
                <button className="btn ghost xs" onClick={() => { setNotesValue(a.notes || ''); setEditingNotes(false); }}>Cancel</button>
              </div>
            </div>
          )}
        </div>
      </div>

      <div className="eyebrow" style={{marginTop:16, marginBottom:8}}>Reminders</div>
      <div className="intake-grid">
        <div className="intake-field">
          <div className="if-label">Day-before</div>
          <div className="if-value">
            {a.day_before_reminder_sent_at
              ? <>✓ Sent {relTime(a.day_before_reminder_sent_at)}</>
              : <span style={{color:'var(--ink-3)'}}>Not sent yet</span>}
          </div>
        </div>
        <div className="intake-field">
          <div className="if-label">Same-day</div>
          <div className="if-value">
            {a.same_day_reminder_sent_at
              ? <>✓ Sent {relTime(a.same_day_reminder_sent_at)}</>
              : <span style={{color:'var(--ink-3)'}}>Not sent yet</span>}
          </div>
        </div>
      </div>

      <div className="eyebrow" style={{marginTop:16, marginBottom:8}}>Audit</div>
      <div className="intake-grid">
        <div className="intake-field">
          <div className="if-label">Booked by</div>
          <div className="if-value">
            {a.created_by === 'voice_agent' ? '🎤 Voice agent' :
             a.created_by === 'whatsapp' ? '💬 WhatsApp' :
             '👤 Manual'}
          </div>
        </div>
        <div className="intake-field">
          <div className="if-label">Created</div>
          <div className="if-value">{a.created_at ? relTime(a.created_at) : '—'}</div>
        </div>
        {a.call_id && (
          <div className="intake-field" style={{gridColumn: '1 / -1'}}>
            <div className="if-label">Source call</div>
            <div className="if-value" style={{fontFamily:'monospace', fontSize:12}}>{a.call_id}</div>
          </div>
        )}
        {a.external_id && (
          <div className="intake-field" style={{gridColumn: '1 / -1'}}>
            <div className="if-label">External sync</div>
            <div className="if-value" style={{fontSize:12}}>
              <span style={{color:'var(--ink-3)'}}>{a.external_source || 'unknown'}:</span> {a.external_id}
              {a.synced_at && <span style={{color:'var(--ink-3)', marginLeft:8}}>· synced {relTime(a.synced_at)}</span>}
            </div>
          </div>
        )}
      </div>
    </Drawer>
  );
};

/* ====================================================================
   Followups — calls that ended with the agent promising a manual
   followup (quote handoffs, degraded bookings, out-of-area courtesy
   callbacks, calls that ended without resolution). This is the
   "things Bill needs to do something about" queue. Real bug
   2026-05-02: Bill had no way to see which agent calls left the
   caller hanging — degraded bookings ("team will reach out") were
   buried in the calls log with no way to filter or mark resolved.
   ==================================================================== */
const FollowupsView = ({ onOpenCall, onOpenCustomer }) => {
  const [tab, setTab] = React.useState('open');
  const { data: rows, loading, refetch } = useApi(
    () => api.followups(tab),
    [tab],
  );
  const list = rows || [];

  const markDone = async (callId) => {
    try {
      await api.resolveFollowup(callId, true);
      refetch();
      toast('Marked done');
    } catch (e) { toast('Error: ' + e.message); }
  };
  const reopen = async (callId) => {
    try {
      await api.resolveFollowup(callId, false);
      refetch();
      toast('Reopened');
    } catch (e) { toast('Error: ' + e.message); }
  };

  const reasonChip = (r) => {
    const label = r.reason_label || 'Needs review';
    let klass = 'pool';
    if (/failed|degraded/i.test(label)) klass = 'clay';
    else if (/quote/i.test(label)) klass = 'sun';
    else if (/out.of.area/i.test(label)) klass = '';
    return <span className={`chip ${klass}`}>{label}</span>;
  };

  return (
    <div>
      <div className="page-head">
        <div>
          <h1>Followups</h1>
          <div className="subtitle">
            Calls that ended without a confirmed booking — quote handoffs, degraded
            bookings, out-of-area requests. Call these people back, then mark done.
          </div>
        </div>
      </div>

      <div className="filters-bar">
        <div className="filter-group">
          <label>Status</label>
          <select value={tab} onChange={e => setTab(e.target.value)}>
            <option value="open">Open ({loading ? '…' : list.length})</option>
            <option value="done">Resolved</option>
          </select>
        </div>
        <span className="results-count">{loading ? '…' : `${list.length} ${tab === 'open' ? 'open' : 'resolved'}`}</span>
      </div>

      {list.length === 0 && !loading && (
        <div className="empty-state card" style={{padding: 32, textAlign: 'center'}}>
          {tab === 'open' ? (
            <>
              <Icon name="check-circle" size={32} />
              <div style={{marginTop: 8, fontWeight: 600}}>Nothing to follow up.</div>
              <div style={{color: 'var(--ink-3)', fontSize: 13}}>The agent's handling everything cleanly.</div>
            </>
          ) : (
            <>No resolved followups yet.</>
          )}
        </div>
      )}

      <div style={{display: 'flex', flexDirection: 'column', gap: 8}}>
        {list.map(r => {
          const ageMs = Date.now() - new Date(r.started_at).getTime();
          const ageH = Math.round(ageMs / 3600000);
          const isUrgent = tab === 'open' && (
            ageH < 2 || /failed/i.test(r.reason_label || '')
          );
          return (
            <div
              key={r.call_id}
              className="card"
              style={{
                padding: 14,
                display: 'grid',
                gridTemplateColumns: '1fr auto',
                gap: 12,
                alignItems: 'center',
                borderLeft: isUrgent ? '3px solid var(--clay)' : '3px solid transparent',
              }}
            >
              <div style={{minWidth: 0}}>
                <div style={{display: 'flex', gap: 10, alignItems: 'center', marginBottom: 6, flexWrap: 'wrap'}}>
                  {reasonChip(r)}
                  <span style={{color: 'var(--ink-3)', fontSize: 12}}>{relTime(r.started_at)}</span>
                  {r.duration_s && <span style={{color: 'var(--ink-3)', fontSize: 12}}>· {Math.round(r.duration_s / 60)}m call</span>}
                  {r.followup_resolved_at && (
                    <span style={{color: 'var(--ink-3)', fontSize: 12}}>· resolved by {r.followup_resolved_by || 'unknown'} {relTime(r.followup_resolved_at)}</span>
                  )}
                </div>
                <div style={{fontWeight: 600, marginBottom: 2}}>
                  {r.name || fmtPhone(r.caller_phone) || '(no caller info)'}
                </div>
                <div style={{color: 'var(--ink-3)', fontSize: 13}}>
                  {r.service && <>Wanted: <span style={{textTransform: 'capitalize'}}>{String(r.service).replace('_', ' ')}</span></>}
                  {r.address && <> · {r.address}</>}
                  {r.outcome_reason && r.outcome_reason !== r.service && (
                    <div style={{marginTop: 4, color: 'var(--ink-3)', fontStyle: 'italic'}}>"{r.outcome_reason}"</div>
                  )}
                </div>
              </div>
              <div style={{display: 'flex', flexDirection: 'column', gap: 4, minWidth: 130}}>
                {r.caller_phone && (
                  <a href={`tel:${r.caller_phone}`} className="btn primary xs" style={{textAlign: 'center', textDecoration: 'none'}}>
                    Call back
                  </a>
                )}
                <button className="btn ghost xs" onClick={() => onOpenCall && onOpenCall(r.call_id)}>
                  View call
                </button>
                {tab === 'open' ? (
                  <button className="btn ghost xs" onClick={() => markDone(r.call_id)}>
                    Mark done
                  </button>
                ) : (
                  <button className="btn ghost xs" onClick={() => reopen(r.call_id)}>
                    Re-open
                  </button>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};

/* ====================================================================
   Appointments — REAL DATA with create support
   ==================================================================== */
const AppointmentsView = ({ onOpenCustomer, onOpenAppointment, prefilled, onPrefilledConsumed }) => {
  const [range, setRange] = React.useState("upcoming");
  const [status, setStatus] = React.useState("all");
  const [showForm, setShowForm] = React.useState(false);
  const [formInitial, setFormInitial] = React.useState(null);
  // Auto-open the new-appointment form when caller passed a prefill
  // (e.g. from CustomerDrawer's "Schedule visit" action). Mark consumed
  // so re-renders don't keep re-opening.
  React.useEffect(() => {
    if (prefilled) {
      setFormInitial(prefilled);
      setShowForm(true);
      onPrefilledConsumed && onPrefilledConsumed();
    }
  }, [prefilled, onPrefilledConsumed]);
  const { data: appointments, loading, refetch } = useApi(
    () => api.appointments(range, status !== 'all' ? status : null),
    [range, status]
  );

  const apptList = appointments || [];

  /* group by day */
  const groups = React.useMemo(() => {
    const m = new Map();
    apptList.forEach(a => {
      const d = new Date(a.scheduled_at);
      const key = d.toDateString();
      if (!m.has(key)) m.set(key, []);
      m.get(key).push(a);
    });
    return [...m.entries()];
  }, [apptList]);

  const dayLabel = (d) => {
    const today = new Date(); today.setHours(0,0,0,0);
    const dd = new Date(d); dd.setHours(0,0,0,0);
    const diff = Math.round((dd - today) / 86400e3);
    if (diff === 0) return "Today";
    if (diff === 1) return "Tomorrow";
    if (diff === -1) return "Yesterday";
    return dd.toLocaleDateString([], { weekday: "long" });
  };

  const handleStatusChange = async (appt, newStatus) => {
    try {
      await api.updateAppointment(appt.id, { status: newStatus });
      refetch();
      toast(`Appointment ${newStatus}`);
    } catch (e) { toast('Error: ' + e.message); }
  };

  const handleCreate = async (formData) => {
    try {
      await api.createAppointment(formData);
      setShowForm(false);
      refetch();
      toast('Appointment created');
    } catch (e) { toast('Error: ' + e.message); }
  };

  return (
    <div>
      <div className="page-head">
        <div>
          <h1>Appointments</h1>
          <div className="subtitle">Reminders auto-send 24h and same-day before each visit.</div>
        </div>
        <button className="btn primary" onClick={() => setShowForm(true)}><Icon name="plus" size={16} /> New appointment</button>
      </div>

      <div className="filters-bar">
        <div className="filter-group">
          <label>When</label>
          <select value={range} onChange={e => setRange(e.target.value)}>
            <option value="upcoming">Upcoming</option>
            <option value="past">Past</option>
            <option value="all">All</option>
          </select>
        </div>
        <div className="filter-group">
          <label>Status</label>
          <select value={status} onChange={e => setStatus(e.target.value)}>
            <option value="all">All</option>
            <option value="scheduled">Scheduled</option>
            <option value="completed">Completed</option>
            <option value="cancelled">Cancelled</option>
            <option value="no_show">No-show</option>
          </select>
        </div>
        <span className="results-count">{loading ? '…' : `${apptList.length} appointments`}</span>
      </div>

      {groups.map(([key, list]) => (
        <div key={key} className="appt-day">
          <div className="appt-day-head">
            <span className="appt-day-name">{dayLabel(key)}</span>
            <span className="appt-day-date">{new Date(key).toLocaleDateString([], { month:"short", day:"numeric", year:"numeric" })}</span>
            <span className="appt-day-count">{list.length} stop{list.length === 1 ? "" : "s"}</span>
          </div>
          {list.map(a => {
            const now = new Date();
            const past = new Date(a.scheduled_at) < now;
            return (
              <div
                key={a.id}
                className={`appt-row ${past ? "past" : ""}`}
                role="button"
                tabIndex={0}
                onClick={() => onOpenAppointment && onOpenAppointment(a)}
                onKeyDown={(e) => { if ((e.key === 'Enter' || e.key === ' ') && onOpenAppointment) { e.preventDefault(); onOpenAppointment(a); } }}
                style={{cursor: onOpenAppointment ? 'pointer' : 'default'}}
              >
                <div className="appt-time">
                  {fmtTime(a.scheduled_at)}
                  <small>{serviceLabel(a.service)}</small>
                </div>
                <div className="appt-customer">
                  <div className="appt-name">
                    {a.customer_name || fmtPhone(a.customer_phone)}
                    {a.assigned_tech && (
                      <span style={{marginLeft:8, fontSize:11, padding:'1px 6px', borderRadius:3, background:'var(--line)', color:'var(--ink-2)'}}>{a.assigned_tech}</span>
                    )}
                  </div>
                  <div className="appt-address"><Icon name="pin" size={11} /> {a.address || '—'}</div>
                </div>
                <div className="appt-status-chip">
                  <span className={`chip ${
                    a.status === "scheduled" ? "pool" :
                    a.status === "completed" ? "sage" :
                    a.status === "cancelled" ? "" : "clay"
                  }`}>{a.status}</span>
                </div>
                <div className="appt-reminder-dots" title={`Day-before: ${a.day_before_reminder_sent_at ? '✓' : '—'} · Same-day: ${a.same_day_reminder_sent_at ? '✓' : '—'}`}>
                  <span className={`rd ${a.day_before_reminder_sent_at ? "sent" : ""}`}></span>
                  <span className={`rd ${a.same_day_reminder_sent_at ? "sent" : ""}`}></span>
                </div>
                {a.status === 'scheduled' && (
                  <div style={{display:'flex', gap:4}} onClick={(e) => e.stopPropagation()}>
                    <button className="btn ghost xs" title="Mark complete" onClick={() => handleStatusChange(a, 'completed')}>✓</button>
                    <button className="btn ghost xs" title="Cancel" onClick={() => handleStatusChange(a, 'cancelled')}>✕</button>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      ))}
      {groups.length === 0 && !loading && <div className="empty-state card">No appointments match these filters.</div>}

      {showForm && <NewAppointmentForm initial={formInitial} onClose={() => { setShowForm(false); setFormInitial(null); }} onSubmit={handleCreate} />}
    </div>
  );
};

/* ---------- New appointment form (drawer) ---------- */
const NewAppointmentForm = ({ onClose, onSubmit, initial }) => {
  const [form, setForm] = React.useState({
    customer_phone: initial?.customer_phone || '',
    customer_name: initial?.customer_name || '',
    service: initial?.service || 'Weekly service',
    address: initial?.address || '',
    scheduled_at: '',
    duration_min: 60,
    notes: '',
    assigned_tech: '',
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  return (
    <Drawer title="New appointment" onClose={onClose} actions={[
      { label: "Create", primary: true, onClick: () => onSubmit(form) },
      { label: "Cancel", onClick: onClose },
    ]}>
      <div className="intake-grid" style={{gap: 12}}>
        <div className="intake-field">
          <div className="if-label">Phone *</div>
          <input className="if-value" value={form.customer_phone} onChange={e => set('customer_phone', e.target.value)} placeholder="+1..." />
        </div>
        <div className="intake-field">
          <div className="if-label">Name</div>
          <input className="if-value" value={form.customer_name} onChange={e => set('customer_name', e.target.value)} placeholder="Customer name" />
        </div>
        <div className="intake-field">
          <div className="if-label">Service</div>
          <select className="if-value" value={form.service} onChange={e => set('service', e.target.value)}>
            <option>Weekly service</option>
            <option>Opening</option>
            <option>Closing</option>
            <option>Liner replacement</option>
            <option>Equipment</option>
            <option>Other</option>
          </select>
        </div>
        <div className="intake-field">
          <div className="if-label">Address</div>
          <input className="if-value" value={form.address} onChange={e => set('address', e.target.value)} placeholder="123 Main St" />
        </div>
        <div className="intake-field">
          <div className="if-label">Date & Time *</div>
          <input className="if-value" type="datetime-local" value={form.scheduled_at} onChange={e => set('scheduled_at', new Date(e.target.value).toISOString())} />
        </div>
        <div className="intake-field">
          <div className="if-label">Duration (min)</div>
          <input className="if-value" type="number" value={form.duration_min} onChange={e => set('duration_min', Number(e.target.value))} />
        </div>
        <div className="intake-field">
          <div className="if-label">Tech</div>
          <input className="if-value" value={form.assigned_tech} onChange={e => set('assigned_tech', e.target.value)} placeholder="(unassigned)" list="tech-roster" />
          {/* Datalist of recent techs — pulled from existing rows. Keeps
              spelling consistent without forcing a hard FK to a roster. */}
          <datalist id="tech-roster">
            <option value="Bill" />
            <option value="Tech 2" />
          </datalist>
        </div>
        <div className="intake-field" style={{gridColumn: '1 / -1'}}>
          <div className="if-label">Notes</div>
          <textarea className="if-value" value={form.notes} onChange={e => set('notes', e.target.value)} rows={2} placeholder="Gate code, special instructions…" />
        </div>
      </div>
    </Drawer>
  );
};

/* ====================================================================
   Messages — REAL DATA from /api/threads
   ==================================================================== */
const MessagesView = ({ openThreadId, setOpenThreadId }) => {
  const [q, setQ] = React.useState("");
  const { data: threads, loading } = useApi(() => api.threads(), []);
  const { data: threadDetail } = useApi(
    () => openThreadId ? api.thread(openThreadId) : Promise.resolve(null),
    [openThreadId]
  );

  const threadList = (threads || []).filter(t => {
    if (!q) return true;
    const s = q.toLowerCase();
    return (t.customer_name || '').toLowerCase().includes(s) || t.phone.includes(s);
  });

  const activeMessages = threadDetail?.messages || [];
  const activeName = threadDetail?.customer_name || (openThreadId ? fmtPhone(openThreadId) : '');

  return (
    <div>
      <div className="page-head">
        <div>
          <h1>Messages</h1>
          <div className="subtitle">SMS + WhatsApp + voicemail in one inbox. The agent replies on routine things, you take over anything personal.</div>
        </div>
      </div>
      <div className={`messages-layout ${openThreadId ? "has-selection" : ""}`}>
        <div className="threads-col">
          <div className="thread-search">
            <div className="search-inline" style={{padding:"6px 12px"}}>
              <Icon name="search" size={14} />
              <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search conversations…" />
            </div>
          </div>
          <div className="thread-list">
            {threadList.map(t => (
              <div key={t.phone} className={`thread-item ${t.phone === openThreadId ? "active" : ""}`} onClick={() => setOpenThreadId(t.phone)}>
                <div className="avatar sm">{initials(t.customer_name)}</div>
                <div className="ti-main">
                  <div className="ti-name">{t.customer_name || fmtPhone(t.phone)}</div>
                  <div className="ti-preview">{t.last_direction === 'out' ? "You: " : ""}{t.last_body}</div>
                </div>
                <div className="ti-meta">
                  <div className="ti-when">{relTime(t.last_message_at)}</div>
                  <div className="ti-count">{t.total_count}</div>
                </div>
              </div>
            ))}
            {threadList.length === 0 && !loading && <div className="empty-state" style={{padding: 20}}>No conversations.</div>}
          </div>
        </div>

        <div className="pane-col">
          {!openThreadId && (
            <div style={{flex:1, display:"flex", alignItems:"center", justifyContent:"center", color:"var(--ink-3)", fontSize:14}}>
              Select a conversation to view messages.
            </div>
          )}
          {openThreadId && threadDetail && (
            <>
              <div className="pane-head">
                <button className="back-btn" onClick={() => setOpenThreadId(null)}>‹ Back</button>
                <div className="avatar">{initials(activeName)}</div>
                <div className="pane-title">
                  <div className="pt-name">{activeName}</div>
                  <div className="pt-meta">{fmtPhone(openThreadId)}</div>
                </div>
              </div>
              <div className="pane-body">
                {activeMessages.map((m, i) => (
                  <div key={i} className={`msg-bubble ${m.direction} ${m.sender === "agent" ? "agent" : ""}`}>
                    {m.body}
                    <div className="msg-meta">
                      {m.direction === "out" && (m.sender === "agent" ? "Agent · " : "You · ")}
                      {(m.channel || 'sms').toUpperCase()} · {fmtTime(m.created_at)}
                      {m.status && m.status !== 'delivered' && m.status !== 'received' && ` · ${m.status}`}
                    </div>
                  </div>
                ))}
                {activeMessages.length === 0 && <div style={{color: 'var(--ink-3)', fontSize: 13, textAlign: 'center', padding: 20}}>No messages in this thread.</div>}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
};

window.AppointmentsView = AppointmentsView;
window.AppointmentDrawer = AppointmentDrawer;
window.FollowupsView = FollowupsView;
window.MessagesView = MessagesView;
