// Shared UI components — Apple-style light theme
const { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext } = React;

// ── Icon ──────────────────────────────────────────────────────────────────
function Icon({ name, size = 16, className = "", strokeWidth = 1.5, style }) {
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current || !window.lucide) return;
    ref.current.innerHTML = "";
    const pascal = name.split("-").map(s => s[0].toUpperCase() + s.slice(1)).join("");
    const def = window.lucide.icons[pascal] || window.lucide.icons.Circle;
    const svg = window.lucide.createElement
      ? window.lucide.createElement(def)
      : null;
    if (svg) {
      svg.setAttribute("width", size);
      svg.setAttribute("height", size);
      svg.setAttribute("stroke-width", strokeWidth);
      ref.current.appendChild(svg);
    } else {
      const i = document.createElement("i");
      i.setAttribute("data-lucide", name);
      ref.current.appendChild(i);
      window.lucide.createIcons({ attrs: { width: size, height: size, "stroke-width": strokeWidth } });
    }
  }, [name, size, strokeWidth]);
  return <span ref={ref} className={"inline-flex items-center " + className} style={{ lineHeight: 0, ...style }} aria-hidden="true" />;
}

// ── V Mark ────────────────────────────────────────────────────────────────
function VMark({ size = 24, color = "currentColor", className = "" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" className={className} fill="none" aria-hidden="true">
      <path d="M4 4 L12 20 L20 4" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ── Button — Apple-style pill ─────────────────────────────────────────────
function Button({ variant = "primary", size = "md", icon, iconRight, children, className = "", disabled, ...props }) {
  const base = "inline-flex items-center justify-center gap-1.5 rounded-full font-medium select-none disabled:opacity-40 disabled:pointer-events-none whitespace-nowrap";
  const sizes = {
    sm: "h-7 px-3 text-[12px]",
    md: "h-9 px-4 text-[13px]",
    lg: "h-11 px-5 text-[14px]"
  };
  const variants = {
    primary:   "bg-ink text-white hover:bg-ink/90",
    secondary: "bg-white text-ink border border-ink/10 hover:bg-ink/[0.03]",
    ghost:     "text-ink/75 hover:text-ink hover:bg-ink/[0.05]",
    outline:   "bg-transparent text-ink border border-ink/15 hover:bg-ink/[0.04]",
    accent:    "bg-accent text-white hover:bg-accentdim",
    danger:    "bg-white text-danger border border-danger/30 hover:bg-danger/[0.05]"
  };
  return (
    <button className={`${base} ${sizes[size]} ${variants[variant] || variants.primary} ${className}`} disabled={disabled} {...props}>
      {icon && <Icon name={icon} size={size === "sm" ? 12 : 13} />}
      {children}
      {iconRight && <Icon name={iconRight} size={size === "sm" ? 12 : 13} />}
    </button>
  );
}

// ── Badge ─────────────────────────────────────────────────────────────────
function Badge({ tone = "neutral", children, className = "", dot }) {
  const tones = {
    neutral: "bg-ink/[0.04] text-ink/75 border border-transparent",
    accent:  "bg-[#E8F1FD] text-[#0058B0]",
    ok:      "bg-[#E5F2EB] text-[#1D6F42]",
    warn:    "bg-[#FBF0DE] text-[#7A521B]",
    danger:  "bg-[#FBE4E5] text-[#8E1A1B]",
    paper:   "bg-ink/[0.05] text-ink/80"
  };
  const dotColors = {
    ok: "#1D6F42", warn: "#A6741A", danger: "#A0292A", accent: "#0071E3", neutral: "#86868B", paper: "#86868B"
  };
  return (
    <span className={`inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-[11px] font-medium ${tones[tone] || tones.neutral} ${className}`}>
      {dot && <span className="h-1.5 w-1.5 rounded-full" style={{ background: dotColors[tone] }} />}
      {children}
    </span>
  );
}

// ── Card ──────────────────────────────────────────────────────────────────
function Card({ children, className = "", padded = true }) {
  return <div className={`bg-white border border-ink/[0.06] rounded-xl shadow-card ${padded ? "p-5" : ""} ${className}`}>{children}</div>;
}

function GlassPanel({ children, className = "" }) {
  return <div className={`glass rounded-xl ${className}`}>{children}</div>;
}

// ── StatCard ──────────────────────────────────────────────────────────────
function StatCard({ label, value, delta, hint, icon }) {
  return (
    <div className="bg-white border border-ink/[0.06] rounded-xl shadow-card p-5">
      <div className="flex items-center justify-between">
        <span className="text-[12px] text-ink/55">{label}</span>
        {icon && <Icon name={icon} size={14} className="text-ink/35" />}
      </div>
      <div className="mt-2 flex items-baseline gap-2">
        <span className="font-display text-[34px] leading-none text-ink tracking-tight">{value}</span>
        {delta && <span className="text-[12px] text-ink/55">{delta}</span>}
      </div>
      {hint && <div className="mt-1.5 text-[12px] text-ink/45">{hint}</div>}
    </div>
  );
}

// ── Toggle — iOS-style ────────────────────────────────────────────────────
function Toggle({ checked, onChange, label, hint, size = "md" }) {
  const sm    = size === "sm";
  const track = sm ? "w-8 h-[18px]"        : "w-[42px] h-[26px]";
  const knob  = sm ? "h-[14px] w-[14px]"   : "h-[22px] w-[22px]";
  // Slide distance = track_w - knob_w - 4px (2px gap on each side).
  const slide = sm ? "translate-x-[14px]" : "translate-x-[16px]";
  return (
    <label className="inline-flex items-center gap-3 cursor-pointer">
      <button
        type="button"
        role="switch"
        aria-checked={checked}
        onClick={() => onChange(!checked)}
        className={`relative shrink-0 p-0 text-left align-middle ${track} rounded-full transition-colors ${checked ? "bg-[#34C759]" : "bg-ink/15"}`}
      >
        <span className={`absolute left-0 top-0 m-[2px] ${knob} rounded-full bg-white shadow-[0_2px_4px_rgba(0,0,0,0.18)] transition-transform ${checked ? slide : "translate-x-0"}`} />
      </button>
      {(label || hint) && (
        <div className="flex flex-col">
          {label && <span className="text-[13px]">{label}</span>}
          {hint && <span className="text-[12px] text-ink/50">{hint}</span>}
        </div>
      )}
    </label>
  );
}

// ── Field / Input / Textarea / Select ─────────────────────────────────────
function Field({ label, hint, error, children, required, action, className = "" }) {
  return (
    <label className={`flex flex-col gap-1.5 ${className}`}>
      {label && (
        <div className="flex items-center justify-between">
          <span className="text-[12px] font-medium text-ink/70">
            {label}{required && <span className="text-ink/30"> *</span>}
          </span>
          {action}
        </div>
      )}
      {children}
      {hint && !error && <span className="text-[11px] text-ink/45">{hint}</span>}
      {error && <span className="text-[11px] text-danger">{error}</span>}
    </label>
  );
}

function Input({ className = "", ...props }) {
  return <input
    className={`h-9 rounded-lg px-3 text-[13px] bg-white border border-ink/[0.12] focus:border-accent/60 focus:bg-white text-ink placeholder-ink/30 transition outline-none focus-ring ${className}`}
    {...props} />;
}
function Textarea({ className = "", ...props }) {
  return <textarea
    className={`rounded-lg p-3 text-[13px] min-h-[72px] resize-y bg-white border border-ink/[0.12] focus:border-accent/60 text-ink placeholder-ink/30 transition outline-none focus-ring ${className}`}
    {...props} />;
}
function Select({ className = "", children, ...props }) {
  return (
    <div className="relative">
      <select
        className={`h-9 w-full rounded-lg pl-3 pr-8 text-[13px] bg-white border border-ink/[0.12] focus:border-accent/60 text-ink transition outline-none focus-ring ${className}`}
        {...props}
      >{children}</select>
      <Icon name="chevron-down" size={12} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-ink/45 pointer-events-none" />
    </div>
  );
}

// ── Drawer ────────────────────────────────────────────────────────────────
function Drawer({ open, onClose, children, title, subtitle, width = 480, actions }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex justify-end fade-in">
      <div className="absolute inset-0 bg-ink/30 backdrop-blur-[2px]" onClick={onClose} />
      <div className="relative drawer-anim bg-white shadow-lift flex flex-col" style={{ width }}>
        <div className="flex items-start justify-between px-6 py-5 border-b border-ink/[0.06]">
          <div>
            {subtitle && <div className="text-[11px] uppercase tracking-[0.08em] text-ink/45 mb-1">{subtitle}</div>}
            {title && <div className="font-display text-2xl">{title}</div>}
          </div>
          <button onClick={onClose} className="text-ink/55 hover:text-ink -mt-1 -mr-1 h-8 w-8 grid place-items-center rounded-full hover:bg-ink/[0.05]">
            <Icon name="x" size={16} />
          </button>
        </div>
        <div className="flex-1 overflow-y-auto px-6 py-5">{children}</div>
        {actions && <div className="px-6 py-4 border-t border-ink/[0.06] flex items-center justify-end gap-2">{actions}</div>}
      </div>
    </div>
  );
}

// ── Modal ─────────────────────────────────────────────────────────────────
function Modal({ open, onClose, children, title, subtitle, width = 480, actions }) {
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center fade-in p-4">
      <div className="absolute inset-0 bg-ink/40 backdrop-blur-[2px]" onClick={onClose} />
      <div className="relative rounded-2xl shadow-lift flex flex-col max-h-[88vh] bg-white text-ink" style={{ width: "100%", maxWidth: width }}>
        <div className="flex items-start justify-between px-5 py-4 border-b border-ink/[0.06]">
          <div>
            {subtitle && <div className="text-[11px] uppercase tracking-[0.08em] mb-1 text-ink/45">{subtitle}</div>}
            {title && <div className="font-display text-xl">{title}</div>}
          </div>
          <button onClick={onClose} className="-mt-1 -mr-1 h-8 w-8 grid place-items-center rounded-full text-ink/55 hover:text-ink hover:bg-ink/[0.05]">
            <Icon name="x" size={16} />
          </button>
        </div>
        <div className="flex-1 overflow-y-auto px-5 py-4">{children}</div>
        {actions && <div className="px-5 py-3 border-t border-ink/[0.06] flex items-center justify-end gap-2">{actions}</div>}
      </div>
    </div>
  );
}

