// Calendar — month / week / day view of the current workspace's bookings.
// Clicking a booking opens the shared BookingActionDrawer from pages-bookings.jsx
// so accept / decline / reschedule all work straight from here too.

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

  const [view, setView] = useState("week");
  const [anchor, setAnchor] = useState(new Date());
  const [bookings, setBookings] = useState([]);
  const [forms, setForms] = useState([]);
  const [blocks, setBlocks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [filters, setFilters] = useState({ status: "active", form: "all" });
  const [selected, setSelected] = useState(null);
  const [showBlock, setShowBlock] = useState(false);
  const [showNewBooking, setShowNewBooking] = useState(false);

  const load = useCallback(async () => {
    if (!ws?.id) { setLoading(false); return; }
    setLoading(true);
    const [bRes, fRes, tbRes] = 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),
      SB.from('forms').select('id, public_title, name').eq('workspace_id', ws.id),
      SB.from('time_blocks').select('id, starts_at, ends_at, label').eq('workspace_id', ws.id)
    ]);
    setLoading(false);
    if (bRes.error) { toast.push(bRes.error.message); return; }
    setBookings((bRes.data || []).map(b => Object.assign({}, b, { _start: new Date(b.starts_at) })));
    setForms(fRes.data || []);
    setBlocks(tbRes.data || []);
  }, [ws?.id, toast]);

  const removeBlock = async (id) => {
    if (!window.confirm("Remove this time block?")) return;
    const res = await SB.from('time_blocks').delete().eq('id', id);
    if (res.error) { toast.push("Couldn't remove: " + res.error.message); return; }
    setBlocks(prev => prev.filter(b => b.id !== id));
    toast.push("Block removed");
  };

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

  // Optimistic patch used by the drawer's action buttons.
  const patchBooking = async (id, patch, msg) => {
    setBookings(prev => prev.map(b => b.id === id ? Object.assign({}, b, patch, patch.starts_at ? { _start: new Date(patch.starts_at) } : {}) : b));
    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(); return null; }
    setBookings(prev => prev.map(b => b.id === id ? Object.assign({}, res.data, { _start: new Date(res.data.starts_at) }) : b));
    if (msg) toast.push(msg);
    return res.data;
  };

  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 (filters.status === "active" && (b.status === "cancelled" || b.status === "declined")) return false;
    if (filters.status !== "active" && filters.status !== "all" && b.status !== filters.status) return false;
    if (filters.form !== "all" && b.form_id !== filters.form) return false;
    return true;
  });

  const navTitle =
    view === "month" ? fmt(anchor, "MMMM yyyy") :
    view === "week"  ? `${fmt(weekStart(anchor), "MMM d")} – ${fmt(weekEnd(anchor), "MMM d, yyyy")}` :
                       fmt(anchor, "EEEE, MMM d, yyyy");

  const shift = (dir) => {
    const d = new Date(anchor);
    if (view === "month") d.setMonth(d.getMonth() + dir);
    else if (view === "week") d.setDate(d.getDate() + 7 * dir);
    else d.setDate(d.getDate() + dir);
    setAnchor(d);
  };

  return (
    <div className="px-5 lg:px-7 py-7 max-w-[1500px] mx-auto">
      <PageHeader
        eyebrow="Schedule"
        title="Calendar"
        subtitle="Appointments by month, week, or day. Click any booking to open it."
        actions={
          <>
            <Button variant="secondary" icon="ban" onClick={() => setShowBlock(true)}>Block time</Button>
            <Button icon="calendar-plus" onClick={() => setShowNewBooking(true)}>New booking</Button>
          </>
        }
      />

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

      <div className="flex flex-wrap items-center gap-3 mb-4">
        <div className="flex items-center gap-1">
          <button onClick={() => shift(-1)} className="h-8 w-8 grid place-items-center rounded-md hover:bg-ink/[0.04] text-ink/75"><Icon name="chevron-left" size={14} /></button>
          <button onClick={() => setAnchor(new Date())} className="h-8 px-3 rounded-md hover:bg-ink/[0.04] text-[12.5px] text-ink/80">Today</button>
          <button onClick={() => shift(1)} className="h-8 w-8 grid place-items-center rounded-md hover:bg-ink/[0.04] text-ink/75"><Icon name="chevron-right" size={14} /></button>
        </div>
        <div className="font-display text-[20px] leading-none tracking-tight">{navTitle}</div>
        <div className="ml-auto flex items-center gap-2">
          <Tabs value={view} onChange={setView} options={[
            { value: "month", label: "Month" },
            { value: "week",  label: "Week"  },
            { value: "day",   label: "Day"   }
          ]} />
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-2 mb-4 text-[12px]">
        <Icon name="filter" size={13} className="text-ink/50" />
        <FilterChip label="Status" value={filters.status} onChange={(v) => setFilters(Object.assign({}, filters, { status: v }))} options={[
          { value: "active", label: "Active" },
          { value: "all", label: "All" },
          { value: "requested", label: "Pending" },
          { value: "confirmed", label: "Confirmed" },
          { value: "completed", label: "Completed" },
          { value: "declined", label: "Declined" },
          { value: "cancelled", label: "Cancelled" }
        ]} />
        <FilterChip label="Form" value={filters.form} onChange={(v) => setFilters(Object.assign({}, filters, { form: v }))} options={[
          { value: "all", label: "All forms" },
          ...forms.map(f => ({ value: f.id, label: f.public_title || f.name }))
        ]} />
        {(filters.status !== "active" || filters.form !== "all") && (
          <button onClick={() => setFilters({ status: "active", form: "all" })} className="text-ink/55 hover:text-ink">Clear</button>
        )}
        <div className="ml-auto text-[12px] text-ink/55">{filtered.length} bookings</div>
      </div>

      {loading ? (
        <div className="py-16 text-center text-[12.5px] text-ink/50">Loading…</div>
      ) : (
        <>
          {view === "month" && <MonthView anchor={anchor} bookings={filtered} formTitle={formTitle} onPick={setSelected} blocks={blocks} />}
          {view === "week"  && <WeekView  anchor={anchor} bookings={filtered} formTitle={formTitle} onPick={setSelected} blocks={blocks} onRemoveBlock={removeBlock} />}
          {view === "day"   && <DayView   anchor={anchor} bookings={filtered} formTitle={formTitle} onPick={setSelected} blocks={blocks} onRemoveBlock={removeBlock} />}
        </>
      )}

      {/* The drawer comes from pages-bookings.jsx (window global). Same lifecycle actions. */}
      {selected && (
        <BookingActionDrawer
          booking={selected}
          formTitle={formTitle(selected.form_id)}
          onClose={() => setSelected(null)}
          onPatch={async (id, patch, msg) => {
            const updated = await patchBooking(id, patch, msg);
            if (updated) setSelected(Object.assign({}, updated, { _start: new Date(updated.starts_at) }));
            return updated;
          }}
        />
      )}
    </div>
  );
}

