// Bookings — list + lifecycle actions (accept / decline / reschedule / cancel /
// complete / no-show) backed by Supabase, scoped to the current workspace.

function BookingsPage() {
  const auth = useAuth();
  const ws = auth.currentWorkspace;
  const toast = useToast();

  const [bookings, setBookings] = useState([]);
  const [forms, setForms] = useState([]);
  const [loading, setLoading] = useState(true);
  const [query, setQuery] = useState("");
  const [status, setStatus] = useState("active");   // 'active' = anything not cancelled / declined
  const [formFilter, setFormFilter] = useState("all");
  const [selected, setSelected] = useState(null);
  const [showNewBooking, setShowNewBooking] = useState(false);

  const load = useCallback(async () => {
    if (!ws?.id) { setLoading(false); return; }
    setLoading(true);
    const [bRes, fRes] = await Promise.all([
      SB.from('bookings')
        .select('id, starts_at, duration_min, status, source, notes, answers, customer_id, form_id, staff_resource_id, proposed_starts_at, customers ( name, email, phone )')
        .eq('workspace_id', ws.id)
        .order('starts_at', { ascending: false }),
      SB.from('forms').select('id, name, public_title').eq('workspace_id', ws.id)
    ]);
    setLoading(false);
    if (bRes.error) { toast.push(bRes.error.message); return; }
    setBookings(bRes.data || []);
    setForms(fRes.data || []);
  }, [ws?.id, toast]);

  useEffect(() => { load(); }, [load]);

  // The drawer needs the latest version of `selected` after we mutate a booking.
  useEffect(() => {
    if (!selected) return;
    const fresh = bookings.find(b => b.id === selected.id);
    if (fresh && fresh !== selected) setSelected(fresh);
  }, [bookings]);

  const formTitle = (id) => forms.find(f => f.id === id)?.public_title
    || forms.find(f => f.id === id)?.name
    || "Booking";

  const filtered = bookings.filter((b) => {
    if (status === "active" && (b.status === "cancelled" || b.status === "declined")) return false;
    if (status !== "active" && status !== "all" && b.status !== status) return false;
    if (formFilter !== "all" && b.form_id !== formFilter) return false;
    if (query) {
      const q = query.toLowerCase();
      const blob = `${b.customers?.name || ""} ${b.customers?.email || ""} ${formTitle(b.form_id)} ${b.id}`.toLowerCase();
      if (!blob.includes(q)) return false;
    }
    return true;
  });

  // Group by date (most recent first because list is desc).
  const groups = {};
  filtered.forEach((b) => {
    const key = fmt(new Date(b.starts_at), "EEEE, MMM d, yyyy");
    if (!groups[key]) groups[key] = [];
    groups[key].push(b);
  });

  // Stats (computed over *all* bookings, not the filtered list).
  const now = new Date();
  const weekAhead = new Date(now); weekAhead.setDate(weekAhead.getDate() + 7);
  const stats = {
    thisWeek:  bookings.filter(b => { const s = new Date(b.starts_at); return s > now && s < weekAhead && ['confirmed','requested','reschedule_proposed'].includes(b.status); }).length,
    confirmed: bookings.filter(b => b.status === "confirmed").length,
    pending:   bookings.filter(b => b.status === "requested" || b.status === "reschedule_proposed").length,
    declined:  bookings.filter(b => b.status === "declined" || b.status === "cancelled" || b.status === "no_show").length
  };

  // Mutate a single booking's status (or any other fields) and update local state.
  const patchBooking = async (id, patch, successMsg) => {
    const optimistic = bookings.map(b => b.id === id ? Object.assign({}, b, patch) : b);
    setBookings(optimistic);
    const res = await SB.from('bookings').update(patch).eq('id', id).select('id, starts_at, duration_min, status, source, notes, answers, customer_id, form_id, staff_resource_id, proposed_starts_at, customers ( name, email, phone )').single();
    if (res.error) {
      toast.push("Couldn't save: " + res.error.message);
      load();  // refresh from server in case of conflict
      return null;
    }
    setBookings(prev => prev.map(b => b.id === id ? res.data : b));
    if (successMsg) toast.push(successMsg);
    return res.data;
  };

  return (
    <div className="px-5 lg:px-7 py-7 max-w-[1500px] mx-auto">
      <PageHeader
        eyebrow="Operations"
        title="Bookings"
        subtitle="Every appointment, request, and manual booking in one place."
        actions={<Button icon="calendar-plus" onClick={() => setShowNewBooking(true)}>New booking</Button>}
      />

      <NewBookingModal
        open={showNewBooking}
        onClose={() => setShowNewBooking(false)}
        onCreated={() => { setShowNewBooking(false); load(); }}
      />

      <div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-6">
        <StatCard label="This week" value={stats.thisWeek} hint="Upcoming · confirmed + pending" />
        <StatCard label="Confirmed" value={stats.confirmed} hint="All time" />
        <StatCard label="Pending" value={stats.pending} hint="Awaiting decision" />
        <StatCard label="Cancelled / declined" value={stats.declined} hint="No-shows included" />
      </div>

      {/* Toolbar */}
      <div className="flex flex-wrap items-center gap-3 mb-4">
        <div className="flex items-center gap-2 bg-ink/[0.02] border border-ink/[0.06] rounded-md px-2.5 h-9 w-full sm:w-80">
          <Icon name="search" size={13} className="text-ink/40" />
          <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search name, email, form, ID" className="bg-transparent flex-1 text-[13px] placeholder-ink/35 outline-none" />
          {query && <button onClick={() => setQuery("")} className="text-ink/45 hover:text-ink"><Icon name="x" size={13} /></button>}
        </div>
        <FilterChip label="Status" value={status} onChange={setStatus} options={[
          { value: "active",    label: "Active" },
          { value: "all",       label: "All" },
          { value: "requested", label: "Pending" },
          { value: "confirmed", label: "Confirmed" },
          { value: "reschedule_proposed", label: "Reschedule proposed" },
          { value: "completed", label: "Completed" },
          { value: "declined",  label: "Declined" },
          { value: "cancelled", label: "Cancelled" },
          { value: "no_show",   label: "No-show" }
        ]} />
        <FilterChip label="Form" value={formFilter} onChange={setFormFilter} options={[
          { value: "all", label: "All forms" },
          ...forms.map(f => ({ value: f.id, label: f.public_title || f.name }))
        ]} />
        <div className="ml-auto text-[12px] text-ink/55">{filtered.length} of {bookings.length}</div>
      </div>

      {loading ? (
        <div className="py-16 text-center text-[12.5px] text-ink/50">Loading bookings…</div>
      ) : bookings.length === 0 ? (
        <div className="rounded-lg border border-dashed border-ink/[0.12] bg-white p-12 text-center">
          <div className="font-display text-[20px] mb-1">No bookings yet</div>
          <p className="text-[13px] text-ink/55 max-w-md mx-auto">
            Bookings will appear here once customers submit your published forms. Make sure at least one form is published, then share its public URL.
          </p>
        </div>
      ) : filtered.length === 0 ? (
        <div className="p-8"><EmptyState icon="search" title="No bookings match" body="Try clearing your filters or search query." /></div>
      ) : (
        <div className="rounded-lg border border-ink/[0.06] bg-ink/[0.015] overflow-hidden">
          {Object.entries(groups).map(([date, list]) => (
            <div key={date}>
              <div className="px-5 py-2 bg-white border-b border-ink/[0.06] flex items-center justify-between">
                <span className="text-[11px] uppercase tracking-[0.08em] text-ink/55">{date}</span>
                <span className="text-[11px] text-ink/40">{list.length} {list.length === 1 ? "booking" : "bookings"}</span>
              </div>
              <table className="w-full text-[13px]">
                <tbody>
                  {list.map((b) => (
                    <BookingRow
                      key={b.id}
                      booking={b}
                      formTitle={formTitle(b.form_id)}
                      onClick={() => setSelected(b)}
                    />
                  ))}
                </tbody>
              </table>
            </div>
          ))}
        </div>
      )}

      <BookingActionDrawer
        booking={selected}
        formTitle={selected ? formTitle(selected.form_id) : ""}
        onClose={() => setSelected(null)}
        onPatch={patchBooking}
      />
    </div>
  );
}