// ── EmptyState ────────────────────────────────────────────────────────────
function EmptyState({ icon = "inbox", title, body, action }) {
  return (
    <div className="flex flex-col items-center justify-center text-center py-14 px-6 rounded-xl bg-white border border-dashed border-ink/[0.10]">
      <div className="h-12 w-12 rounded-full grid place-items-center mb-4 bg-ink/[0.04] text-ink/55">
        <Icon name={icon} size={18} />
      </div>
      <div className="font-display text-xl mb-1.5">{title}</div>
      {body && <div className="text-[13px] max-w-sm text-ink/55">{body}</div>}
      {action && <div className="mt-5">{action}</div>}
    </div>
  );
}

// ── PageHeader ────────────────────────────────────────────────────────────
function PageHeader({ eyebrow, title, subtitle, actions, children }) {
  return (
    <div className="flex flex-wrap items-end justify-between gap-4 mb-7">
      <div className="min-w-0">
        {eyebrow && <div className="text-[12px] text-ink/45 mb-1.5">{eyebrow}</div>}
        <h1 className="font-display text-[34px] leading-[1.1] tracking-tight text-ink">{title}</h1>
        {subtitle && <p className="mt-1.5 text-[14px] text-ink/55 max-w-2xl">{subtitle}</p>}
        {children}
      </div>
      {actions && <div className="flex items-center gap-2 flex-shrink-0">{actions}</div>}
    </div>
  );
}