function FilterChip({ label, value, onChange, options }) {
  return (
    <div className="inline-flex items-center gap-1.5 rounded-md border border-ink/[0.06] bg-white pl-2.5 pr-1.5 h-7 text-[12px] leading-none">
      <span className="text-ink/50">{label}</span>
      <select value={value} onChange={(e) => onChange(e.target.value)} className="bg-transparent text-ink appearance-none pr-4 cursor-pointer outline-none text-[12px]">
        {options.map(o => <option key={o.value} value={o.value} className="bg-paper">{o.label}</option>)}
      </select>
      <Icon name="chevron-down" size={11} className="text-ink/50 -ml-3 pointer-events-none" />
    </div>
  );
}

function statusColor(status) {
  switch (status) {
    case "requested":            return "#B07A2A";   // amber
    case "reschedule_proposed":  return "#B07A2A";
    case "confirmed":            return "#3D7BB0";   // blue
    case "completed":            return "#3F7A5F";   // green
    case "cancelled":            return "#A04444";   // red
    case "declined":             return "#A04444";
    case "no_show":              return "#6E6E73";   // muted
    default:                     return "#3D7BB0";
  }
}

// ── Month ─────────────────────────────────────────────────────────────────
function MonthView({ anchor, bookings, formTitle, onPick }) {
  const first = new Date(anchor.getFullYear(), anchor.getMonth(), 1);
  const startGrid = new Date(first);
  startGrid.setDate(1 - first.getDay());
  const days = Array.from({ length: 42 }, (_, i) => { const d = new Date(startGrid); d.setDate(startGrid.getDate() + i); return d; });
  const today = new Date();

  return (
    <div className="rounded-lg border border-ink/[0.06] overflow-hidden bg-ink/[0.015]">
      <div className="grid grid-cols-7 text-[11px] uppercase tracking-[0.08em] text-ink/50 border-b border-ink/[0.06] bg-white">
        {["Sun","Mon","Tue","Wed","Thu","Fri","Sat"].map(d => (
          <div key={d} className="px-3 py-2.5 border-r border-ink/[0.06] last:border-r-0">{d}</div>
        ))}
      </div>
      <div className="grid grid-cols-7">
        {days.map((d, i) => {
          const inMonth = d.getMonth() === anchor.getMonth();
          const isToday = sameDay(d, today);
          const dayBookings = bookings.filter(b => sameDay(b._start, d)).sort((a, b) => a._start - b._start);
          return (
            <div key={i} className={`relative h-[110px] border-r border-b border-ink/[0.06] p-2 ${i % 7 === 6 ? "border-r-0" : ""} ${!inMonth ? "bg-ink/[0.015]" : "bg-white"}`}>
              <div className="flex items-center justify-between">
                <span className={`text-[12px] ${isToday ? "bg-accent text-white rounded-full h-5 w-5 grid place-items-center" : inMonth ? "text-ink/85" : "text-ink/35"}`}>
                  {d.getDate()}
                </span>
                {dayBookings.length > 0 && <span className="text-[10px] text-ink/45">{dayBookings.length}</span>}
              </div>
              <div className="mt-1 flex flex-col gap-0.5">
                {dayBookings.slice(0, 3).map(b => (
                  <button
                    key={b.id}
                    onClick={() => onPick(b)}
                    className="text-left text-[10.5px] px-1.5 py-0.5 rounded truncate hover:opacity-90"
                    style={{ background: hexWithAlpha(statusColor(b.status), 0.15), color: "#1D1D1F" }}
                  >
                    <span className="text-ink/55">{fmt(b._start, "h:mma").toLowerCase()}</span> {(b.customers?.name || "?").split(" ")[0]}
                  </button>
                ))}
                {dayBookings.length > 3 && <span className="text-[10px] text-ink/45 px-1.5">+{dayBookings.length - 3} more</span>}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function hexWithAlpha(hex, alpha) {
  const a = Math.round(alpha * 255).toString(16).padStart(2, "0");
  return hex + a;
}

// ── Week ──────────────────────────────────────────────────────────────────
function WeekView({ anchor, bookings, formTitle, onPick, blocks, onRemoveBlock }) {
  const start = weekStart(anchor);
  const days = Array.from({ length: 7 }, (_, i) => { const d = new Date(start); d.setDate(start.getDate() + i); return d; });
  const today = new Date();
  const startH = 8, endH = 20, totalH = endH - startH;
  const nowOffset = ((today.getHours() + today.getMinutes()/60) - startH) / totalH * 100;
  const colHeight = 720;
  const blocksForDay = (d) => (blocks || []).filter(b => {
    const bs = new Date(b.starts_at), be = new Date(b.ends_at);
    const ds = new Date(d); ds.setHours(0,0,0,0);
    const de = new Date(ds); de.setDate(de.getDate() + 1);
    return bs < de && be > ds;
  });

  return (
    <div className="rounded-lg border border-ink/[0.06] overflow-hidden bg-white">
      <div className="grid grid-cols-[56px_repeat(7,1fr)] border-b border-ink/[0.06]">
        <div />
        {days.map((d, i) => (
          <div key={i} className={`px-3 py-2.5 border-l border-ink/[0.06] flex items-baseline gap-2 ${sameDay(d, today) ? "bg-accent/[0.06]" : ""}`}>
            <span className="text-[11px] uppercase tracking-[0.08em] text-ink/50">{fmt(d, "EEE")}</span>
            <span className={`text-[15px] ${sameDay(d, today) ? "text-ink font-medium" : "text-ink/85"}`}>{d.getDate()}</span>
          </div>
        ))}
      </div>
      <div className="grid grid-cols-[56px_repeat(7,1fr)] relative" style={{ height: colHeight }}>
        <div className="relative">
          {Array.from({length: totalH + 1}, (_, i) => (
            <div key={i} className="absolute -translate-y-1/2 right-2 text-[10.5px] text-ink/40" style={{ top: `${(i / totalH) * 100}%` }}>
              {(startH + i) % 12 || 12}{startH + i < 12 ? "a" : "p"}
            </div>
          ))}
        </div>
        {days.map((d, di) => {
          const dayBookings = bookings.filter(b => sameDay(b._start, d));
          return (
            <div key={di} className="relative border-l border-ink/[0.06]">
              {Array.from({length: totalH}, (_, i) => (
                <div key={i} className="absolute left-0 right-0 border-b border-ink/[0.04]" style={{ top: `${(i / totalH) * 100}%`, height: `${(1 / totalH) * 100}%` }} />
              ))}
              {sameDay(d, today) && nowOffset > 0 && nowOffset < 100 && (
                <div className="absolute left-0 right-0 z-10" style={{ top: `${nowOffset}%` }}>
                  <div className="h-px bg-accent" />
                  <div className="absolute -left-1 -top-1 h-2 w-2 rounded-full bg-accent" />
                </div>
              )}
              {dayBookings.map(b => {
                const startMin = b._start.getHours() + b._start.getMinutes()/60;
                const top = (startMin - startH) / totalH * 100;
                const height = Math.max(2.5, (b.duration_min / 60) / totalH * 100);
                const accent = statusColor(b.status);
                return (
                  <button
                    key={b.id}
                    onClick={() => onPick(b)}
                    className="absolute left-1 right-1 rounded-md border bg-white hover:bg-ink/[0.04] border-ink/[0.08] p-1.5 text-left overflow-hidden transition shadow-card"
                    style={{ top: `${top}%`, height: `${height}%`, borderLeft: `3px solid ${accent}` }}
                  >
                    <div className="text-[11px] font-medium truncate">{b.customers?.name || "—"}</div>
                    <div className="text-[10.5px] text-ink/55 truncate">{fmt(b._start, "h:mma").toLowerCase()} · {formTitle(b.form_id)}</div>
                  </button>
                );
              })}
              {blocksForDay(d).map(tb => {
                const bs = new Date(tb.starts_at);
                const be = new Date(tb.ends_at);
                const ds = new Date(d); ds.setHours(0,0,0,0);
                const de = new Date(ds); de.setDate(de.getDate() + 1);
                const visibleStart = bs < ds ? ds : bs;
                const visibleEnd   = be > de ? de : be;
                const startMin = visibleStart.getHours() + visibleStart.getMinutes()/60;
                const endMin   = visibleEnd.getDate() > ds.getDate() ? endH : (visibleEnd.getHours() + visibleEnd.getMinutes()/60);
                const top = Math.max(0, (startMin - startH) / totalH * 100);
                const height = Math.max(1.5, Math.min(100 - top, (endMin - startMin) / totalH * 100));
                return (
                  <button
                    key={tb.id}
                    onClick={() => onRemoveBlock && onRemoveBlock(tb.id)}
                    title={`Blocked${tb.label ? `: ${tb.label}` : ""} — click to remove`}
                    className="absolute left-1 right-1 rounded-md text-left overflow-hidden bg-ink/[0.06] hover:bg-ink/[0.10] border border-dashed border-ink/[0.25] transition"
                    style={{ top: `${top}%`, height: `${height}%` }}
                  >
                    <div className="px-1.5 py-1 flex items-center gap-1 text-[10.5px] text-ink/55">
                      <Icon name="ban" size={10} />
                      <span className="truncate">{tb.label || "Blocked"}</span>
                    </div>
                  </button>
                );
              })}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── Day ───────────────────────────────────────────────────────────────────
function DayView({ anchor, bookings, formTitle, onPick, blocks, onRemoveBlock }) {
  const dayBookings = bookings.filter(b => sameDay(b._start, anchor)).sort((a, b) => a._start - b._start);
  const startH = 7, endH = 21, totalH = endH - startH;
  const today = new Date();
  const nowOffset = sameDay(anchor, today) ? ((today.getHours() + today.getMinutes()/60) - startH) / totalH * 100 : -1;
  const dayBlocks = (blocks || []).filter(b => {
    const bs = new Date(b.starts_at), be = new Date(b.ends_at);
    const ds = new Date(anchor); ds.setHours(0,0,0,0);
    const de = new Date(ds); de.setDate(de.getDate() + 1);
    return bs < de && be > ds;
  });

  return (
    <div className="rounded-lg border border-ink/[0.06] overflow-hidden bg-white">
      <div className="grid grid-cols-[72px_1fr] relative" style={{ height: 920 }}>
        <div className="relative">
          {Array.from({length: totalH + 1}, (_, i) => (
            <div key={i} className="absolute -translate-y-1/2 right-3 text-[11px] text-ink/50" style={{ top: `${(i / totalH) * 100}%` }}>
              {(startH + i) % 12 || 12}:00 {startH + i < 12 ? "AM" : "PM"}
            </div>
          ))}
        </div>
        <div className="relative border-l border-ink/[0.06]">
          {Array.from({length: totalH}, (_, i) => (
            <div key={i} className="absolute left-0 right-0 border-b border-ink/[0.04]" style={{ top: `${(i / totalH) * 100}%`, height: `${(1 / totalH) * 100}%` }} />
          ))}
          {nowOffset >= 0 && nowOffset < 100 && (
            <div className="absolute left-0 right-0 z-10" style={{ top: `${nowOffset}%` }}>
              <div className="h-px bg-accent" />
              <div className="absolute -left-1 -top-1 h-2 w-2 rounded-full bg-accent" />
            </div>
          )}
          {dayBookings.map(b => {
            const startMin = b._start.getHours() + b._start.getMinutes()/60;
            const top = (startMin - startH) / totalH * 100;
            const height = Math.max(3, (b.duration_min / 60) / totalH * 100);
            const accent = statusColor(b.status);
            return (
              <button
                key={b.id}
                onClick={() => onPick(b)}
                className="absolute left-3 right-3 rounded-md border bg-white hover:bg-ink/[0.04] border-ink/[0.08] p-3 text-left transition shadow-card"
                style={{ top: `${top}%`, height: `${height}%`, borderLeft: `3px solid ${accent}` }}
              >
                <div className="flex items-center justify-between gap-3">
                  <div className="text-[13.5px] font-medium truncate">{b.customers?.name || "—"}</div>
                  <StatusBadge status={b.status} />
                </div>
                <div className="text-[12px] text-ink/65 mt-0.5">{fmt(b._start, "h:mma").toLowerCase()} – {fmt(new Date(b._start.getTime() + b.duration_min*60000), "h:mma").toLowerCase()} · {formTitle(b.form_id)}</div>
              </button>
            );
          })}
          {dayBlocks.map(tb => {
            const bs = new Date(tb.starts_at);
            const be = new Date(tb.ends_at);
            const ds = new Date(anchor); ds.setHours(0,0,0,0);
            const de = new Date(ds); de.setDate(de.getDate() + 1);
            const visibleStart = bs < ds ? ds : bs;
            const visibleEnd   = be > de ? de : be;
            const startMin = visibleStart.getHours() + visibleStart.getMinutes()/60;
            const endMin   = visibleEnd.getDate() > ds.getDate() ? endH : (visibleEnd.getHours() + visibleEnd.getMinutes()/60);
            const top = Math.max(0, (startMin - startH) / totalH * 100);
            const height = Math.max(2, Math.min(100 - top, (endMin - startMin) / totalH * 100));
            return (
              <button
                key={tb.id}
                onClick={() => onRemoveBlock && onRemoveBlock(tb.id)}
                title="Click to remove"
                className="absolute left-3 right-3 rounded-md text-left overflow-hidden bg-ink/[0.06] hover:bg-ink/[0.10] border border-dashed border-ink/[0.25] transition"
                style={{ top: `${top}%`, height: `${height}%` }}
              >
                <div className="px-3 py-2 text-[12px] text-ink/65 flex items-center gap-2">
                  <Icon name="ban" size={12} />
                  <span>Blocked{tb.label ? ` · ${tb.label}` : ""}</span>
                  <span className="ml-auto text-[11px] text-ink/45">{fmt(bs, "h:mma").toLowerCase()} – {fmt(be, "h:mma").toLowerCase()}</span>
                </div>
              </button>
            );
          })}
          {dayBookings.length === 0 && dayBlocks.length === 0 && (
            <div className="absolute inset-0 grid place-items-center text-[13px] text-ink/45">
              No bookings on this day.
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function DL({ label, children }) {
  return (
    <div>
      <dt className="text-[11px] uppercase tracking-[0.08em] text-ink/50">{label}</dt>
      <dd className="mt-1 text-ink/90">{children}</dd>
    </div>
  );
}

function weekStart(d) { const r = new Date(d); r.setDate(d.getDate() - d.getDay()); r.setHours(0,0,0,0); return r; }
function weekEnd(d)   { const r = weekStart(d); r.setDate(r.getDate() + 6); return r; }

Object.assign(window, { CalendarPage, FilterChip, DL });