function BookingRow({ booking, formTitle, onClick }) {
  const start = new Date(booking.starts_at);
  const c = booking.customers || {};
  return (
    <tr onClick={onClick} className="border-b border-ink/[0.04] hover:bg-white cursor-pointer">
      <td className="px-5 py-3 w-[88px]">
        <div className="font-mono text-[12px] text-ink/55">{fmt(start, "h:mma").toLowerCase()}</div>
        <div className="text-[10.5px] text-ink/40">{booking.duration_min}m</div>
      </td>
      <td className="px-2 py-3">
        <div className="flex items-center gap-2.5">
          <Avatar name={c.name || "?"} size={28} />
          <div className="min-w-0">
            <div className="font-medium truncate">{c.name || "Unknown"}</div>
            <div className="text-[11.5px] text-ink/50 truncate">{c.email || ""}</div>
          </div>
        </div>
      </td>
      <td className="px-2 py-3">
        <div>{formTitle}</div>
        <div className="text-[11.5px] text-ink/50 capitalize">{booking.source}</div>
      </td>
      <td className="px-2 py-3 hidden md:table-cell">
        {(booking.answers || []).length > 0 ? (
          <div className="text-[11.5px] text-ink/55 truncate max-w-[220px]">
            {booking.answers[0].q}: <span className="text-ink/85">{String(booking.answers[0].a || "—")}</span>
            {booking.answers.length > 1 && <span className="text-ink/40"> +{booking.answers.length - 1}</span>}
          </div>
        ) : (
          <span className="text-[11.5px] text-ink/35">No custom answers</span>
        )}
      </td>
      <td className="px-2 py-3"><StatusBadge status={booking.status} /></td>
      <td className="px-5 py-3 text-right">
        <button className="text-ink/55 hover:text-ink p-1"><Icon name="chevron-right" size={14} /></button>
      </td>
    </tr>
  );
}