// ── Tabs — segmented control ──────────────────────────────────────────────
function Tabs({ value, onChange, options }) {
  return (
    <div className="inline-flex rounded-full p-1 bg-ink/[0.05]">
      {options.map((o) => {
        const active = value === o.value;
        return (
          <button
            key={o.value}
            onClick={() => onChange(o.value)}
            className={`px-3.5 h-7 rounded-full text-[12px] font-medium transition ${active ? "bg-white text-ink shadow-card" : "text-ink/60 hover:text-ink"}`}
          >
            {o.label}
          </button>
        );
      })}
    </div>
  );
}

// ── Avatar ────────────────────────────────────────────────────────────────
function Avatar({ name, initials, size = 28 }) {
  const text = initials || (name ? name.split(/\s+/).slice(0,2).map(s=>s[0]).join("") : "??");
  return (
    <span
      className="inline-flex items-center justify-center rounded-full bg-ink/[0.06] text-ink/80 font-medium"
      style={{ width: size, height: size, fontSize: size * 0.4 }}
    >
      {text.toUpperCase()}
    </span>
  );
}

// ── Status badge ──────────────────────────────────────────────────────────
function StatusBadge({ status }) {
  const map = {
    confirmed:  { tone: "ok",      label: "Confirmed" },
    pending:    { tone: "warn",    label: "Pending"   },
    cancelled:  { tone: "danger",  label: "Cancelled" },
    completed:  { tone: "neutral", label: "Completed" },
    Live:       { tone: "ok",      label: "Live" },
    Onboarding: { tone: "warn",    label: "Onboarding" },
    Paused:     { tone: "neutral", label: "Paused" },
    Published:  { tone: "ok",      label: "Published" },
    Draft:      { tone: "neutral", label: "Draft" },
    Full:       { tone: "accent",  label: "Full" },
    Cancelled:  { tone: "danger",  label: "Cancelled" }
  };
  const cfg = map[status] || { tone: "neutral", label: status };
  return <Badge tone={cfg.tone} dot>{cfg.label}</Badge>;
}

