import { useEffect, useState, useRef, useCallback, useMemo } from "react";
import SignedImage from "@/components/SignedImage";
import BookingSuccessScreen from "@/components/client/BookingSuccessScreen";
import { useSearchParams, Link, useNavigate } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/contexts/AuthContext";
import DashboardLayout from "@/components/DashboardLayout";
import { clientNavItems } from "@/components/client/clientNav";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { Calendar } from "@/components/ui/calendar";
import { Checkbox } from "@/components/ui/checkbox";
import { useToast } from "@/hooks/use-toast";
import { cn } from "@/lib/utils";
import BookingProgress from "@/components/client/BookingProgress";
import BookingChat from "@/components/client/BookingChat";
import BookingModeChooser from "@/components/client/BookingModeChooser";
import BookingEstimate from "@/components/client/BookingEstimate";
import BookingPetSelector from "@/components/client/BookingPetSelector";
import PetPhotoGrid from "@/components/client/PetPhotoGrid";
import ActiveBookingsBanner from "@/components/client/ActiveBookingsBanner";
import {
  CalendarIcon, CheckCircle2, Home, MapPin, Sparkles,
  Heart, Star, ArrowRight, ArrowLeft, Send, MessageCircle, FileText,
  Loader2, PawPrint, AlertCircle, Mic, MicOff, ChevronDown, ChevronUp,
  Repeat, Gift, Check, Clock, Sunrise, Sun, Sunset, Moon,
  UtensilsCrossed, Droplets, CatIcon, Mail, Phone,
} from "lucide-react";
import StructuredPhoneInput, { stripPhone, toE164, parsePhone } from "@/components/client/StructuredPhoneInput";
import { format, differenceInDays, addDays, addWeeks, addMonths, formatDistanceToNow, differenceInHours } from "date-fns";
import { sendAdminAlert, sendSmsNotification } from "@/lib/admin-alerts";

type ServiceOption = {
  id: string;
  service_type: string;
  base_price: number;
  modifiers: any;
  additional_pet_fee?: number;
};

type ChatMessage = {
  role: "user" | "assistant";
  content: string;
  toolCall?: any;
};

const serviceIcons: Record<string, any> = {
  overnight_stay: Home,
  in_home_stay: Home,
  daily_visit: MapPin,
  drop_in: MapPin,
  dog_walking: MapPin,
  special_care: Heart,
  senior_care: Heart,
};

const SERVICE_ALIAS: Record<string, string> = {
  overnight: "stay",
  dropin: "drop_in",
  walking: "walk",
  daycare: "daily_visit",
  special: "special_care",
  puppy: "special_care",
};

const SINGLE_DAY_SERVICES = ["drop_in", "walk", "dog_walking"];
const isSingleDayService = (serviceType: string) => SINGLE_DAY_SERVICES.includes(serviceType);
const isWalkService = (serviceType: string) => ["walk", "dog_walking", "drop_in"].includes(serviceType);

type TimeSlot = "morning" | "midday" | "afternoon" | "evening";
const TIME_SLOTS: { value: TimeSlot; label: string; range: string; icon: any }[] = [
  { value: "morning", label: "Morning", range: "7:00–10:00", icon: Sunrise },
  { value: "midday", label: "Midday", range: "11:00–14:00", icon: Sun },
  { value: "afternoon", label: "Afternoon", range: "14:00–17:00", icon: Sunset },
  { value: "evening", label: "Evening", range: "17:00–20:00", icon: Moon },
];

const SPECIFIC_TIMES = Array.from({ length: 27 }, (_, i) => {
  const h = Math.floor(i / 2) + 7;
  const m = i % 2 === 0 ? "00" : "30";
  return `${h.toString().padStart(2, "0")}:${m}`;
}).filter((t) => t <= "20:00");

const formatTime12 = (time: string) => {
  const [h, m] = time.split(":").map(Number);
  const suffix = h >= 12 ? "PM" : "AM";
  const hour12 = h === 0 ? 12 : h > 12 ? h - 12 : h;
  return `${hour12}:${m.toString().padStart(2, "0")} ${suffix}`;
};

const resolveServiceType = (raw: string | null, available: ServiceOption[]): string => {
  if (!raw) return "";
  if (available.some((s) => s.service_type === raw)) return raw;
  const alias = SERVICE_ALIAS[raw];
  if (alias) {
    const match = available.find((s) => s.service_type.includes(alias));
    if (match) return match.service_type;
  }
  const partial = available.find((s) => s.service_type.includes(raw) || raw.includes(s.service_type));
  if (partial) return partial.service_type;
  return raw;
};

const CHAT_URL = `${import.meta.env.VITE_SUPABASE_URL}/functions/v1/booking-assistant`;
const BOOKING_STATE_KEY = "haven_booking_state";
const CRASH_RETENTION_KEY = "haven_booking_draft";
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
const PHONE_REGEX = /^[0-9()+\-\s]{10,20}$/;