// ── Drawer with status-aware lifecycle actions ───────────────────────────
function BookingActionDrawer({ booking, formTitle, onClose, onPatch }) {
  const [notes, setNotes] = useState("");
  const [showReschedule, setShowReschedule] = useState(false);
  const [reschedAt, setReschedAt] = useState("");
  const [busy, setBusy] = useState(false);
  const toast = useToast();

  // Fires the Resend email via the Supabase Edge Function. Fire-and-forget:
  // if the email fails we still committed the status change.
  const sendEmail = async (kind) => {
    if (!booking) return;
    const res = await SB.functions.invoke('send-booking-email', {
      body: { booking_id: booking.id, kind }
    });
    if (res.error) {
      toast.push(`Status saved, but email failed: ${res.error.message || "unknown"}`);
    } else if (res.data?.skipped) {
      toast.push("Status saved (email template disabled)");
    } else if (res.data?.ok) {
      toast.push("Email sent");
    }
  };

  useEffect(() => {
    if (booking) {
      setNotes(booking.notes || "");
      setShowReschedule(false);
      setReschedAt(booking.proposed_starts_at || booking.starts_at || new Date().toISOString());
    }
  }, [booking?.id]);

  if (!booking) return null;

  const start = new Date(booking.starts_at);
  const end = new Date(start.getTime() + booking.duration_min * 60000);
  const c = booking.customers || {};
  const isPending      = booking.status === "requested";
  const isConfirmed    = booking.status === "confirmed";
  const isProposed     = booking.status === "reschedule_proposed";
  const isTerminal     = ["completed","cancelled","declined","no_show"].includes(booking.status);

  const doPatch = async (patch, msg) => {
    setBusy(true);
    await onPatch(booking.id, patch, msg);
    setBusy(false);
  };

  const saveNotes = async () => {
    if ((booking.notes || "") === notes) return;
    setBusy(true);
    await onPatch(booking.id, { notes }, "Note saved");
    setBusy(false);
  };

  const accept = async () => {
    await doPatch({ status: "confirmed", proposed_starts_at: null }, "Booking confirmed");
    sendEmail("booking_confirmed");
  };
  const decline = async () => {
    await doPatch({ status: "declined" }, "Booking declined");
    sendEmail("booking_declined");
  };
  const cancel = async () => {
    if (!window.confirm("Cancel this booking?")) return;
    await doPatch({ status: "cancelled" }, "Booking cancelled");
    sendEmail("cancellation");
  };
  const markDone   = () => doPatch({ status: "completed" }, "Marked as completed");   // internal, no email
  const markNoShow = () => doPatch({ status: "no_show" },   "Marked as no-show");     // internal, no email
  const submitReschedule = async () => {
    if (!reschedAt) return;
    const iso = new Date(reschedAt).toISOString();
    await doPatch({ proposed_starts_at: iso, status: "reschedule_proposed" }, "Reschedule proposed");
    setShowReschedule(false);
    sendEmail("reschedule_proposed");
  };
  const confirmProposed = async () => {
    if (!booking.proposed_starts_at) return;
    await doPatch({ starts_at: booking.proposed_starts_at, proposed_starts_at: null, status: "confirmed" }, "Reschedule confirmed");
    sendEmail("booking_confirmed");
  };

  // Footer action buttons depend on current status.
  let actions = null;
  if (isPending) {
    actions = (
      <>
        <Button variant="ghost" icon="x" onClick={decline} disabled={busy}>Decline</Button>
        <Button variant="secondary" icon="calendar-clock" onClick={() => setShowReschedule(true)} disabled={busy}>Propose reschedule</Button>
        <Button icon="check" onClick={accept} disabled={busy}>Accept</Button>
      </>
    );
  } else if (isProposed) {
    actions = (
      <>
        <Button variant="ghost" icon="x" onClick={cancel} disabled={busy}>Cancel</Button>
        <Button icon="check" onClick={confirmProposed} disabled={busy}>Confirm new time</Button>
      </>
    );
  } else if (isConfirmed) {
    actions = (
      <>
        <Button variant="ghost" icon="x" onClick={cancel} disabled={busy}>Cancel</Button>
        <Button variant="secondary" icon="user-x" onClick={markNoShow} disabled={busy}>No-show</Button>
        <Button icon="check" onClick={markDone} disabled={busy}>Mark completed</Button>
      </>
    );
  } else if (isTerminal) {
    actions = <Button variant="ghost" onClick={onClose}>Close</Button>;
  }

  const shortRef = (booking.id.split("-")[0] || "").toUpperCase();

  return (
    <Drawer
      open={!!booking}
      onClose={onClose}
      subtitle={`VB-${shortRef}`}
      title={formTitle}
      width={560}
      actions={actions}
    >
      <div className="flex items-center gap-3 pb-5 border-b border-ink/[0.06]">
        <Avatar name={c.name || "?"} size={44} />
        <div className="flex-1 min-w-0">
          <div className="text-[15px]">{c.name || "Unknown"}</div>
          <div className="text-[12.5px] text-ink/55">
            {c.email || "—"}{c.phone ? ` · ${c.phone}` : ""}
          </div>
        </div>
        <StatusBadge status={booking.status} />
      </div>

      <dl className="grid grid-cols-2 gap-y-4 gap-x-6 pt-5 text-[13px]">
        <DL label="Date">{fmt(start, "EEEE, MMM d, yyyy")}</DL>
        <DL label="Time">{fmt(start, "h:mma").toLowerCase()} – {fmt(end, "h:mma").toLowerCase()}</DL>
        <DL label="Duration">{booking.duration_min} minutes</DL>
        <DL label="Source" className="capitalize">{booking.source}</DL>
        {booking.proposed_starts_at && (
          <DL label="Proposed time" className="col-span-2">
            <span className="text-warn">
              {fmt(new Date(booking.proposed_starts_at), "EEEE, MMM d · h:mma").toLowerCase()}
            </span>
          </DL>
        )}
      </dl>

      {showReschedule && (
        <div className="mt-5 p-4 rounded-md border border-warn/30 bg-warn/[0.04]">
          <div className="text-[11px] uppercase tracking-[0.08em] text-warn mb-2">Propose a new time</div>
          <DateTimePicker
            value={reschedAt}
            onChange={(iso) => setReschedAt(iso)}
            minDate={new Date().toISOString()}
          />
          <div className="mt-3 flex items-center justify-end gap-2">
            <Button size="sm" variant="ghost" onClick={() => setShowReschedule(false)} disabled={busy}>Cancel</Button>
            <Button size="sm" icon="check" onClick={submitReschedule} disabled={busy || !reschedAt}>Propose</Button>
          </div>
        </div>
      )}

      <div className="mt-6">
        <div className="text-[11px] uppercase tracking-[0.08em] text-ink/50 mb-2">Internal note</div>
        <Textarea value={notes} onChange={(e) => setNotes(e.target.value)} placeholder="Notes visible only to your team…" />
        <div className="mt-2 flex items-center justify-end">
          <Button size="sm" variant="ghost" onClick={saveNotes} disabled={busy || (booking.notes || "") === notes}>Save note</Button>
        </div>
      </div>

      {(booking.answers || []).length > 0 && (
        <div className="mt-6">
          <div className="text-[11px] uppercase tracking-[0.08em] text-ink/50 mb-3">Submitted answers</div>
          <div className="rounded-md border border-ink/[0.06] divide-y divide-ink/[0.06]">
            {booking.answers.map((a, i) => (
              <div key={i} className="px-3 py-2.5 flex items-baseline gap-4">
                <span className="text-[12px] text-ink/55 w-40 flex-shrink-0">{a.q}</span>
                <span className="text-[13px]">{a.a === null || a.a === "" ? <span className="text-ink/40">—</span> : Array.isArray(a.a) ? a.a.join(", ") : String(a.a)}</span>
              </div>
            ))}
          </div>
        </div>
      )}
    </Drawer>
  );
}

// `datetime-local` input expects "yyyy-MM-ddTHH:mm" in local time.
function toLocalInputValue(d) {
  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())}`;
}

Object.assign(window, { BookingsPage });