// ── Locked notice ─────────────────────────────────────────────────────────
function LockedNotice({ text = "Visual styling is managed by your Vale website template.", className = "" }) {
  return (
    <div className={`flex items-start gap-2.5 rounded-xl bg-[#F7F4ED] border border-[#E8DEC2] px-3.5 py-3 text-[12.5px] text-ink/75 ${className}`}>
      <Icon name="lock" size={13} className="text-[#A6741A] mt-0.5" />
      <span>{text}</span>
    </div>
  );
}

// ── Toast ─────────────────────────────────────────────────────────────────
const ToastCtx = createContext({ push: () => {} });
function ToastProvider({ children }) {
  const [list, setList] = useState([]);
  const push = useCallback((msg, opts = {}) => {
    const id = Math.random().toString(36).slice(2);
    setList((l) => [...l, { id, msg, ...opts }]);
    setTimeout(() => setList((l) => l.filter((t) => t.id !== id)), opts.duration || 3000);
  }, []);
  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="fixed bottom-6 right-6 z-[100] flex flex-col gap-2 max-w-sm">
        {list.map((t) => (
          <div key={t.id} className="glass rounded-full px-4 py-2.5 text-[13px] shadow-glass flex items-center gap-2 fade-in">
            <Icon name={t.icon || "check"} size={13} className="text-ok" />
            <span>{t.msg}</span>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}
const useToast = () => useContext(ToastCtx);

// ── Date helper ───────────────────────────────────────────────────────────
function fmt(date, p) {
  if (!date) return "";
  return dateFns.format(new Date(date), p);
}

// ── Owner-side manual booking modal ─────────────────────────────────────────
// Used from both the Dashboard "New booking" button and the Bookings list.
// Customer is upserted by (workspace_id, email); booking is inserted with
// status='confirmed' since the owner created it directly.
function NewBookingModal(props) {
  const auth = useAuth();
  const toast = useToast();
  const ws = auth.currentWorkspace;

  const [forms, setForms] = useState([]);
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [phone, setPhone] = useState("");
  const [formId, setFormId] = useState("");
  const [startsAt, setStartsAt] = useState("");
  const [durationMin, setDurationMin] = useState(60);
  const [notes, setNotes] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  // Load workspace forms (only published) when opening, so the owner can pick
  // a service or leave it blank for a custom one-off booking.
  useEffect(() => {
    if (!props.open || !ws?.id) return;
    let cancelled = false;
    (async () => {
      const res = await SB.from('forms')
        .select('id, name, public_title, duration_min, buffer_min')
        .eq('workspace_id', ws.id)
        .is('archived_at', null);
      if (cancelled) return;
      setForms(res.data || []);
    })();
    // reset form state on open
    setName(""); setEmail(""); setPhone("");
    setFormId(""); setStartsAt(""); setDurationMin(60);
    setNotes(""); setBusy(false); setError(null);
    return () => { cancelled = true; };
  }, [props.open, ws?.id]);

  // Auto-fill duration when a form is selected.
  const onPickForm = (id) => {
    setFormId(id);
    const f = forms.find(x => x.id === id);
    if (f && f.duration_min) setDurationMin(f.duration_min);
  };

  const canSubmit =
    !!ws?.id &&
    name.trim().length >= 2 &&
    /^.+@.+\..+$/.test(email.trim()) &&
    !!startsAt &&
    durationMin > 0 &&
    !busy;

  const submit = async () => {
    setBusy(true); setError(null);

    // Upsert customer by (workspace_id, email).
    const custRes = await SB.from('customers')
      .upsert(
        { workspace_id: ws.id, email: email.trim().toLowerCase(), name: name.trim(), phone: phone.trim() || null },
        { onConflict: 'workspace_id,email' }
      )
      .select()
      .single();
    if (custRes.error) {
      setBusy(false);
      setError("Couldn't create/find customer: " + custRes.error.message);
      return;
    }

    // Insert booking. Owner-created bookings are confirmed by default.
    const bkRes = await SB.from('bookings').insert({
      workspace_id: ws.id,
      customer_id: custRes.data.id,
      form_id: formId || null,
      starts_at: startsAt,
      duration_min: durationMin,
      status: 'confirmed',
      source: 'manual',
      notes: notes || '',
      answers: []
    }).select().single();

    if (bkRes.error) {
      setBusy(false);
      setError("Couldn't create booking: " + bkRes.error.message);
      return;
    }

    // Log activity (best-effort).
    await SB.from('activity').insert({
      workspace_id: ws.id,
      kind: 'booking',
      text: `${name.trim()} added by team (manual)`,
      ref_id: bkRes.data.id
    });

    setBusy(false);
    toast.push("Booking created");
    if (props.onCreated) props.onCreated(bkRes.data);
  };

  return (
    <Modal
      open={props.open}
      onClose={props.onClose}
      title="New booking"
      subtitle="Create a booking on behalf of a customer."
      width={560}
      actions={
        <>
          <Button variant="ghost" onClick={props.onClose} disabled={busy}>Cancel</Button>
          <Button icon="check" onClick={submit} disabled={!canSubmit}>{busy ? "Creating…" : "Create booking"}</Button>
        </>
      }
    >
      <div className="flex flex-col gap-4">
        <div className="grid sm:grid-cols-2 gap-3">
          <Field label="Customer name" required>
            <Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Marcus Whitfield" autoFocus />
          </Field>
          <Field label="Phone">
            <Input value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="+32 …" />
          </Field>
          <Field label="Email" required className="sm:col-span-2" hint="If a customer with this email exists, they'll be reused.">
            <Input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="marcus@example.com" />
          </Field>
        </div>

        <div className="grid sm:grid-cols-2 gap-3">
          <Field label="Service / form" hint="Optional. Picks the duration for you.">
            <Select value={formId} onChange={(e) => onPickForm(e.target.value)}>
              <option value="">No form — custom booking</option>
              {forms.map(f => <option key={f.id} value={f.id}>{f.public_title || f.name}</option>)}
            </Select>
          </Field>
          <Field label="Duration (minutes)" required>
            <Input type="number" value={durationMin} onChange={(e) => setDurationMin(Math.max(5, +e.target.value || 0))} />
          </Field>
        </div>

        <Field label="Starts at" required>
          <DateTimePicker value={startsAt} onChange={setStartsAt} />
        </Field>

        <Field label="Internal note" hint="Optional — visible only to your team.">
          <Textarea value={notes} onChange={(e) => setNotes(e.target.value)} placeholder="Anything the team should know about this booking…" />
        </Field>

        {error && (
          <div className="text-[12px] text-danger bg-danger/[0.06] border border-danger/15 rounded-md px-3 py-2">{error}</div>
        )}
      </div>
    </Modal>
  );
}

// ── Block-time modal ────────────────────────────────────────────────────────
// Inserts a row into `time_blocks`. The public booking page treats these as
// busy intervals so customers can't book over them.
function TimeBlockModal(props) {
  const auth = useAuth();
  const toast = useToast();
  const ws = auth.currentWorkspace;

  const [startsAt, setStartsAt] = useState("");
  const [endsAt, setEndsAt] = useState("");
  const [label, setLabel] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!props.open) return;
    setStartsAt(""); setEndsAt(""); setLabel("");
    setBusy(false); setError(null);
  }, [props.open]);

  const canSubmit = !!ws?.id && !!startsAt && !!endsAt && new Date(endsAt) > new Date(startsAt) && !busy;

  const submit = async () => {
    setBusy(true); setError(null);
    const res = await SB.from('time_blocks').insert({
      workspace_id: ws.id,
      starts_at: startsAt,
      ends_at: endsAt,
      label: label.trim()
    }).select().single();
    setBusy(false);
    if (res.error) { setError(res.error.message); return; }
    toast.push("Time blocked");
    if (props.onCreated) props.onCreated(res.data);
  };

  return (
    <Modal
      open={props.open}
      onClose={props.onClose}
      title="Block time"
      subtitle="Mark a period as unavailable for new bookings."
      width={520}
      actions={
        <>
          <Button variant="ghost" onClick={props.onClose} disabled={busy}>Cancel</Button>
          <Button icon="check" onClick={submit} disabled={!canSubmit}>{busy ? "Saving…" : "Block time"}</Button>
        </>
      }
    >
      <div className="flex flex-col gap-4">
        <div className="grid sm:grid-cols-2 gap-3">
          <Field label="From" required>
            <DateTimePicker
              value={startsAt}
              onChange={(iso) => {
                const s = new Date(iso);
                const e = endsAt ? new Date(endsAt) : null;
                if (!e || e <= s) {
                  const newEnd = new Date(s); newEnd.setHours(newEnd.getHours() + 1);
                  setEndsAt(newEnd.toISOString());
                }
                setStartsAt(iso);
              }}
            />
          </Field>
          <Field label="To" required>
            <DateTimePicker value={endsAt} minDate={startsAt} onChange={setEndsAt} />
          </Field>
        </div>
        <Field label="Label" hint="Optional — e.g. Lunch, Holiday, Training.">
          <Input value={label} onChange={(e) => setLabel(e.target.value)} placeholder="What's this for?" />
        </Field>
        {error && (
          <div className="text-[12px] text-danger bg-danger/[0.06] border border-danger/15 rounded-md px-3 py-2">{error}</div>
        )}
      </div>
    </Modal>
  );
}