const ClientBooking = () => {
  const { user, loading: authLoading } = useAuth();
  const { toast } = useToast();
  const [searchParams] = useSearchParams();

  const intentFromStorage = (() => {
    try {
      const raw = sessionStorage.getItem("haven_booking_intent");
      if (raw) { sessionStorage.removeItem("haven_booking_intent"); localStorage.removeItem("haven_booking_intent_backup"); return JSON.parse(raw) as Record<string, string>; }
    } catch {}
    // Fall back to localStorage backup (survives new-tab email confirmation)
    try {
      const raw = localStorage.getItem("haven_booking_intent_backup");
      if (raw) {
        const parsed = JSON.parse(raw);
        localStorage.removeItem("haven_booking_intent_backup");
        if (parsed._saved_at && Date.now() - parsed._saved_at > 2 * 60 * 60 * 1000) return null;
        const { _saved_at, ...intent } = parsed;
        return intent as Record<string, string>;
      }
    } catch {}
    return null;
  })();

  const savedBookingState = (() => {
    try {
      const raw = sessionStorage.getItem(BOOKING_STATE_KEY);
      if (raw) { sessionStorage.removeItem(BOOKING_STATE_KEY); return JSON.parse(raw) as Record<string, any>; }
    } catch {}
    return null;
  })();

  const crashDraft = (() => {
    try {
      const raw = localStorage.getItem(CRASH_RETENTION_KEY);
      if (raw) {
        const parsed = JSON.parse(raw) as Record<string, any>;
        const savedAt = parsed.saved_at ? new Date(parsed.saved_at) : null;
        if (savedAt) {
          const hoursOld = differenceInHours(new Date(), savedAt);
          if (hoursOld > 72) {
            localStorage.removeItem(CRASH_RETENTION_KEY);
            return null;
          }
        }
        return parsed;
      }
    } catch {}
    return null;
  })();

  const crashDraftAge = useMemo(() => {
    if (!crashDraft?.saved_at) return null;
    const savedAt = new Date(crashDraft.saved_at);
    const hours = differenceInHours(new Date(), savedAt);
    return { hours, savedAt, label: formatDistanceToNow(savedAt, { addSuffix: true }) };
  }, []);

  const [showResumeBanner, setShowResumeBanner] = useState(!!crashDraft && !savedBookingState);

  const preselectedService = searchParams.get("service") || intentFromStorage?.service || savedBookingState?.service || crashDraft?.service || null;
  const preselectedStart = searchParams.get("start") || intentFromStorage?.start || savedBookingState?.start || crashDraft?.start || null;
  const preselectedEnd = searchParams.get("end") || intentFromStorage?.end || savedBookingState?.end || crashDraft?.end || null;
  const preselectedStartTime = searchParams.get("startTime") || intentFromStorage?.startTime || savedBookingState?.startTime || crashDraft?.startTime || null;
  const preselectedEndTime = searchParams.get("endTime") || intentFromStorage?.endTime || savedBookingState?.endTime || crashDraft?.endTime || null;
  const savedPetIds: string[] | null = savedBookingState?.selectedPetIds || crashDraft?.selectedPetIds || null;
  const savedMode: "choose" | "chat" | "form" | null = savedBookingState?.mode || crashDraft?.mode || null;
  const savedNotes: string = savedBookingState?.notes || crashDraft?.notes || "";
  const savedAddonIds: string[] = crashDraft?.selectedAddonIds || [];
  const savedRecurrence: "none" | "weekly" | "biweekly" | "monthly" = crashDraft?.recurrence || "none";

  const navigate = useNavigate();
  const [mode, setMode] = useState<"choose" | "chat" | "form">(savedMode || "choose");
  const [client, setClient] = useState<any>(null);
  const [pets, setPets] = useState<any[]>([]);
  const [services, setServices] = useState<ServiceOption[]>([]);
  const [addons, setAddons] = useState<any[]>([]);
  const [petApprovals, setPetApprovals] = useState<any[]>([]);
  const [clientPricing, setClientPricing] = useState<any[]>([]);
  const [cashDiscountEnabled, setCashDiscountEnabled] = useState(false);
  const [cashDiscountPct, setCashDiscountPct] = useState(3);
  const [loading, setLoading] = useState(true);
  const [selectedPetIds, setSelectedPetIds] = useState<string[]>([]);
  const [chatMessages, setChatMessages] = useState<ChatMessage[]>([]);
  const [chatInput, setChatInput] = useState("");
  const [streaming, setStreaming] = useState(false);
  const [extractedBooking, setExtractedBooking] = useState<any>(null);
  const [bookingConfirmed, setBookingConfirmed] = useState(false);
  const [selectedService, setSelectedService] = useState<string>(preselectedService || "");
  const [startDate, setStartDate] = useState<Date | undefined>(preselectedStart ? new Date(preselectedStart + "T00:00:00") : undefined);
  const [endDate, setEndDate] = useState<Date | undefined>(preselectedEnd ? new Date(preselectedEnd + "T00:00:00") : undefined);
  const [dropOffTime, setDropOffTime] = useState<string>(preselectedStartTime || "");
  const [pickUpTime, setPickUpTime] = useState<string>(preselectedEndTime || "");
  const [notes, setNotes] = useState(savedNotes);
  const [submitting, setSubmitting] = useState(false);
  const [successData, setSuccessData] = useState<any>(null);
  const [selectedAddonIds, setSelectedAddonIds] = useState<string[]>(savedAddonIds);
  const [showAddons, setShowAddons] = useState(false);
  const [showPetSelector, setShowPetSelector] = useState(false);
  const [recurrence, setRecurrence] = useState<"none" | "weekly" | "biweekly" | "monthly">(savedRecurrence);
  const [selectedTimeSlots, setSelectedTimeSlots] = useState<TimeSlot[]>([]);
  const [specificTime, setSpecificTime] = useState<string>("");
  const [showSpecificTime, setShowSpecificTime] = useState(false);
  const [isNotesListening, setIsNotesListening] = useState(false);
  const [calendarOpen, setCalendarOpen] = useState(true);
  const afterCalendarRef = useRef<HTMLDivElement>(null);

  // Inline contact editing state
  const existingPhone = parsePhone(client?.phone || "");
  const [inlineEmail, setInlineEmail] = useState("");
  const [inlinePhoneCountry, setInlinePhoneCountry] = useState(existingPhone.countryCode);
  const [inlinePhoneDigits, setInlinePhoneDigits] = useState(existingPhone.digits);
  const [contactSaving, setContactSaving] = useState(false);

  // Sync inline state when client loads
  useEffect(() => {
    if (client) {
      const parsed = parsePhone(client.phone || "");
      setInlinePhoneCountry(parsed.countryCode);
      setInlinePhoneDigits(parsed.digits);
      setInlineEmail(client.email || user?.email || "");
    }
  }, [client?.id]);
  const notesRecognitionRef = useRef<any>(null);
  const [availabilityBlocks, setAvailabilityBlocks] = useState<any[]>([]);
  const [datesUnavailable, setDatesUnavailable] = useState(false);
  const [activeBookings, setActiveBookings] = useState<any[]>([]);
  const [exceptionRequested, setExceptionRequested] = useState(false);
  const [requestingException, setRequestingException] = useState(false);
  const [isListening, setIsListening] = useState(false);
  const recognitionRef = useRef<any>(null);
  const [promoInput, setPromoInput] = useState(() => sessionStorage.getItem("haven_promo_code") || "");
  const [promoApplied, setPromoApplied] = useState<{ code: string; description: string; discount: string } | null>(null);
  const [promoError, setPromoError] = useState("");
  const [promoLoading, setPromoLoading] = useState(false);
  const [showPromo, setShowPromo] = useState(() => !!sessionStorage.getItem("haven_promo_code"));
  const [caregiver, setCaregiver] = useState<{ name: string; avatar_url?: string | null; verified?: boolean; specialities?: string[]; bio?: string | null; certification_date?: string | null; member_since?: string | null } | null>(null);

  // ── Crash retention ──
  useEffect(() => {
    if (mode === "chat") return;
    const draft: Record<string, any> = {};
    if (selectedService) draft.service = selectedService;
    if (startDate) draft.start = format(startDate, "yyyy-MM-dd");
    if (endDate) draft.end = format(endDate, "yyyy-MM-dd");
    if (dropOffTime) draft.startTime = dropOffTime;
    if (pickUpTime) draft.endTime = pickUpTime;
    if (notes) draft.notes = notes;
    if (selectedPetIds.length > 0) draft.selectedPetIds = selectedPetIds;
    if (selectedAddonIds.length > 0) draft.selectedAddonIds = selectedAddonIds;
    if (recurrence !== "none") draft.recurrence = recurrence;
    if (mode !== "choose") draft.mode = mode;
    if (Object.keys(draft).length > 0) {
      draft.saved_at = crashDraft?.saved_at || new Date().toISOString();
      localStorage.setItem(CRASH_RETENTION_KEY, JSON.stringify(draft));
    } else {
      localStorage.removeItem(CRASH_RETENTION_KEY);
    }
  }, [selectedService, startDate, endDate, dropOffTime, pickUpTime, notes, selectedPetIds, selectedAddonIds, recurrence, mode]);

  const clearDraft = () => localStorage.removeItem(CRASH_RETENTION_KEY);

  const handleStartOver = () => {
    clearDraft();
    setSelectedService("");
    setStartDate(undefined);
    setEndDate(undefined);
    setDropOffTime("");
    setPickUpTime("");
    setNotes("");
    setSelectedAddonIds([]);
    setRecurrence("none");
    setSelectedTimeSlots([]);
    setSpecificTime("");
    setShowSpecificTime(false);
    setMode("choose");
    setExtractedBooking(null);
    setBookingConfirmed(false);
    setChatMessages([]);
    setShowResumeBanner(false);
    setExceptionRequested(false);
    setDatesUnavailable(false);
    if (pets.length) setSelectedPetIds(pets.map((p: any) => p.id));
  };

  const signedInEmail = user?.email?.trim() || "";
  const contactEmail = inlineEmail || client?.email?.trim() || signedInEmail;
  const contactPhone = client?.phone?.trim() || "";
  const emailValid = EMAIL_REGEX.test(contactEmail);
  const phoneDigitsClean = stripPhone(inlinePhoneDigits);
  const phoneValid = phoneDigitsClean.length === 10 && phoneDigitsClean.slice(3, 6) !== "555";
  const missingRequiredContact = !emailValid || !phoneValid;

  const saveInlineContact = async () => {
    if (!client || !emailValid || !phoneValid) return;
    setContactSaving(true);
    const e164 = toE164(inlinePhoneCountry, inlinePhoneDigits);
    const { error } = await supabase
      .from("clients")
      .update({ email: contactEmail, phone: e164 })
      .eq("id", client.id);
    if (error) {
      toast({ title: "Could not save contact details", description: error.message, variant: "destructive" });
    } else {
      toast({ title: "Contact details saved ✓" });
      // Refresh the client data
      setClient((prev: any) => prev ? { ...prev, email: contactEmail, phone: e164 } : prev);
    }
    setContactSaving(false);
  };

  // ── Voice helpers ──
  const createRecognition = (onResult: (f: string, i: string) => void, onEnd: () => void, initial: string) => {
    const SR = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    if (!SR) { toast({ title: "Voice not supported", description: "Try Chrome or Safari.", variant: "destructive" }); return null; }
    const r = new SR();
    r.continuous = true; r.interimResults = true; r.lang = "en-US";
    let final = initial;
    r.onresult = (e: any) => { let interim = ""; for (let i = e.resultIndex; i < e.results.length; i++) { if (e.results[i].isFinal) final += e.results[i][0].transcript + " "; else interim += e.results[i][0].transcript; } onResult(final, interim); };
    r.onerror = () => onEnd(); r.onend = () => onEnd();
    return r;
  };

  const toggleVoice = () => {
    if (isListening && recognitionRef.current) { recognitionRef.current.stop(); setIsListening(false); return; }
    const r = createRecognition((f, i) => setChatInput(f + i), () => setIsListening(false), chatInput);
    if (!r) return; recognitionRef.current = r; r.start(); setIsListening(true);
  };

  const toggleNotesVoice = () => {
    if (isNotesListening && notesRecognitionRef.current) { notesRecognitionRef.current.stop(); setIsNotesListening(false); return; }
    const r = createRecognition((f, i) => setNotes(f + i), () => setIsNotesListening(false), notes);
    if (!r) return; notesRecognitionRef.current = r; r.start(); setIsNotesListening(true);
  };

  const handleAddPet = () => {
    const state: Record<string, any> = { selectedPetIds, service: selectedService || undefined, start: startDate ? format(startDate, "yyyy-MM-dd") : undefined, end: endDate ? format(endDate, "yyyy-MM-dd") : undefined, notes: notes || undefined, mode: mode !== "choose" ? mode : undefined };
    sessionStorage.setItem(BOOKING_STATE_KEY, JSON.stringify(state));
    navigate("/client/pet/new?returnTo=/client/book");
  };

  const togglePet = (petId: string) => setSelectedPetIds((prev) => prev.includes(petId) ? prev.filter((id) => id !== petId) : [...prev, petId]);

  const applyPromoCode = async () => {
    const trimmed = promoInput.trim().toUpperCase();
    if (!trimmed) return;
    setPromoLoading(true);
    setPromoError("");
    try {
      const { data: promo } = await supabase
        .from("promo_codes")
        .select("*")
        .eq("code", trimmed)
        .eq("active", true)
        .maybeSingle();
      if (!promo) { setPromoError("Code not recognised"); return; }
      if (promo.expires_at && new Date(promo.expires_at) < new Date()) { setPromoError("This code has expired"); return; }
      if (promo.max_uses && promo.current_uses >= promo.max_uses) { setPromoError("This code has reached its limit"); return; }

      // Check if already applied
      if (client?.id) {
        const { data: existing } = await supabase
          .from("client_promo_codes").select("id")
          .eq("client_id", client.id).eq("promo_code_id", promo.id).maybeSingle();
        if (!existing) {
          await supabase.from("client_promo_codes").insert({ client_id: client.id, promo_code_id: promo.id });
        }
      }

      sessionStorage.removeItem("haven_promo_code");
      const disc = promo.discount_type === "percentage" ? `${promo.discount_value}% off` : `$${promo.discount_value} rate`;
      setPromoApplied({ code: promo.code, description: promo.description || "", discount: disc });
      toast({ title: "Code applied! 🎉", description: promo.description || disc });
    } catch (err: any) {
      setPromoError(err.message || "Something went wrong");
    } finally {
      setPromoLoading(false);
    }
  };

  const fetchAvailability = useCallback(async () => {
    const { data } = await supabase.from("availability_blocks").select("*").eq("block_type", "unavailable");
    setAvailabilityBlocks(data || []);
  }, []);

  // ── Data fetch ──
  useEffect(() => {
    if (authLoading) return;
    if (!user) { setLoading(false); return; }
    const fetchData = async () => {
      const [servicesRes, clientRes, addonsRes, cashSettingsRes, caregiverRes] = await Promise.all([
        supabase.from("pricing_rules").select("*").order("service_type"),
        supabase.from("clients").select("*").eq("user_id", user.id),
        supabase.from("service_addons").select("*").eq("active", true),
        supabase.from("app_settings").select("key, value").in("key", ["cash_discount_enabled", "cash_discount_pct"]),
        supabase.from("caregiver_profiles").select("name, avatar_url, verified, specialities, bio, certification_date, member_since").limit(1),
      ]);
      if (servicesRes.error || clientRes.error) {
        toast({ title: "Couldn't load booking data", description: "Please refresh the page and try again.", variant: "destructive" });
      }
      const loadedServices = servicesRes.data || [];
      setServices(loadedServices);
      if (preselectedService && loadedServices.length) {
        const resolved = resolveServiceType(preselectedService, loadedServices);
        if (resolved) setSelectedService(resolved);
      }
      setAddons(addonsRes.data || []);
      if (caregiverRes.data?.length) {
        setCaregiver(caregiverRes.data[0]);
      }
      if (cashSettingsRes.data) {
        const csMap: Record<string, string> = {};
        cashSettingsRes.data.forEach((r: any) => { csMap[r.key] = r.value || ""; });
        setCashDiscountEnabled(csMap.cash_discount_enabled === "true");
        setCashDiscountPct(Number(csMap.cash_discount_pct || "3"));
      }
      await fetchAvailability();
      if (clientRes.data?.length) {
        const c = clientRes.data[0];
        setClient(c);
        const [petRes, approvalsRes, pricingRes, activeBookingsRes] = await Promise.all([
          supabase.from("pets").select("*").eq("client_id", c.id).eq("status", "active"),
          supabase.from("pet_addon_approvals").select("*"),
          supabase.from("client_pricing").select("*").eq("client_id", c.id),
          supabase.from("bookings").select("*, booking_pets(pet_id, pets(name))").eq("client_id", c.id).in("status", ["requested", "approved", "deposit_paid", "confirmed", "active"]).order("created_at", { ascending: false }),
        ]);
        setPets(petRes.data || []);
        setPetApprovals(approvalsRes.data || []);
        setClientPricing(pricingRes.data || []);
        setActiveBookings((activeBookingsRes.data || []).map((b: any) => ({
          ...b,
          petNames: (b.booking_pets || []).map((bp: any) => bp.pets?.name).filter(Boolean),
        })));
        if (petRes.data?.length) {
          if (savedPetIds) {
            const allIds = petRes.data.map((p: any) => p.id);
            const newPetIds = allIds.filter((id: string) => !savedPetIds.includes(id));
            setSelectedPetIds([...savedPetIds.filter((id: string) => allIds.includes(id)), ...newPetIds]);
          } else {
            setSelectedPetIds(petRes.data.map((p: any) => p.id));
          }
        }
        if (!preselectedService && c.last_service_type) setSelectedService(c.last_service_type);
        if (savedBookingState) {
          const newPetCount = savedPetIds ? (petRes.data || []).filter((p: any) => !savedPetIds.includes(p.id)).length : 0;
          toast({ title: "Welcome back! 🐾", description: newPetCount > 0 ? "New pet added and your selections are preserved." : "Your selections are right where you left them." });
        } else if (crashDraft && !savedBookingState) {
          if (!showResumeBanner) {
            toast({ title: "Your saved booking has been restored.", description: crashDraftAge?.label ? `Started ${crashDraftAge.label}.` : "We saved your progress from last time." });
          }
        }
      }
      setLoading(false);
    };
    fetchData();
  }, [user, authLoading, fetchAvailability]);

  // Realtime availability
  useEffect(() => {
    const channel = supabase.channel("booking-availability").on("postgres_changes", { event: "*", schema: "public", table: "availability_blocks" }, () => fetchAvailability()).subscribe();
    return () => { supabase.removeChannel(channel); };
  }, [fetchAvailability]);

  // ── Helpers ──
  const saveBookingPets = async (bookingId: string) => {
    if (selectedPetIds.length === 0) return;
    const { error } = await supabase.from("booking_pets").insert(selectedPetIds.map((pet_id) => ({ booking_id: bookingId, pet_id })));
    if (error) {
      // Rollback: delete the orphaned booking
      await supabase.from("bookings").delete().eq("id", bookingId);
      throw new Error("Failed to link pets to booking. Please try again.");
    }
  };

  const saveBookingAddons = async (bookingId: string) => {
    if (selectedAddonIds.length === 0) return;
    const { error } = await supabase.from("booking_addons").insert(selectedAddonIds.map((addon_id) => {
      const addon = addons.find((a: any) => a.id === addon_id);
      return { booking_id: bookingId, addon_id, price: addon?.price || 0 };
    }));
    if (error) console.error("[HAVEN] Failed to save booking addons:", error.message);
  };

  const isAddonAvailable = (addon: any) => {
    if (!addon.requires_approval) return true;
    return selectedPetIds.some((petId) => petApprovals.some((a: any) => a.pet_id === petId && a.addon_id === addon.id));
  };

  const toggleAddon = (addonId: string) => setSelectedAddonIds((prev) => prev.includes(addonId) ? prev.filter((id) => id !== addonId) : [...prev, addonId]);

  const toggleTimeSlot = (slot: TimeSlot) => {
    setSelectedTimeSlots((prev) => prev.includes(slot) ? prev.filter((s) => s !== slot) : [...prev, slot]);
    setSpecificTime("");
    setShowSpecificTime(false);
  };

  const handleSpecificTime = (time: string) => {
    setSpecificTime(time);
    setSelectedTimeSlots([]);
  };

  // Smart extras: suggest relevant addons based on pet species and service
  const selectedPets = useMemo(() => pets.filter((p) => selectedPetIds.includes(p.id)), [pets, selectedPetIds]);
  const hasCat = selectedPets.some((p) => p.species === "cat");
  const isWalk = isWalkService(selectedService);

  const suggestedAddons = useMemo(() => {
    if (!isWalk || addons.length === 0) return [];
    const names = ["Feeding", "Fresh Water", "Litter Changing", "Medication Administration"];
    return addons.filter((a: any) => {
      if (!a.active) return false;
      if (a.name === "Litter Changing" && !hasCat) return false;
      if (a.name === "Medication Administration") {
        return selectedPets.some((p) => p.medications);
      }
      return names.includes(a.name);
    });
  }, [isWalk, addons, hasCat, selectedPets]);

  const otherAddons = useMemo(() => {
    if (!isWalk) return addons.filter((a: any) => a.active);
    const suggestedIds = new Set(suggestedAddons.map((a: any) => a.id));
    return addons.filter((a: any) => a.active && !suggestedIds.has(a.id));
  }, [isWalk, addons, suggestedAddons]);

  const buildTimeNote = () => {
    if (selectedTimeSlots.length > 0) {
      const labels = selectedTimeSlots.map((s) => TIME_SLOTS.find((t) => t.value === s)?.label).filter(Boolean);
      return `Preferred time: ${labels.join(", ")}`;
    }
    if (specificTime) return `Preferred time: ${formatTime12(specificTime)}`;
    return "";
  };

  const checkAvailability = useCallback((from: Date | undefined, to: Date | undefined) => {
    setDatesUnavailable(false); setExceptionRequested(false);
    if (!from || !to) return;
    const start = format(from, "yyyy-MM-dd"); const end = format(to, "yyyy-MM-dd");
    const hasConflict = availabilityBlocks.some((block: any) => start <= block.end_date && end >= block.start_date);
    setDatesUnavailable(hasConflict);
    if (client && selectedService) {
      supabase.from("availability_searches").insert({ client_id: client.id, service_type: selectedService, start_date: start, end_date: end, was_available: !hasConflict }).then(() => {});
    }
  }, [availabilityBlocks, client, selectedService]);

  const handleExceptionRequest = async () => {
    if (!client || !startDate || !endDate) return;
    setRequestingException(true);
    await supabase.from("availability_searches").insert({ client_id: client.id, service_type: selectedService, start_date: format(startDate, "yyyy-MM-dd"), end_date: format(endDate, "yyyy-MM-dd"), was_available: false, exception_requested: true });
    const { data: adminRoles } = await supabase.from("user_roles").select("user_id").eq("role", "admin");
    if (adminRoles?.length) {
      await supabase.from("notifications").insert(adminRoles.map((r: any) => ({ user_id: r.user_id, type: "vip_exception", message: `VIP client ${client.name} requested care for ${format(startDate, "MMM d")}–${format(endDate, "MMM d")} (${selectedService.replace(/_/g, " ")}) despite unavailability.`, entity_id: client.id })));
    }
    setExceptionRequested(true); setRequestingException(false);
    toast({ title: "Request sent", description: "We'll review your request and get back to you shortly." });
  };

  // ── Chat ──
  const startChat = () => {
    setMode("chat");
    const selectedPets = pets.filter((p) => selectedPetIds.includes(p.id));
    const petNames = selectedPets.map((p) => p.name).join(" and ");
    const petSpecies = selectedPets.length === 1 ? selectedPets[0].species : "pets";
    setChatMessages([{
      role: "assistant",
      content: petNames
        ? `Hi there! 👋 I'm here to help plan the perfect care for ${petNames}. Tell me about your upcoming trip — where you're headed, when, any special requests — and I'll find the best fit for your ${petSpecies === "dog" ? "pup" : petSpecies === "cat" ? "kitty" : petSpecies}. 🐾`
        : `Hi there! 👋 I'd love to help plan your pet's care. Tell me about your upcoming plans — when you're away, what kind of care you're looking for — and I'll take care of the rest.`,
    }]);
  };

  const sendChatMessage = async (inputText: string) => {
    if (!inputText.trim() || !client || streaming) return;
    const userMsg: ChatMessage = { role: "user", content: inputText.trim() };
    const allMessages = [...chatMessages, userMsg];
    setChatMessages(allMessages); setChatInput(""); setStreaming(true);
    let assistantContent = ""; let toolCallData: any = null;
    const abortCtrl = new AbortController();
    const chatTimeout = setTimeout(() => abortCtrl.abort(), 60_000); // 60s timeout
    try {
      const resp = await fetch(CHAT_URL, {
        method: "POST",
        headers: { "Content-Type": "application/json", Authorization: `Bearer ${import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY}` },
        body: JSON.stringify({ messages: allMessages.map((m) => ({ role: m.role, content: m.content })), client_id: client.id, selected_pet_ids: selectedPetIds }),
        signal: abortCtrl.signal,
      });
      if (!resp.ok) { const errData = await resp.json().catch(() => ({})); throw new Error(errData.error || `Error ${resp.status}`); }
      if (!resp.body) throw new Error("No response body");
      const reader = resp.body.getReader(); const decoder = new TextDecoder();
      let textBuffer = ""; let toolCallArgs = ""; let isToolCall = false;
      const updateAssistant = () => {
        setChatMessages((prev) => {
          const last = prev[prev.length - 1];
          if (last?.role === "assistant" && prev.length === allMessages.length + 1) return prev.map((m, i) => i === prev.length - 1 ? { ...m, content: assistantContent, toolCall: toolCallData } : m);
          return [...prev, { role: "assistant", content: assistantContent, toolCall: toolCallData }];
        });
      };
      while (true) {
        const { done, value } = await reader.read(); if (done) break;
        textBuffer += decoder.decode(value, { stream: true });
        let newlineIndex: number;
        while ((newlineIndex = textBuffer.indexOf("\n")) !== -1) {
          let line = textBuffer.slice(0, newlineIndex); textBuffer = textBuffer.slice(newlineIndex + 1);
          if (line.endsWith("\r")) line = line.slice(0, -1);
          if (!line.startsWith("data: ")) continue;
          const jsonStr = line.slice(6).trim(); if (jsonStr === "[DONE]") break;
          try {
            const parsed = JSON.parse(jsonStr); const delta = parsed.choices?.[0]?.delta;
            if (delta?.content) { assistantContent += delta.content; updateAssistant(); }
            if (delta?.tool_calls) { isToolCall = true; for (const tc of delta.tool_calls) { if (tc.function?.arguments) toolCallArgs += tc.function.arguments; } }
          } catch {}
        }
      }
      if (isToolCall && toolCallArgs) { try { toolCallData = JSON.parse(toolCallArgs); setExtractedBooking(toolCallData); updateAssistant(); } catch { console.error("Failed to parse tool call args:", toolCallArgs); } }
      clearTimeout(chatTimeout);
    } catch (err: any) {
      clearTimeout(chatTimeout);
      const msg = abortCtrl.signal.aborted ? "The assistant is taking too long. Please try again or switch to the form." : (err.message || "Something went wrong.");
      toast({ title: "Couldn't reach our assistant", description: msg, variant: "destructive" });
      setChatMessages((prev) => [...prev, { role: "assistant", content: "I'm having a moment — could you try again? Or you can switch to the form below." }]);
    }
    setStreaming(false);
  };

  const confirmAIBooking = async () => {
    if (!extractedBooking || !client) return;
    if (missingRequiredContact) { toast({ title: "Mobile number required", description: "We need a valid mobile number to send you booking updates and check-ins.", variant: "destructive" }); return; }
    if (selectedPetIds.length === 0) { toast({ title: "Please select at least one pet", variant: "destructive" }); return; }
    try {
      const { data: inserted, error } = await supabase.from("bookings").insert({
        client_id: client.id, service_type: extractedBooking.service_type, start_date: extractedBooking.start_date, end_date: extractedBooking.end_date, notes: extractedBooking.notes || null, payment_contact_email: contactEmail, payment_contact_phone: phoneValid ? toE164(inlinePhoneCountry, inlinePhoneDigits) : contactPhone,
      }).select().single();
      if (error) { if (error.code === "23505") { toast({ title: "That slot was just taken", description: "Please choose different dates and try again." }); await fetchAvailability(); setSubmitting(false); return; } throw error; }
      await saveBookingPets(inserted.id); await saveBookingAddons(inserted.id);
      await supabase.from("clients").update({ last_service_type: extractedBooking.service_type }).eq("id", client.id);
      import("@/lib/onboarding-events").then(({ logOnboardingEvent }) =>
        logOnboardingEvent("first_booking", { service: extractedBooking.service_type })
      ).catch(() => {});
      clearDraft(); navigate(`/client/booking/${inserted.id}`);
    } catch (err: any) {
      const friendlyMsg = err?.message?.includes("row-level security") ? "Your session may have expired. Please sign out and back in." : err?.message?.includes("check") ? "Something didn't match — please double-check your service and dates." : err?.message || "Something went wrong. Please try again.";
      toast({ title: "Couldn't save booking request", description: friendlyMsg, variant: "destructive" });
    }
    setSubmitting(false);
  };

  // ── Form submit ──
  const handleFormSubmit = async () => {
    if (!client || !selectedService || !startDate || (!endDate && !isSingleDayService(selectedService))) { toast({ title: "Missing info", description: "Please select a service and dates.", variant: "destructive" }); return; }
    if (missingRequiredContact) { toast({ title: "Mobile number required", description: "We need a valid mobile number to send you booking updates and check-ins.", variant: "destructive" }); return; }
    if (selectedPetIds.length === 0) { toast({ title: "Please select at least one pet", description: "We need to know which pet(s) need care.", variant: "destructive" }); return; }
    setSubmitting(true);
    const effectiveEndDate = isSingleDayService(selectedService) ? startDate : endDate!;
    const timeNote = isWalk
      ? buildTimeNote()
      : [dropOffTime && `Drop-off: ${formatTime12(dropOffTime)}`, pickUpTime && `Pick-up: ${formatTime12(pickUpTime)}`].filter(Boolean).join(" · ");
    const fullNotes = [timeNote, notes.trim()].filter(Boolean).join("\n") || null;
    try {
      const { data: inserted, error } = await supabase.from("bookings").insert({
        client_id: client.id, service_type: selectedService, start_date: format(startDate, "yyyy-MM-dd"), end_date: format(effectiveEndDate, "yyyy-MM-dd"), notes: fullNotes, recurrence_rule: recurrence !== "none" ? recurrence : null, payment_contact_email: contactEmail, payment_contact_phone: phoneValid ? toE164(inlinePhoneCountry, inlinePhoneDigits) : contactPhone,
      }).select().single();
      if (error) {
        if (error.code === "23505") { toast({ title: "That slot was just taken", description: "Please choose different dates and try again." }); await fetchAvailability(); setSubmitting(false); return; }
        if (error.code === "23514") { toast({ title: "Invalid service type", description: "Please select a valid service and try again.", variant: "destructive" }); setSubmitting(false); return; }
        if (error.code === "42501") { toast({ title: "Session expired", description: "Please sign out and sign back in, then try again.", variant: "destructive" }); setSubmitting(false); return; }
        throw error;
      }
      await saveBookingPets(inserted.id); await saveBookingAddons(inserted.id);
      // Recurring bookings
      if (recurrence !== "none") {
        const duration = differenceInDays(endDate, startDate);
        const recurringBookings = []; let nextStart = startDate;
        for (let i = 0; i < 12; i++) {
          if (recurrence === "weekly") nextStart = addWeeks(nextStart, 1);
          else if (recurrence === "biweekly") nextStart = addWeeks(nextStart, 2);
          else if (recurrence === "monthly") nextStart = addMonths(nextStart, 1);
          recurringBookings.push({ client_id: client.id, service_type: selectedService, start_date: format(nextStart, "yyyy-MM-dd"), end_date: format(addDays(nextStart, duration), "yyyy-MM-dd"), notes: notes.trim() || null, recurrence_rule: recurrence, parent_booking_id: inserted.id });
        }
        const { error: recurErr } = await supabase.from("bookings").insert(recurringBookings);
        if (recurErr) {
          console.error("[HAVEN] Failed to create recurring bookings:", recurErr);
          toast({ title: "Recurring bookings issue", description: "Your initial booking was created, but we couldn't set up all recurring dates. Please contact us to arrange the remaining visits.", variant: "destructive" });
        }
        if (selectedPetIds.length > 0) {
          const { data: allRecurring } = await supabase.from("bookings").select("id").eq("parent_booking_id", inserted.id);
          if (allRecurring) await supabase.from("booking_pets").insert(allRecurring.flatMap((b: any) => selectedPetIds.map((pet_id) => ({ booking_id: b.id, pet_id }))));
        }
      }
      await supabase.from("clients").update({ last_service_type: selectedService }).eq("id", client.id);
      void sendAdminAlert({ templateName: "admin-new-booking", idempotencyKey: `admin-new-booking-${inserted.id}`, templateData: { clientName: client.name, petNames: selectedPetNames.join(" & "), serviceType: selectedService.replace(/_/g, " "), startDate: format(startDate!, "EEEE, d MMMM yyyy"), endDate: format(effectiveEndDate, "EEEE, d MMMM yyyy"), notes: notes.trim() || undefined }, slackTitle: `New Booking Request from ${client.name}`, slackEventType: "new_booking", slackFields: [{ label: "Pets", value: selectedPetNames.join(" & ") }, { label: "Service", value: selectedService.replace(/_/g, " ") }, { label: "Dates", value: `${format(startDate!, "EEEE, d MMMM yyyy")} — ${format(effectiveEndDate, "EEEE, d MMMM yyyy")}` }, ...(notes.trim() ? [{ label: "Notes", value: notes.trim().slice(0, 150) }] : [])] });
      if (client.email) {
        void supabase.functions.invoke("send-transactional-email", { body: { templateName: "booking-confirmation", recipientEmail: client.email, idempotencyKey: `booking-confirmation-${inserted.id}`, templateData: { clientName: client.preferred_name || client.first_name || client.name, petNames: selectedPetNames.join(" & "), serviceType: selectedService.replace(/_/g, " "), startDate: format(startDate!, "EEEE, d MMMM yyyy"), endDate: format(effectiveEndDate, "EEEE, d MMMM yyyy"), notes: notes.trim() || undefined } } });
      }
      // SMS notifications: client + admin
      void sendSmsNotification(inserted.id, "booking_created" as any);
      void supabase.functions.invoke("send-sms", { body: { bookingId: inserted.id, eventType: "admin_booking_created", force: true } });
      clearDraft();
      setSuccessData({ bookingId: inserted.id, serviceType: selectedService, startDate: startDate!, endDate: effectiveEndDate, petNames: selectedPetNames, notes: notes.trim() || undefined, estimatedTotal, cashTotal: cashDiscountEnabled ? cashTotal : undefined, cashDiscountEnabled, dropOffTime: dropOffTime || undefined, pickUpTime: pickUpTime || undefined, addons: selectedAddonDetails, petCount: selectedPetIds.length, additionalPetFee: currentAdditionalPetFee, basePrice: currentBasePrice });
    } catch (err: any) {
      const friendlyMsg = err?.message?.includes("row-level security") ? "Your session may have expired. Please sign out and back in." : err?.message?.includes("check") ? "Something didn't match — please double-check your service and dates." : err?.message || "Something went wrong. Please try again.";
      toast({ title: "Couldn't save booking request", description: friendlyMsg, variant: "destructive" });
    }
    setSubmitting(false);
  };

  // ── Derived values ──
  const selectedServiceData = services.find((s) => s.service_type === selectedService);
  const selectedPetNames = pets.filter((p) => selectedPetIds.includes(p.id)).map((p) => p.name);
  const isSingleDay = isSingleDayService(selectedService);
  const daysCount = isSingleDay ? (startDate ? 1 : 0) : (startDate && endDate ? differenceInDays(endDate, startDate) : 0);
  const currentBasePrice = selectedServiceData ? Number(selectedServiceData.base_price) : 0;
  const currentAdditionalPetFee = selectedServiceData?.additional_pet_fee != null ? Number(selectedServiceData.additional_pet_fee) : 0;
  const extraPetCount = Math.max(0, selectedPetIds.length - 1);
  const multiPetCharge = extraPetCount * currentAdditionalPetFee * daysCount;
  const addonTotal = selectedAddonIds.reduce((s, id) => s + (addons.find((a: any) => a.id === id)?.price || 0), 0);
  const selectedAddonDetails = selectedAddonIds.map((id) => { const a = addons.find((x: any) => x.id === id); return a ? { name: a.name, price: Number(a.price) } : null; }).filter(Boolean) as { name: string; price: number }[];
  const getDiscount = (serviceType: string): number => {
    const specific = clientPricing.find((p: any) => p.service_type === serviceType && p.discount_pct);
    if (specific) return Number(specific.discount_pct);
    const global = clientPricing.find((p: any) => p.service_type === "all" && p.discount_pct);
    return global ? Number(global.discount_pct) : 0;
  };
  const currentDiscount = selectedService ? getDiscount(selectedService) : 0;
  const baseTotal = daysCount * currentBasePrice + multiPetCharge + addonTotal;
  const discountAmount = currentDiscount > 0 ? baseTotal * (currentDiscount / 100) : 0;
  const estimatedTotal = baseTotal - discountAmount;
  const cashTotal = cashDiscountEnabled ? estimatedTotal * (1 - cashDiscountPct / 100) : estimatedTotal;
  const canSubmit = selectedService && startDate && (isSingleDay || endDate) && selectedPetIds.length > 0 && !datesUnavailable;
  const datesPreFilled = !!(preselectedStart && preselectedEnd);

  // ── Render: Success ──
  if (successData) return <DashboardLayout navItems={clientNavItems} title="Book Care"><BookingSuccessScreen {...successData} /></DashboardLayout>;

  // ── Render: Loading ──
  if (loading) return <DashboardLayout navItems={clientNavItems} title="Book Care"><div className="h-64 bg-muted rounded-2xl animate-pulse" /></DashboardLayout>;

  // ── Render: No pets gate ──
  if (pets.length === 0) {
    const hasIntent = !!(preselectedStart && preselectedEnd);
    const intentStart = preselectedStart ? new Date(preselectedStart + "T00:00:00") : undefined;
    const intentEnd = preselectedEnd ? new Date(preselectedEnd + "T00:00:00") : undefined;
    let intentUnavailable = false;
    if (intentStart && intentEnd) {
      const s = format(intentStart, "yyyy-MM-dd"); const e = format(intentEnd, "yyyy-MM-dd");
      intentUnavailable = availabilityBlocks.some((block: any) => s <= block.end_date && e >= block.start_date);
    }
    const serviceName = (preselectedService || "").replace(/_/g, " ").replace(/\b\w/g, (c: string) => c.toUpperCase()) || "Care";
    return (
      <DashboardLayout navItems={clientNavItems} title="Book Care">
        <div className="max-w-md mx-auto space-y-6 pt-4">
          <BookingProgress currentStep={1} mode="form" datesPreFilled={datesPreFilled} />
          {hasIntent && !intentUnavailable && (
            <div className="rounded-2xl border border-primary/30 bg-primary/5 p-6 space-y-3 text-center">
              <div className="w-14 h-14 mx-auto rounded-2xl bg-primary/15 flex items-center justify-center"><CheckCircle2 className="h-7 w-7 text-primary" /></div>
              <h2 className="text-lg font-medium tracking-tight" style={{ fontFamily: "'Playfair Display', serif" }}>Great news — we're available!</h2>
              <p className="text-sm text-muted-foreground font-sans">{serviceName} · {intentStart && format(intentStart, "MMM d")} – {intentEnd && format(intentEnd, "MMM d, yyyy")}</p>
            </div>
          )}
          {hasIntent && intentUnavailable && (
            <div className="rounded-2xl border border-amber-500/30 bg-amber-500/5 p-6 space-y-3 text-center">
              <div className="w-14 h-14 mx-auto rounded-2xl bg-amber-500/15 flex items-center justify-center"><AlertCircle className="h-7 w-7 text-amber-600 dark:text-amber-400" /></div>
              <h2 className="text-lg font-medium tracking-tight" style={{ fontFamily: "'Playfair Display', serif" }}>Those dates aren't available</h2>
              <p className="text-sm text-muted-foreground font-sans">{serviceName} · {intentStart && format(intentStart, "MMM d")} – {intentEnd && format(intentEnd, "MMM d, yyyy")}</p>
              <Button variant="outline" size="sm" className="rounded-full" onClick={() => navigate("/")}>← Pick different dates</Button>
            </div>
          )}
          {(!hasIntent || !intentUnavailable) && (
            <div className="text-center space-y-4">
              <h1 className="text-xl font-medium tracking-tight" style={{ fontFamily: "'Playfair Display', serif" }}>{hasIntent ? "Next — tell us about your pet" : "Who needs care?"}</h1>
              <p className="text-sm text-muted-foreground font-sans max-w-sm mx-auto">{hasIntent ? "We just need your pet's details to build their personalised care plan." : "Add your pet's details so we can provide the best care."}</p>
              <PetPhotoGrid pets={[]} selectedPetIds={[]} onToggle={() => {}} onAddPet={handleAddPet} />
            </div>
          )}
        </div>
      </DashboardLayout>
    );
  }

  // ── Render: Chat mode ──
  if (mode === "chat") {
    return (
      <DashboardLayout navItems={clientNavItems} title="Book Care">
        <BookingChat
          chatMessages={chatMessages}
          chatInput={chatInput}
          setChatInput={setChatInput}
          streaming={streaming}
          isListening={isListening}
          extractedBooking={extractedBooking}
          bookingConfirmed={bookingConfirmed}
          submitting={submitting}
          selectedPetNames={selectedPetNames}
          selectedPets={pets.filter((p: any) => selectedPetIds.includes(p.id)).map((p: any) => ({ id: p.id, name: p.name, photo_url: p.photo_url, species: p.species, breed: p.breed }))}
          caregiver={caregiver}
          onSendMessage={sendChatMessage}
          onConfirmBooking={confirmAIBooking}
          onAdjust={() => { setExtractedBooking(null); setChatInput("I'd like to adjust the plan..."); }}
          onToggleVoice={toggleVoice}
          onBack={() => setMode("choose")}
          onSwitchToForm={() => setMode("form")}
          recognitionRef={recognitionRef}
          services={services}
          clientId={client?.id}
          clientDiscount={currentDiscount}
          cashDiscountEnabled={cashDiscountEnabled}
          cashDiscountPct={cashDiscountPct}
          addons={addons}
          selectedAddonIds={selectedAddonIds}
          onToggleAddon={(id: string) => setSelectedAddonIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id])}
          clientAddress={client?.address}
          clientSecondaryAddress={(client as any)?.secondary_address}
        />
      </DashboardLayout>
    );
  }

  // ── Render: Choose mode (pre-filled review or method chooser) ──
  if (mode === "choose") {
    if (datesPreFilled && selectedService && selectedPetIds.length > 0) {
      const resolvedService = services.find((s) => s.service_type === selectedService);
      const ResolvedIcon = serviceIcons[selectedService] || Sparkles;
      const disc = getDiscount(selectedService);
      const basePrice = Number(resolvedService?.base_price || 0);

      return (
        <DashboardLayout navItems={clientNavItems} title="Book Care">
          <div className="max-w-lg mx-auto space-y-5 pt-2 pb-24">
            <BookingProgress currentStep={3} mode="form" datesPreFilled={datesPreFilled} />
            <div className="text-center space-y-1">
              <h1 className="text-xl font-medium tracking-tight" style={{ fontFamily: "'Playfair Display', serif" }}>Review & Confirm</h1>
              <p className="text-sm text-muted-foreground font-sans">Check your details, add any notes, and submit.</p>
            </div>
            {/* Service card */}
            <button onClick={() => setMode("form")} className="w-full rounded-xl border border-primary/30 bg-primary/5 p-4 flex items-center gap-3 text-left hover:bg-primary/10 transition-colors">
              <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0"><ResolvedIcon className="h-5 w-5 text-primary" /></div>
              <div className="flex-1 min-w-0">
                <p className="text-sm font-medium font-sans capitalize">{selectedService.replace(/_/g, " ")}</p>
                <p className="text-xs text-muted-foreground font-sans">${basePrice}/day{disc > 0 && <span className="text-amber-700 ml-1">({disc}% VIP discount)</span>}</p>
              </div>
              <span className="text-[11px] text-primary font-sans underline underline-offset-2 shrink-0">Change</span>
            </button>
            {/* Dates card */}
            <button onClick={() => { setStartDate(undefined); setEndDate(undefined); setCalendarOpen(true); setMode("form"); }} className="w-full rounded-xl border border-primary/30 bg-primary/5 p-4 flex items-center gap-3 text-left hover:bg-primary/10 transition-colors">
              <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0"><CalendarIcon className="h-5 w-5 text-primary" /></div>
              <div className="flex-1 min-w-0">
                <p className="text-sm font-medium font-sans">{startDate && format(startDate, "EEE, d MMM")}{dropOffTime && ` at ${formatTime12(dropOffTime)}`}{!isSingleDay && <>{" → "}{endDate && format(endDate, "EEE, d MMM yyyy")}{pickUpTime && ` at ${formatTime12(pickUpTime)}`}</>}</p>
                <p className="text-xs text-muted-foreground font-sans">{daysCount} {daysCount === 1 ? "day" : "days"}</p>
              </div>
              <span className="text-[11px] text-primary font-sans underline underline-offset-2 shrink-0">Change</span>
            </button>
            {/* Pets */}
            <div className="space-y-2">
              <div className="flex items-center justify-between px-1">
                <p className="text-xs font-medium font-sans text-muted-foreground">Your pets</p>
                <button onClick={() => setShowPetSelector(!showPetSelector)} className="text-[11px] text-primary font-sans underline underline-offset-2">{showPetSelector ? "Done" : "Change"}</button>
              </div>
              {showPetSelector ? (
                <PetPhotoGrid pets={pets} selectedPetIds={selectedPetIds} onToggle={togglePet} onAddPet={handleAddPet} />
              ) : (
                <div className="rounded-xl border border-primary/30 bg-primary/5 p-4 flex items-center gap-3">
                  <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0"><PawPrint className="h-5 w-5 text-primary" /></div>
                  <p className="text-sm font-medium font-sans">{selectedPetNames.join(", ")}</p>
                  <CheckCircle2 className="h-4 w-4 text-primary shrink-0 ml-auto" />
                </div>
              )}
            </div>
            {/* Notes */}
            <div className="space-y-1.5">
              <p className="text-xs font-medium font-sans text-muted-foreground px-1">Notes (optional)</p>
              <div className="relative">
                <Textarea placeholder={isNotesListening ? "Listening — speak now…" : "Anything we should know…"} value={notes} onChange={(e) => setNotes(e.target.value)} rows={3} className="rounded-xl text-sm pr-12" />
                <Button type="button" size="icon" variant={isNotesListening ? "default" : "ghost"} className={cn("absolute right-2 top-2 h-8 w-8 rounded-full", isNotesListening && "bg-destructive hover:bg-destructive/90 animate-pulse")} onClick={toggleNotesVoice}>
                  {isNotesListening ? <MicOff className="h-3.5 w-3.5" /> : <Mic className="h-3.5 w-3.5" />}
                </Button>
              </div>
            </div>
            {/* Care reminders */}
            {pets.filter((p) => selectedPetIds.includes(p.id) && (p.medications || p.special_care_notes)).length > 0 && (
              <div className="bg-accent/30 rounded-xl p-3 space-y-1.5">
                <p className="text-[11px] font-medium font-sans text-muted-foreground">📋 Care Reminders</p>
                {pets.filter((p) => selectedPetIds.includes(p.id) && (p.medications || p.special_care_notes)).map((p) => (
                  <p key={p.id} className="text-[11px] text-muted-foreground font-sans"><span className="font-medium text-foreground">{p.name}:</span>{p.medications && <span> 💊 {p.medications}</span>}{p.special_care_notes && <span> ✨ {p.special_care_notes}</span>}</p>
                ))}
              </div>
            )}
            {/* Estimate */}
            <BookingEstimate daysCount={daysCount} basePrice={basePrice} addonTotal={addonTotal} discountPct={disc} cashDiscountEnabled={cashDiscountEnabled} cashDiscountPct={cashDiscountPct} submitting={submitting} onSubmit={handleFormSubmit} contactEmail={client?.email} contactPhone={client?.phone} petCount={selectedPetIds.length} additionalPetFee={Number(resolvedService?.additional_pet_fee || 0)} selectedAddons={selectedAddonDetails} serviceType={selectedService} />
            <div className="flex items-center justify-center gap-4 pt-1">
              <button onClick={startChat} className="text-xs text-muted-foreground hover:text-primary font-sans transition-colors">
                <MessageCircle className="h-3.5 w-3.5 inline mr-1.5" />Chat instead
              </button>
              <span className="text-border">·</span>
              <button onClick={handleStartOver} className="text-xs text-muted-foreground hover:text-destructive font-sans transition-colors">
                Start over
              </button>
            </div>
          </div>
        </DashboardLayout>
      );
    }

    return (
      <DashboardLayout navItems={clientNavItems} title="Book Care">
        <div className="max-w-lg mx-auto space-y-5">
          {showResumeBanner && crashDraft && (
            <Card className="rounded-2xl border-2 border-primary/20 bg-primary/5">
              <CardContent className="py-4 space-y-3">
                <div className="space-y-1">
                  <p className="text-sm font-medium">You have a saved booking</p>
                  <p className="text-xs text-muted-foreground font-sans">
                    {crashDraftAge?.hours && crashDraftAge.hours >= 24
                      ? `Started ${crashDraftAge.label}. Would you like to continue or start fresh?`
                      : `Started ${crashDraftAge?.label || "earlier"}. Pick up where you left off?`}
                  </p>
                  {(crashDraft.service || crashDraft.start) && (
                    <p className="text-xs text-muted-foreground font-sans mt-1">
                      {crashDraft.service && <span className="capitalize">{crashDraft.service.replace(/_/g, " ")}</span>}
                      {crashDraft.start && crashDraft.end && <span> · {crashDraft.start} → {crashDraft.end}</span>}
                    </p>
                  )}
                </div>
                <div className="flex gap-2">
                  <Button size="sm" className="rounded-full flex-1" onClick={() => setShowResumeBanner(false)}>
                    Continue
                  </Button>
                  <Button size="sm" variant="outline" className="rounded-full flex-1" onClick={() => {
                    clearDraft();
                    setShowResumeBanner(false);
                    setSelectedService("");
                    setStartDate(undefined);
                    setEndDate(undefined);
                    setDropOffTime("");
                    setPickUpTime("");
                    setNotes("");
                    setSelectedAddonIds([]);
                    setRecurrence("none");
                    setMode("choose");
                    if (pets.length) setSelectedPetIds(pets.map((p: any) => p.id));
                  }}>
                    Start fresh
                  </Button>
                </div>
              </CardContent>
            </Card>
          )}
          {activeBookings.length > 0 && (
            <ActiveBookingsBanner
              bookings={activeBookings}
              onCancel={async (id) => {
                const { error } = await supabase.from("bookings").update({ status: "cancelled" }).eq("id", id);
                if (error) { toast({ title: "Couldn't cancel", description: error.message, variant: "destructive" }); return; }
                setActiveBookings((prev) => prev.filter((b: any) => b.id !== id));
                toast({ title: "Booking cancelled" });
              }}
            />
          )}
          <BookingModeChooser pets={pets} selectedPetIds={selectedPetIds} onTogglePet={togglePet} onAddPet={handleAddPet} onStartChat={startChat} onStartForm={() => setMode("form")} />
        </div>
      </DashboardLayout>
    );
  }

  // ── Render: Form mode ──
  const formStep = !selectedPetIds.length ? 1 : !selectedService ? 2 : datesPreFilled ? 3 : !(startDate && (isSingleDay || endDate)) ? 3 : 4;

  return (
    <DashboardLayout navItems={clientNavItems} title="Book Care">
      <div className="max-w-2xl mx-auto space-y-5 pb-8">
        {activeBookings.length > 0 && (
          <ActiveBookingsBanner
            bookings={activeBookings}
            onCancel={async (id) => {
              const { error } = await supabase.from("bookings").update({ status: "cancelled" }).eq("id", id);
              if (error) { toast({ title: "Couldn't cancel", description: error.message, variant: "destructive" }); return; }
              setActiveBookings((prev) => prev.filter((b: any) => b.id !== id));
              toast({ title: "Booking cancelled" });
            }}
          />
        )}
        <BookingProgress currentStep={formStep} mode="form" datesPreFilled={datesPreFilled} />
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-3">
            <Button variant="ghost" size="icon" className="rounded-full" onClick={() => setMode("choose")}><ArrowLeft className="h-4 w-4" /></Button>
            <h1 className="text-xl font-medium tracking-tight">Book Care</h1>
          </div>
          <div className="flex items-center gap-2">
            {client?.vip && <Badge className="bg-amber-50 text-amber-700 border border-amber-200 gap-1"><Star className="h-3 w-3 fill-amber-500" /> VIP</Badge>}
            <Button variant="ghost" size="sm" className="text-xs rounded-full gap-1" onClick={startChat}><MessageCircle className="h-3.5 w-3.5" /> Try AI</Button>
          </div>
        </div>

        {/* Pets */}
        <div className="space-y-2">
          <p className="text-xs font-medium font-sans text-muted-foreground px-1">Who needs care?</p>
          <PetPhotoGrid pets={pets} selectedPetIds={selectedPetIds} onToggle={togglePet} onAddPet={handleAddPet} />
        </div>

        {/* Promo / Invite Code */}
        {!promoApplied ? (
          <div className="space-y-1.5">
            {!showPromo ? (
              <button onClick={() => setShowPromo(true)} className="text-xs text-primary hover:underline font-sans flex items-center gap-1.5 px-1">
                <Gift className="h-3.5 w-3.5" /> Have an invite or promo code?
              </button>
            ) : (
              <div className="flex gap-2 items-start">
                <Input
                  value={promoInput}
                  onChange={(e) => { setPromoInput(e.target.value.toUpperCase()); setPromoError(""); }}
                  placeholder="e.g. HAVEN-FRIEND"
                  className="font-mono uppercase text-sm h-9 rounded-xl"
                  onKeyDown={(e) => e.key === "Enter" && applyPromoCode()}
                />
                <Button onClick={applyPromoCode} disabled={promoLoading || !promoInput.trim()} size="sm" className="rounded-full shrink-0 h-9">
                  {promoLoading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : "Apply"}
                </Button>
              </div>
            )}
            {promoError && <p className="text-xs text-destructive font-sans px-1">{promoError}</p>}
          </div>
        ) : (
          <div className="flex items-center gap-2 px-3 py-2.5 rounded-xl bg-primary/5 border border-primary/20">
            <Check className="h-4 w-4 text-primary shrink-0" />
            <div className="flex-1 min-w-0">
              <span className="font-mono text-xs">{promoApplied.code}</span>
              {promoApplied.description && <p className="text-[10px] text-muted-foreground truncate">{promoApplied.description}</p>}
            </div>
            <Badge variant="secondary" className="text-[10px] shrink-0">{promoApplied.discount}</Badge>
          </div>
        )}

        {/* Service selector */}
        <div className="space-y-2">
          <p className="text-xs font-medium font-sans text-muted-foreground px-1">What do you need?</p>
          <div className="grid gap-2">
            {services.map((s) => {
              const Icon = serviceIcons[s.service_type] || Sparkles;
              const isLast = client?.last_service_type === s.service_type;
              const active = selectedService === s.service_type;
              const disc = getDiscount(s.service_type);
              const basePrice = Number(s.base_price);
              const discPrice = disc > 0 ? basePrice * (1 - disc / 100) : basePrice;
              return (
                <button key={s.id} onClick={() => setSelectedService(s.service_type)} className={cn("flex items-center gap-3 px-4 py-3 rounded-xl border-2 transition-all text-left w-full", active ? "border-primary bg-primary/5 shadow-sm" : "border-border/50 hover:border-primary/30")}>
                  <div className="w-9 h-9 rounded-lg bg-primary/10 flex items-center justify-center shrink-0"><Icon className="h-4 w-4 text-primary" /></div>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2">
                      <span className="text-sm font-medium font-sans capitalize">{s.service_type.replace(/_/g, " ")}</span>
                      {isLast && <Badge variant="secondary" className="text-[9px]">Last booked</Badge>}
                      {disc > 0 && <Badge className="bg-amber-50 text-amber-700 border border-amber-200 text-[9px]">{disc}% off</Badge>}
                    </div>
                    {(s.modifiers as any)?.description && <p className="text-[11px] text-muted-foreground font-sans mt-0.5 line-clamp-1">{(s.modifiers as any).description}</p>}
                  </div>
                  <div className="text-right shrink-0">
                    {disc > 0 ? (
                      <div className="flex flex-col items-end">
                        <span className="text-sm font-mono text-primary font-medium">${discPrice.toFixed(0)}</span>
                        <span className="text-[10px] font-mono text-muted-foreground line-through">${basePrice.toFixed(0)}</span>
                      </div>
                    ) : <span className="text-sm font-mono text-muted-foreground">${basePrice.toFixed(0)}</span>}
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        {/* Dates — compact summary when pre-filled */}
        {selectedService && datesPreFilled && !datesUnavailable && (
          <div className="space-y-2">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1">Your dates</p>
            <div className="border border-primary/30 rounded-xl bg-primary/5 p-3">
              <div className="flex items-center gap-2 text-sm font-sans">
                <CalendarIcon className="h-4 w-4 text-primary shrink-0" />
                <span className="font-medium">
                  {startDate && format(startDate, "EEE, d MMM")}{dropOffTime && ` at ${formatTime12(dropOffTime)}`}
                  {!isSingleDay && <>{" → "}{endDate && format(endDate, "EEE, d MMM yyyy")}{pickUpTime && ` at ${formatTime12(pickUpTime)}`}</>}
                </span>
                <Badge variant="secondary" className="text-[10px] shrink-0 ml-auto">{daysCount} {daysCount === 1 ? "day" : "days"}</Badge>
              </div>
              <button onClick={() => { setStartDate(undefined); setEndDate(undefined); setCalendarOpen(true); }} className="text-[11px] text-muted-foreground hover:text-primary font-sans mt-1.5 underline underline-offset-2">Change dates</button>
            </div>
          </div>
        )}

        {/* Dates — calendar */}
        {selectedService && (!datesPreFilled || datesUnavailable || (!startDate && !endDate)) && (
          <div className="space-y-2">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1">When?</p>

            {/* Collapsed date summary */}
            {!calendarOpen && startDate && (isSingleDay || endDate) && !datesUnavailable && (
              <button
                onClick={() => setCalendarOpen(true)}
                className="w-full rounded-xl border border-primary/30 bg-primary/5 p-4 flex items-center gap-3 text-left hover:bg-primary/10 transition-colors"
              >
                <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
                  <CalendarIcon className="h-5 w-5 text-primary" />
                </div>
                <div className="flex-1 min-w-0">
                  <p className="text-sm font-medium font-sans">
                    {format(startDate, "EEE, d MMM")}
                    {!isSingleDay && endDate && <>{" → "}{format(endDate, "EEE, d MMM yyyy")}</>}
                  </p>
                  <p className="text-xs text-muted-foreground font-sans">{daysCount} {daysCount === 1 ? "day" : "days"}</p>
                </div>
                <div className="flex items-center gap-2 shrink-0">
                  <CheckCircle2 className="h-4 w-4 text-primary" />
                  <span className="text-[11px] text-primary font-sans underline underline-offset-2">Change</span>
                </div>
              </button>
            )}

            {/* Open calendar */}
            {(calendarOpen || !(startDate && (isSingleDay || endDate)) || datesUnavailable) && (
              <div className="border border-border/50 rounded-xl bg-card p-3 space-y-3">
                {isSingleDay ? (
                  <>
                    <div className="flex items-center gap-2 text-sm font-sans">
                      <div className={cn("flex-1 rounded-lg border px-3 py-2 text-center text-xs", startDate ? "border-primary bg-primary/5 font-medium" : "border-border text-muted-foreground")}>{startDate ? format(startDate, "MMM d") : "Select date"}</div>
                      {startDate && <Badge variant="secondary" className="text-[10px] shrink-0">1 day</Badge>}
                    </div>
                    <Calendar mode="single" selected={startDate} onSelect={(date) => {
                      setStartDate(date || undefined); setEndDate(date || undefined); checkAvailability(date || undefined, date || undefined);
                      if (date) { setCalendarOpen(false); setTimeout(() => afterCalendarRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }), 150); }
                    }} disabled={(d) => d < new Date()} numberOfMonths={1} className="p-2 pointer-events-auto mx-auto" />
                  </>
                ) : (
                  <>
                    <div className="flex items-center gap-2 text-sm font-sans">
                      <div className={cn("flex-1 rounded-lg border px-3 py-2 text-center text-xs", startDate ? "border-primary bg-primary/5 font-medium" : "border-border text-muted-foreground")}>{startDate ? format(startDate, "MMM d") : "Start"}</div>
                      <ArrowRight className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
                      <div className={cn("flex-1 rounded-lg border px-3 py-2 text-center text-xs", endDate ? "border-primary bg-primary/5 font-medium" : "border-border text-muted-foreground")}>{endDate ? format(endDate, "MMM d") : "End"}</div>
                      {daysCount > 0 && <Badge variant="secondary" className="text-[10px] shrink-0">{daysCount} {daysCount === 1 ? "day" : "days"}</Badge>}
                    </div>
                    <Calendar mode="range" selected={startDate && endDate ? { from: startDate, to: endDate } : startDate ? { from: startDate, to: undefined } : undefined} onSelect={(range) => {
                      setStartDate(range?.from); setEndDate(range?.to); checkAvailability(range?.from, range?.to);
                      if (range?.from && range?.to) { setCalendarOpen(false); setTimeout(() => afterCalendarRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }), 150); }
                    }} disabled={(d) => d < new Date()} numberOfMonths={1} className="p-2 pointer-events-auto mx-auto" />
                  </>
                )}
                {datesUnavailable && !exceptionRequested && (
                  <div className="rounded-xl border border-amber-500/30 bg-amber-50/50 dark:bg-amber-950/20 p-3 space-y-2">
                    <div className="flex items-start gap-2">
                      <AlertCircle className="h-4 w-4 text-amber-600 dark:text-amber-400 shrink-0 mt-0.5" />
                      <div><p className="text-xs font-medium font-sans text-amber-900 dark:text-amber-200">Not currently available</p><p className="text-[11px] text-amber-700/80 dark:text-amber-300/70 font-sans">Try different dates above.</p></div>
                    </div>
                    {client?.vip && <Button onClick={handleExceptionRequest} disabled={requestingException} variant="outline" size="sm" className="w-full rounded-lg text-xs gap-1">{requestingException ? <Loader2 className="h-3 w-3 animate-spin" /> : <Star className="h-3 w-3" />}Request as VIP</Button>}
                  </div>
                )}
                {exceptionRequested && (
                  <div className="rounded-xl border border-primary/30 bg-primary/5 p-3 flex items-start gap-2"><CheckCircle2 className="h-4 w-4 text-primary shrink-0 mt-0.5" /><p className="text-xs font-sans">Exception request sent — we'll be in touch.</p></div>
                )}
              </div>
            )}
          </div>
        )}
        <div ref={afterCalendarRef} />

        {/* Walk Time Slots */}
        {selectedService && isWalk && startDate && (
          <div className="space-y-2">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1 flex items-center gap-1.5">
              <Clock className="h-3.5 w-3.5" /> When would you like the visit?
            </p>
            <div className="grid grid-cols-2 gap-2">
              {TIME_SLOTS.map((slot) => {
                const Icon = slot.icon;
                const active = selectedTimeSlots.includes(slot.value);
                return (
                  <button
                    key={slot.value}
                    onClick={() => toggleTimeSlot(slot.value)}
                    className={cn(
                      "flex items-center gap-2.5 px-3 py-3 rounded-xl border-2 transition-all text-left",
                      active ? "border-primary bg-primary/5 shadow-sm" : "border-border/50 hover:border-primary/30"
                    )}
                  >
                    <Icon className={cn("h-4 w-4 shrink-0", active ? "text-primary" : "text-muted-foreground")} />
                    <div>
                      <p className={cn("text-sm font-sans", active ? "font-medium text-primary" : "")}>{slot.label}</p>
                      <p className="text-[10px] text-muted-foreground font-sans">{slot.range}</p>
                    </div>
                  </button>
                );
              })}
            </div>
            <div className="flex items-center gap-2 px-1">
              <span className="text-[10px] text-muted-foreground font-sans">or</span>
              {!showSpecificTime ? (
                <button onClick={() => { setShowSpecificTime(true); setSelectedTimeSlots([]); }} className="text-[11px] text-primary font-sans underline underline-offset-2">
                  Choose a specific time
                </button>
              ) : (
                <div className="flex items-center gap-2 flex-1">
                  <select
                    value={specificTime}
                    onChange={(e) => handleSpecificTime(e.target.value)}
                    className="flex-1 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-sans"
                  >
                    <option value="">Select time…</option>
                    {SPECIFIC_TIMES.map((t) => (
                      <option key={t} value={t}>{formatTime12(t)}</option>
                    ))}
                  </select>
                  <button onClick={() => { setShowSpecificTime(false); setSpecificTime(""); }} className="text-[10px] text-muted-foreground font-sans underline underline-offset-2">
                    Back to slots
                  </button>
                </div>
              )}
            </div>
            {selectedTimeSlots.length > 1 && (
              <p className="text-[10px] text-muted-foreground font-sans px-1">
                Multiple slots selected — we'll schedule visits for each time window.
              </p>
            )}
          </div>
        )}

        {/* Drop-off / Pick-up times (non-walk services) */}
        {selectedService && !isWalk && startDate && (endDate || isSingleDay) && (
          <div className="space-y-1.5">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1">Times (optional)</p>
            <div className="grid grid-cols-2 gap-2">
              <div>
                <label htmlFor="dropoff-time" className="text-[10px] text-muted-foreground font-sans px-1">Drop-off</label>
                <Input id="dropoff-time" aria-label="Drop-off time (optional)" type="time" value={dropOffTime} onChange={(e) => setDropOffTime(e.target.value)} className="rounded-xl text-sm" />
              </div>
              <div>
                <label htmlFor="pickup-time" className="text-[10px] text-muted-foreground font-sans px-1">Pick-up</label>
                <Input id="pickup-time" aria-label="Pick-up time (optional)" type="time" value={pickUpTime} onChange={(e) => setPickUpTime(e.target.value)} className="rounded-xl text-sm" />
              </div>
            </div>
          </div>
        )}

        {/* Notes */}
        {selectedService && (
          <div className="space-y-1.5">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1">Notes (optional)</p>
            <div className="relative">
              <Textarea placeholder={isNotesListening ? "Listening — speak now…" : "Anything we should know — schedules, medication, special instructions…"} value={notes} onChange={(e) => setNotes(e.target.value)} rows={3} className="rounded-xl text-sm pr-12" />
              <Button type="button" size="icon" variant={isNotesListening ? "default" : "ghost"} className={cn("absolute right-2 top-2 h-8 w-8 rounded-full", isNotesListening && "bg-destructive hover:bg-destructive/90 animate-pulse")} onClick={toggleNotesVoice}>
                {isNotesListening ? <MicOff className="h-3.5 w-3.5" /> : <Mic className="h-3.5 w-3.5" />}
              </Button>
            </div>
            {isNotesListening && <p className="text-[10px] text-primary font-sans px-1 animate-pulse">🎙️ Listening — your words will appear as you speak</p>}
          </div>
        )}

        {/* Recurrence */}
        {selectedService && startDate && endDate && (
          <div className="space-y-2">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1 flex items-center gap-1.5"><Repeat className="h-3.5 w-3.5" /> Repeat this booking?</p>
            <div className="grid grid-cols-2 gap-2">
              {([{ value: "none", label: "Just once" }, { value: "weekly", label: "Every week" }, { value: "biweekly", label: "Every 2 weeks" }, { value: "monthly", label: "Every month" }] as const).map((opt) => (
                <button key={opt.value} onClick={() => setRecurrence(opt.value)} className={cn("px-3 py-2.5 rounded-xl border text-sm font-sans transition-all text-center", recurrence === opt.value ? "border-primary bg-primary/10 text-primary font-medium" : "border-border bg-card text-muted-foreground hover:border-primary/30")}>{opt.label}</button>
              ))}
            </div>
            {recurrence !== "none" && <p className="text-[10px] text-muted-foreground font-sans px-1">This will create 12 future bookings ({recurrence === "weekly" ? "weekly" : recurrence === "biweekly" ? "fortnightly" : "monthly"}). Each booking goes through the normal approval process.</p>}
          </div>
        )}

        {/* Smart Extras — "While we're there" for walk services */}
        {isWalk && suggestedAddons.length > 0 && selectedService && startDate && (
          <div className="space-y-2">
            <p className="text-xs font-medium font-sans text-muted-foreground px-1 flex items-center gap-1.5">
              <UtensilsCrossed className="h-3.5 w-3.5" /> While we're there
            </p>
            <div className="grid gap-2">
              {suggestedAddons.map((addon: any) => {
                const available = isAddonAvailable(addon);
                const selected = selectedAddonIds.includes(addon.id);
                const addonIcon = addon.name === "Feeding" ? UtensilsCrossed
                  : addon.name === "Fresh Water" ? Droplets
                  : addon.name === "Litter Changing" ? CatIcon
                  : PawPrint;
                const AddonIcon = addonIcon;
                return (
                  <button
                    key={addon.id}
                    disabled={!available}
                    onClick={() => available && toggleAddon(addon.id)}
                    className={cn(
                      "flex items-center gap-3 px-4 py-3 rounded-xl border-2 transition-all text-left w-full",
                      !available ? "opacity-50 border-border/30" : selected ? "border-primary bg-primary/5" : "border-border/50 hover:border-primary/30"
                    )}
                  >
                    <div className={cn("w-8 h-8 rounded-lg flex items-center justify-center shrink-0", selected ? "bg-primary/10" : "bg-muted")}>
                      <AddonIcon className={cn("h-4 w-4", selected ? "text-primary" : "text-muted-foreground")} />
                    </div>
                    <div className="flex-1 min-w-0">
                      <span className="text-sm font-sans">{addon.name}</span>
                      {addon.description && <p className="text-[10px] text-muted-foreground font-sans line-clamp-1">{addon.description}</p>}
                    </div>
                    {Number(addon.price) > 0 ? (
                      <span className="text-xs font-mono text-muted-foreground shrink-0">+${Number(addon.price).toFixed(0)}</span>
                    ) : (
                      <Badge variant="secondary" className="text-[9px] shrink-0">Free</Badge>
                    )}
                    <Checkbox checked={selected} disabled={!available} className="pointer-events-none shrink-0" />
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {/* Other Add-ons */}
        {otherAddons.length > 0 && selectedService && (
          <div>
            <button onClick={() => setShowAddons(!showAddons)} className="w-full flex items-center justify-between px-4 py-2.5 bg-card border border-border/50 rounded-xl hover:bg-accent/30 transition-colors">
              <span className="text-sm font-sans text-muted-foreground">{isWalk ? "More add-ons" : "Add-ons"} {selectedAddonIds.filter((id) => otherAddons.some((a: any) => a.id === id)).length > 0 && `(${selectedAddonIds.filter((id) => otherAddons.some((a: any) => a.id === id)).length})`}</span>
              {showAddons ? <ChevronUp className="h-4 w-4 text-muted-foreground" /> : <ChevronDown className="h-4 w-4 text-muted-foreground" />}
            </button>
            {showAddons && (
              <div className="mt-2 grid gap-2">
                {otherAddons.map((addon: any) => {
                  const available = isAddonAvailable(addon);
                  const selected = selectedAddonIds.includes(addon.id);
                  return (
                    <button key={addon.id} disabled={!available} onClick={() => available && toggleAddon(addon.id)} className={cn("flex items-center gap-3 px-4 py-3 rounded-xl border-2 transition-all text-left w-full", !available ? "opacity-50 border-border/30" : selected ? "border-primary bg-primary/5" : "border-border/50 hover:border-primary/30")}>
                      <Checkbox checked={selected} disabled={!available} className="pointer-events-none" />
                      <div className="flex-1 min-w-0"><span className="text-sm font-sans">{addon.name}</span>{addon.requires_approval && !available && <span className="text-[10px] text-muted-foreground ml-2">Needs approval</span>}</div>
                      <span className="text-xs font-mono text-muted-foreground">+${Number(addon.price).toFixed(0)}</span>
                    </button>
                  );
                })}
              </div>
            )}
          </div>
        )}

        {/* Care reminders */}
        {selectedService && pets.filter((p) => selectedPetIds.includes(p.id) && (p.medications || p.special_care_notes)).length > 0 && (
          <div className="bg-accent/30 rounded-xl p-3 space-y-1.5">
            <p className="text-[11px] font-medium font-sans text-muted-foreground">📋 Care Reminders</p>
            {pets.filter((p) => selectedPetIds.includes(p.id) && (p.medications || p.special_care_notes)).map((p) => (
              <p key={p.id} className="text-[11px] text-muted-foreground font-sans"><span className="font-medium text-foreground">{p.name}:</span>{p.medications && <span> 💊 {p.medications}</span>}{p.special_care_notes && <span> ✨ {p.special_care_notes}</span>}</p>
            ))}
          </div>
        )}

        {/* Inline contact details — shown when missing */}
        {canSubmit && missingRequiredContact && (
          <div className="space-y-3 rounded-xl border-2 border-primary/30 bg-primary/5 p-4" id="booking-contact-fields">
            <div className="flex items-center gap-2">
              <Phone className="h-4 w-4 text-primary" />
              <p className="text-sm font-medium font-sans">Mobile number required</p>
            </div>
            <p className="text-xs text-muted-foreground font-sans">
              We need your mobile number to send booking updates, check-ins, and care notifications by text. Email is also required for confirmations.
            </p>
            <div className="space-y-1.5">
              <label htmlFor="booking-email" className="text-xs font-medium font-sans text-muted-foreground">Email</label>
              <Input
                id="booking-email"
                type="email"
                value={inlineEmail}
                onChange={(e) => setInlineEmail(e.target.value)}
                placeholder="your@email.com"
                className="rounded-xl"
              />
              {inlineEmail && !emailValid && (
                <p className="text-[10px] text-destructive font-sans">Please enter a valid email address.</p>
              )}
            </div>
            <StructuredPhoneInput
              countryCode={inlinePhoneCountry}
              phoneNumber={inlinePhoneDigits}
              onCountryCodeChange={setInlinePhoneCountry}
              onPhoneNumberChange={setInlinePhoneDigits}
            />
            <Button
              onClick={saveInlineContact}
              disabled={contactSaving || !emailValid || !phoneValid}
              className="w-full rounded-xl gap-2"
              size="sm"
            >
              {contactSaving ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />}
              {contactSaving ? "Saving…" : "Save & Continue"}
            </Button>
          </div>
        )}

        {/* Estimate + submit */}
        {canSubmit && !missingRequiredContact && (
          <BookingEstimate daysCount={daysCount} basePrice={currentBasePrice} addonTotal={addonTotal} discountPct={currentDiscount} cashDiscountEnabled={cashDiscountEnabled} cashDiscountPct={cashDiscountPct} submitting={submitting} onSubmit={handleFormSubmit} contactEmail={contactEmail} contactPhone={phoneValid ? toE164(inlinePhoneCountry, inlinePhoneDigits) : contactPhone} petCount={selectedPetIds.length} additionalPetFee={currentAdditionalPetFee} selectedAddons={selectedAddonDetails} serviceType={selectedService} />
        )}

        {/* Start over */}
        <div className="text-center pt-2 pb-4">
          <button onClick={handleStartOver} className="text-xs text-muted-foreground hover:text-destructive font-sans transition-colors">
            Clear & start over
          </button>
        </div>
      </div>
    </DashboardLayout>
  );
};

export default ClientBooking;