// Apple-style date + time picker. Displays DD/MM/YYYY · HH:MM regardless of
// browser locale, supports a `minDate` floor (used so end-date can't be set
// before start-date), and shows a clean popover calendar instead of the
// stock OS chrome.
function DateTimePicker(props) {
  const value     = props.value;
  const onChange  = props.onChange;
  const minDate   = props.minDate;
  const ariaLabel = props.ariaLabel;

  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);

  const selected = value ? new Date(value) : null;
  const min      = minDate ? new Date(minDate) : null;

  const [viewMonth, setViewMonth] = useState(() => {
    const d = selected ? new Date(selected) : new Date();
    d.setDate(1); d.setHours(0, 0, 0, 0);
    return d;
  });

  useEffect(() => {
    if (selected) {
      const m = new Date(selected); m.setDate(1); m.setHours(0,0,0,0);
      if (m.getTime() !== viewMonth.getTime()) setViewMonth(m);
    }
  }, [value]);

  useEffect(() => {
    if (!open) return;
    const handler = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  const pad = (n) => String(n).padStart(2, "0");
  const sameDayCheck = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();

  const display = selected
    ? `${pad(selected.getDate())}/${pad(selected.getMonth()+1)}/${selected.getFullYear()} · ${pad(selected.getHours())}:${pad(selected.getMinutes())}`
    : "";

  // Build Monday-first day grid for the viewed month.
  const firstOfMonth = new Date(viewMonth);
  firstOfMonth.setDate(1);
  const startOffset = (firstOfMonth.getDay() + 6) % 7; // 0 = Mon
  const daysInMonth = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + 1, 0).getDate();
  const grid = [];
  for (let i = 0; i < startOffset; i++) grid.push(null);
  for (let d = 1; d <= daysInMonth; d++) {
    const dt = new Date(viewMonth); dt.setDate(d); grid.push(dt);
  }
  while (grid.length < 42) grid.push(null);

  const isDisabled = (d) => {
    if (!min) return false;
    const a = new Date(d.getFullYear(), d.getMonth(), d.getDate());
    const b = new Date(min.getFullYear(), min.getMonth(), min.getDate());
    return a < b;
  };
  const today = new Date();

  const setDay = (d) => {
    if (isDisabled(d)) return;
    const next = new Date(d);
    if (selected) next.setHours(selected.getHours(), selected.getMinutes(), 0, 0);
    else          next.setHours(9, 0, 0, 0);
    if (min && next < min) next.setTime(min.getTime());
    onChange(next.toISOString());
  };

  const setTime = (h, m) => {
    if (!selected) return;
    const next = new Date(selected);
    next.setHours(Math.max(0, Math.min(23, h)), Math.max(0, Math.min(59, m)), 0, 0);
    if (min && next < min) next.setTime(min.getTime());
    onChange(next.toISOString());
  };

  const shiftMonth = (delta) => {
    const next = new Date(viewMonth);
    next.setMonth(next.getMonth() + delta);
    setViewMonth(next);
  };

  return (
    <div className="relative" ref={wrapRef}>
      <button
        type="button"
        aria-label={ariaLabel || "Pick date and time"}
        onClick={() => setOpen(o => !o)}
        className="h-10 w-full px-3 text-left bg-white border border-ink/[0.15] rounded-md text-[13px] outline-none focus:border-ink/40 hover:border-ink/[0.30] inline-flex items-center gap-2 transition"
      >
        <Icon name="calendar" size={13} className="text-ink/55" />
        <span className={selected ? "text-ink" : "text-ink/40"}>{selected ? display : "Pick a date"}</span>
        <Icon name="chevron-down" size={11} className="ml-auto text-ink/45" />
      </button>

      {open && (
        <div className="absolute left-0 top-full mt-1.5 z-50 w-[300px] rounded-xl border border-ink/[0.08] bg-white shadow-lift p-3">
          <div className="flex items-center justify-between mb-2">
            <button type="button" onClick={() => shiftMonth(-1)} className="h-7 w-7 grid place-items-center rounded-md hover:bg-ink/[0.05] text-ink/65">
              <Icon name="chevron-left" size={12} />
            </button>
            <div className="text-[13px] font-medium tracking-tight">{fmt(viewMonth, "MMMM yyyy")}</div>
            <button type="button" onClick={() => shiftMonth(1)} className="h-7 w-7 grid place-items-center rounded-md hover:bg-ink/[0.05] text-ink/65">
              <Icon name="chevron-right" size={12} />
            </button>
          </div>

          <div className="grid grid-cols-7 gap-0.5 text-center text-[10px] uppercase tracking-[0.08em] text-ink/45 mb-1">
            {["Mo","Tu","We","Th","Fr","Sa","Su"].map(d => <div key={d} className="py-1">{d}</div>)}
          </div>
          <div className="grid grid-cols-7 gap-0.5">
            {grid.map((d, i) => {
              if (!d) return <div key={i} />;
              const dis  = isDisabled(d);
              const sel  = selected && sameDayCheck(d, selected);
              const tdy  = sameDayCheck(d, today);
              return (
                <button
                  key={i}
                  type="button"
                  onClick={() => setDay(d)}
                  disabled={dis}
                  className={`h-8 grid place-items-center rounded-md text-[12.5px] transition ${
                    sel ? "bg-ink text-white font-medium" :
                    dis ? "text-ink/25 cursor-not-allowed" :
                    tdy ? "border border-ink/25 text-ink hover:bg-ink/[0.04]" :
                    "text-ink/85 hover:bg-ink/[0.05]"
                  }`}
                >
                  {d.getDate()}
                </button>
              );
            })}
          </div>

          <div className="mt-3 pt-3 border-t border-ink/[0.06] flex items-center gap-2">
            <Icon name="clock" size={12} className="text-ink/55" />
            <div className="flex items-center gap-1">
              <input
                type="number" min="0" max="23"
                value={selected ? pad(selected.getHours()) : ""}
                onChange={(e) => setTime(+e.target.value || 0, selected ? selected.getMinutes() : 0)}
                disabled={!selected}
                className="h-7 w-12 px-1 text-center text-[13px] border border-ink/[0.10] rounded-md outline-none focus:border-ink/30 disabled:opacity-40"
              />
              <span className="text-ink/40">:</span>
              <input
                type="number" min="0" max="59" step="5"
                value={selected ? pad(selected.getMinutes()) : ""}
                onChange={(e) => setTime(selected ? selected.getHours() : 9, +e.target.value || 0)}
                disabled={!selected}
                className="h-7 w-12 px-1 text-center text-[13px] border border-ink/[0.10] rounded-md outline-none focus:border-ink/30 disabled:opacity-40"
              />
            </div>
            <button
              type="button"
              onClick={() => setOpen(false)}
              className="ml-auto h-7 px-3 text-[12px] rounded-md bg-ink text-white hover:bg-ink/90"
            >
              Done
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

// Uncontrolled variant of <Toggle> — holds its own state. Use this on
// placeholder/visual settings rows that aren't yet wired to backend state, so
// the switch at least *moves* when the user clicks it.
function LocalToggle(props) {
  const [on, setOn] = useState(!!props.defaultChecked);
  return (
    <Toggle
      checked={on}
      onChange={(v) => { setOn(v); if (props.onChange) props.onChange(v); }}
      size={props.size}
      label={props.label}
      hint={props.hint}
    />
  );
}

Object.assign(window, {
  Icon, VMark,
  Button, Badge, Card, GlassPanel, StatCard, Toggle, LocalToggle, DateTimePicker,
  Field, Input, Textarea, Select,
  Drawer, Modal, EmptyState, PageHeader, Tabs, Avatar,
  StatusBadge, LockedNotice,
  ToastProvider, useToast,
  NewBookingModal, TimeBlockModal,
  fmt
});
