import { useEffect, useState, useMemo } from "react";
import { useNewMediaCount } from "@/hooks/use-new-media-count";
import SignedImage from "@/components/SignedImage";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/contexts/AuthContext";
import { getAuthMethodDisplay } from "@/lib/auth-display";
import { Link } from "react-router-dom";
import DashboardLayout from "@/components/DashboardLayout";
import { clientNavItems } from "@/components/client/clientNav";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
// Service images removed — not applicable for handyman service
// PetPassportCard removed — not applicable for handyman service
import {
  CalendarDays, CheckCircle2, Clock, Sparkles, Wrench,
  Award, Cake, Heart, Star, RotateCcw, MessageCircle,
  Download, FileText, Pill, UtensilsCrossed, Mail,
  Calendar, ArrowRight, Bell, X,
} from "lucide-react";
import { format, differenceInDays, differenceInMonths, differenceInYears, differenceInHours, isBefore, addYears, isToday, isYesterday, formatDistanceToNow } from "date-fns";
import { useToast } from "@/hooks/use-toast";
import { cn } from "@/lib/utils";
import { cacheBookingSnapshots } from "@/lib/booking-snapshot";
import { parseAddress } from "@/components/client/StructuredAddressInput";
import { formatServiceTypeLabel } from "@/lib/service-types";
import { buildBookingNotes, parseBookingTeamFromNotes } from "@/lib/booking-team";
import { getClientBookingPremiumSummary } from "@/lib/client-booking-premium";
import type { PricingRuleLike, RateOverrideLike } from "@/lib/pricing";
import comfortHome from "@/assets/comfort-home.jpg";
import heroHome from "@/assets/hero-home.jpg";
import {
  DASHBOARD_VISIBLE_UPDATES_LIMIT,
  getDashboardAcknowledgementKeys,
  getBookingChangeSummary,
  getDashboardChangeKey,
  getDashboardChangeFamilyKey,
  getDashboardViewedUpdatesStorageKey,
  partitionDashboardRecentChanges,
} from "@/lib/client-dashboard-updates";
import { isCancellationReviewPending } from "@/lib/booking-cancellation";

const parseDateOnly = (value?: string | null) => {
  if (!value) return null;
  const [year, month, day] = value.split("-").map(Number);
  if (!year || !month || !day) return null;
  return new Date(year, month - 1, day);
};

const statusColors: Record<string, string> = {
  requested: "bg-accent text-accent-foreground",
  approved: "bg-primary/10 text-primary",
  deposit_paid: "bg-primary/10 text-primary",
  confirmed: "bg-primary/10 text-primary",
  active: "bg-primary text-primary-foreground",
  completed: "bg-muted text-muted-foreground",
  cancelled: "bg-destructive/10 text-destructive",
};

const loyaltyTier = (months: number) => {
  if (months >= 36) return { label: "Platinum", color: "bg-violet-100 text-violet-700 border-violet-200", icon: "💎" };
  if (months >= 24) return { label: "Gold", color: "bg-amber-100 text-amber-700 border-amber-200", icon: "🥇" };
  if (months >= 12) return { label: "Silver", color: "bg-slate-100 text-slate-600 border-slate-200", icon: "🥈" };
  return { label: "Member", color: "bg-primary/10 text-primary border-primary/20", icon: "🔧" };
};

const getBookingRef = (id: string) => `ADAM-${id.substring(0, 6).toUpperCase()}`;

const getRecurrenceLabel = (rule?: string | null) => {
  switch (rule) {
    case "weekly":
      return "Every week";
    case "biweekly":
      return "Every 2 weeks";
    case "monthly":
      return "Every month";
    default:
      return null;
  }
};

const SERVICE_CARD_VISUALS: Record<string, { image: string; eyebrow: string; overlay: string }> = {
  snow_removal: {
    image: "https://images.pexels.com/photos/6952447/pexels-photo-6952447.jpeg?auto=compress&cs=tinysrgb&w=1600",
    eyebrow: "Winter service",
    overlay: "from-slate-950/55 via-slate-950/20 to-transparent",
  },
  yard_cleanup: {
    image: "https://images.pexels.com/photos/9620215/pexels-photo-9620215.jpeg?auto=compress&cs=tinysrgb&w=1600",
    eyebrow: "Outdoor service",
    overlay: "from-emerald-950/45 via-emerald-950/15 to-transparent",
  },
  gutter_cleaning: {
    image: "https://images.pexels.com/photos/35153375/pexels-photo-35153375.jpeg?auto=compress&cs=tinysrgb&w=1600",
    eyebrow: "Exterior upkeep",
    overlay: "from-sky-950/45 via-sky-950/15 to-transparent",
  },
  handyman: {
    image: heroHome,
    eyebrow: "Home repair",
    overlay: "from-neutral-950/55 via-neutral-950/20 to-transparent",
  },
  small_tasks: {
    image: "https://images.pexels.com/photos/4792482/pexels-photo-4792482.jpeg?auto=compress&cs=tinysrgb&w=1600",
    eyebrow: "Quick help",
    overlay: "from-stone-950/45 via-stone-950/15 to-transparent",
  },
  property_inspection: {
    image: "https://images.pexels.com/photos/5517853/pexels-photo-5517853.png?auto=compress&cs=tinysrgb&w=1600",
    eyebrow: "Property check",
    overlay: "from-slate-950/45 via-slate-950/15 to-transparent",
  },
};

const DASHBOARD_UPDATE_ACCENTS: Record<string, { rail: string; chip: string; panel: string }> = {
  snow_removal: {
    rail: "bg-sky-400/80",
    chip: "border-sky-200 bg-sky-50 text-sky-800",
    panel: "border-sky-200/70 bg-sky-50/80",
  },
  yard_cleanup: {
    rail: "bg-emerald-400/80",
    chip: "border-emerald-200 bg-emerald-50 text-emerald-800",
    panel: "border-emerald-200/70 bg-emerald-50/80",
  },
  gutter_cleaning: {
    rail: "bg-cyan-400/80",
    chip: "border-cyan-200 bg-cyan-50 text-cyan-800",
    panel: "border-cyan-200/70 bg-cyan-50/80",
  },
  handyman: {
    rail: "bg-amber-400/80",
    chip: "border-amber-200 bg-amber-50 text-amber-800",
    panel: "border-amber-200/70 bg-amber-50/80",
  },
  small_tasks: {
    rail: "bg-orange-400/80",
    chip: "border-orange-200 bg-orange-50 text-orange-800",
    panel: "border-orange-200/70 bg-orange-50/80",
  },
  property_inspection: {
    rail: "bg-violet-400/80",
    chip: "border-violet-200 bg-violet-50 text-violet-800",
    panel: "border-violet-200/70 bg-violet-50/80",
  },
};

const getServiceCardVisual = (serviceType?: string | null) =>
  SERVICE_CARD_VISUALS[serviceType || ""] || {
    image: comfortHome,
    eyebrow: "Service visit",
    overlay: "from-neutral-950/75 via-neutral-950/30 to-transparent",
  };

const getDashboardUpdateAccent = (serviceType?: string | null) =>
  DASHBOARD_UPDATE_ACCENTS[serviceType || ""] || {
    rail: "bg-rose-400/80",
    chip: "border-rose-200 bg-rose-50 text-rose-800",
    panel: "border-rose-200/70 bg-rose-50/80",
  };

const formatBookingTimeLabel = (value?: string | null) => {
  if (!value) return null;
  const normalized = value.trim().toLowerCase();
  if (normalized === "am") return "Morning";
  if (normalized === "pm") return "Afternoon";
  if (normalized === "anytime") return "Anytime";
  if (normalized === "tbd") return "Time TBD";

  if (/^\d{1,2}:\d{2}(:\d{2})?$/.test(value)) {
    const [hours, minutes] = value.split(":").map(Number);
    const date = new Date(2000, 0, 1, hours || 0, minutes || 0);
    return Number.isNaN(date.getTime()) ? value : format(date, "h:mm a");
  }

  return value;
};

const formatBookingSchedule = (booking: { start_date?: string | null; end_date?: string | null; start_time?: string | null }) => {
  const startLabel = formatSafeDate(booking.start_date, "EEEE, MMM d");
  const endLabel = formatSafeDate(booking.end_date, "EEEE, MMM d");
  const timeLabel = formatBookingTimeLabel(booking.start_time);

  if (!startLabel) return "Date TBD";
  if (endLabel && booking.end_date && booking.end_date !== booking.start_date) {
    return `${startLabel}${timeLabel ? ` · ${timeLabel}` : ""} — ${endLabel}`;
  }

  return `${startLabel}${timeLabel ? ` · ${timeLabel}` : ""}`;
};

const formatClientPropertyLabel = (address?: string | null) => {
  const parsed = parseAddress(address || null);
  if (!parsed.street.trim()) return "Your property";
  return [parsed.street, parsed.city].filter(Boolean).join(", ");
};

const stripKeepMarkers = (notes?: string | null) =>
  (notes || "")
    .split(/\r?\n/)
    .filter((line) => !/^\[Client keep · /i.test(line.trim()))
    .join("\n")
    .replace(/\n{3,}/g, "\n\n")
    .trim();

const hasCancellationMarker = (bookingLike?: { status?: string | null; payment_state?: string | null; notes?: string | null } | null) =>
  Boolean(
    bookingLike &&
      (bookingLike.status === "cancelled" ||
        bookingLike.payment_state === "cancelled" ||
        /\[Client cancellation · /i.test(bookingLike.notes || "")),
  );

const normalizeCancelledBooking = <T extends { status?: string | null; payment_state?: string | null; notes?: string | null } | null>(
  bookingLike: T,
) => {
  if (!hasCancellationMarker(bookingLike)) return bookingLike;
  return {
    ...bookingLike,
    status: "cancelled",
    payment_state: "cancelled",
  } as T;
};

const parseDashboardDateValue = (value?: string | null) => {
  if (!value) return null;
  if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
    return parseDateOnly(value);
  }
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? null : date;
};

const formatSafeDate = (value?: string | null, pattern = "MMM d, yyyy") => {
  const date = parseDashboardDateValue(value);
  return date ? format(date, pattern) : null;
};

const getSafeDate = (value?: string | null) => {
  return parseDashboardDateValue(value);
};

const formatSafeRelative = (value?: string | null) => {
  const date = getSafeDate(value);
  return date ? formatDistanceToNow(date, { addSuffix: true }) : null;
};

const getClientStatusLabel = (status?: string | null) => {
  switch (status) {
    case "requested":
      return "Waiting on us";
    case "approved":
    case "deposit_paid":
    case "confirmed":
      return "Booked";
    case "active":
      return "In progress";
    case "completed":
      return "Completed";
    case "cancelled":
      return "Cancelled";
    default:
      return "Update pending";
  }
};

const getRequestAgeState = (createdAt?: string | null) => {
  const created = getSafeDate(createdAt);
  if (!created) return { hours: 0, label: "Waiting for an update", tone: "normal" as const };
  const hours = differenceInHours(new Date(), created);

  if (hours >= 72) {
    return { hours, label: `Older request · waiting ${formatDistanceToNow(created)}.`, tone: "critical" as const };
  }

  if (hours >= 24) {
    return { hours, label: `Still waiting · ${formatDistanceToNow(created)} so far.`, tone: "warning" as const };
  }

  return { hours, label: `Requested ${formatDistanceToNow(created, { addSuffix: true })}.`, tone: "normal" as const };
};

type TimelineEntry = {
  id: string;
  type: "task" | "photo" | "message";
  timestamp: string;
  title: string;
  description?: string;
  imageUrl?: string;
  status?: string;
};

const ClientDashboard = () => {
  const { user } = useAuth();
  const [client, setClient] = useState<any>(null);
  const [bookings, setBookings] = useState<any[]>([]);
  const [pricingRules, setPricingRules] = useState<PricingRuleLike[]>([]);
  const [rateOverrides, setRateOverrides] = useState<RateOverrideLike[]>([]);
  const [propertyCount, setPropertyCount] = useState(0);
  const [tasks, setTasks] = useState<any[]>([]);
  const [messages, setMessages] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [activeBookingId, setActiveBookingId] = useState<string | null>(null);
  const [quickActionBookingId, setQuickActionBookingId] = useState<string | null>(null);
  const [unreadCount, setUnreadCount] = useState(0);
  const { toast } = useToast();
  const newMediaCount = useNewMediaCount();
  const photoBadges = useMemo(() => newMediaCount > 0 ? { "/client/photos": newMediaCount } : undefined, [newMediaCount]);
  const authMethodDisplay = user ? getAuthMethodDisplay(user) : null;

  // Activity tab state
  const [activityTab, setActivityTab] = useState<"upcoming" | "past" | "pending">("upcoming");
  const [showAllRecentUpdates, setShowAllRecentUpdates] = useState(false);
  const [viewedRecentUpdateKeys, setViewedRecentUpdateKeys] = useState<string[]>([]);
  const [persistedViewedRecentUpdateKeys, setPersistedViewedRecentUpdateKeys] = useState<string[]>([]);

  const [smsBannerDismissed, setSmsBannerDismissed] = useState(() => sessionStorage.getItem("adam_sms_banner_dismissed") === "1");

  useEffect(() => {
    if (!user?.id) {
      setViewedRecentUpdateKeys([]);
      setPersistedViewedRecentUpdateKeys([]);
      return;
    }

    try {
      const raw = localStorage.getItem(getDashboardViewedUpdatesStorageKey(user.id));
      if (!raw) {
        setViewedRecentUpdateKeys([]);
        return;
      }

      const parsed = JSON.parse(raw);
      setViewedRecentUpdateKeys(Array.isArray(parsed) ? parsed.filter((value): value is string => typeof value === "string") : []);
    } catch {
      setViewedRecentUpdateKeys([]);
    }
  }, [user?.id]);

  useEffect(() => {
    if (!user) return;
    let cancelled = false;

    const fetchData = async () => {
      // Retry client lookup — the record may still be creating via ensureProfileAndClient
      let c: any = null;
      for (let attempt = 0; attempt < 6; attempt++) {
        const { data: clients, error: clientErr } = await supabase.from("clients").select("*").eq("user_id", user.id);
        console.log(`[ADAM] Client lookup attempt ${attempt}:`, { userId: user.id, found: clients?.length, error: clientErr?.message });
        if (clients?.length) { c = clients[0]; break; }
        // After initial retries, actively create the client record as a fallback
        if (attempt === 3) {
          const meta = user.user_metadata || {};
          const fullName = meta.full_name || meta.name || [meta.first_name, meta.last_name].filter(Boolean).join(" ") || "";
          const email = user.email || meta.email || "";
          const parts = fullName.split(" ");
          await supabase.from("clients").upsert({
            user_id: user.id,
            name: fullName || email || "New Client",
            first_name: parts[0] || null,
            last_name: parts.slice(1).join(" ") || null,
            email: email || null,
            status: "active",
            zone: "TBD",
          }, { onConflict: "user_id", ignoreDuplicates: true });
          // Also ensure profile exists
          await supabase.from("profiles").upsert(
            { user_id: user.id, full_name: fullName || null },
            { onConflict: "user_id" }
          );
        }
        if (attempt < 5) await new Promise((r) => setTimeout(r, 1000));
      }
      if (cancelled) return;
      if (!c) { setLoading(false); return; }

      // Warm-start: if invite code in session, populate client from lead data
      const savedInvite = sessionStorage.getItem("adam_invite_code");
      if (savedInvite) sessionStorage.removeItem("adam_invite_code");

      // Try invite code first, then fall back to email match
      // Match any non-terminal lead status (not just "pending")
      const activeStatuses = ["pending", "contacted", "invited"];
      let lead: any = null;
      if (savedInvite) {
        const { data } = await supabase
          .from("leads")
          .select("*")
          .eq("invite_code", savedInvite)
          .in("status", activeStatuses)
          .maybeSingle();
        lead = data;
      }

      if (lead) {
        try {
            // Update client with lead data — prefer admin-entered lead data
            const updates: any = {};
            if (lead.first_name) updates.first_name = lead.first_name;
            if (lead.last_name) updates.last_name = lead.last_name;
            if (lead.email && !c.email) updates.email = lead.email;
            if (lead.mobile_phone) updates.phone = lead.mobile_phone;
            if (lead.address) updates.address = lead.address;
            if (lead.household_id) updates.household_id = lead.household_id;
            if (lead.first_name || lead.last_name) {
              updates.name = [lead.first_name, lead.last_name].filter(Boolean).join(" ");
            }
            // Carry over VIP flag
            if ((lead as any).vip) updates.vip = true;
            if (Object.keys(updates).length > 0) {
              await supabase.from("clients").update(updates).eq("id", c.id);
              c = { ...c, ...updates };
            }

            // Carry over lead pricing to client_pricing
            const leadDiscountPct = (lead as any).discount_pct;
            const leadCustomPricing = (lead as any).custom_pricing as Record<string, number> | null;
            if (leadDiscountPct || leadCustomPricing) {
              if (leadCustomPricing && typeof leadCustomPricing === "object") {
                // Insert per-service fixed prices
                for (const [serviceType, price] of Object.entries(leadCustomPricing)) {
                  await supabase.from("client_pricing").upsert({
                    client_id: c.id,
                    service_type: serviceType,
                    custom_price: price,
                    discount_pct: leadDiscountPct || null,
                    notes: "Carried over from lead",
                  }, { onConflict: "client_id,service_type" });
                }
              } else if (leadDiscountPct) {
                // Apply blanket discount
                await supabase.from("client_pricing").insert({
                  client_id: c.id,
                  service_type: "all",
                  discount_pct: leadDiscountPct,
                  notes: "Carried over from lead",
                });
              }
            }

            // Create pets from lead_pets — transfer ALL fields
            const { data: leadPets } = await supabase.from("lead_pets").select("*").eq("lead_id", lead.id);
            if (leadPets?.length) {
              for (const lp of leadPets) {
                await supabase.from("pets").insert({
                  client_id: c.id,
                  name: lp.name,
                  species: lp.species,
                  breed: lp.breed,
                  age: lp.age,
                  weight_kg: lp.weight_kg,
                  temperament: lp.temperament,
                  medical_notes: lp.medical_notes,
                  dietary_restrictions: lp.dietary_restrictions,
                  feeding_rules: lp.feeding_rules,
                  medications: lp.medications,
                  special_care_notes: lp.special_care_notes,
                  birthday: lp.birthday,
                  color: lp.color,
                  life_stage: lp.life_stage,
                  spayed_neutered: lp.spayed_neutered,
                  nicknames: lp.nicknames || [],
                  insurance_provider: lp.insurance_provider,
                  microchip_id: lp.microchip_id,
                  vet_name: lp.vet_name,
                  vet_clinic: lp.vet_clinic,
                  vet_phone: lp.vet_phone,
                  photo_url: lp.photo_url,
                });
              }
            }

            // Mark lead as converted
            await supabase.from("leads").update({
              status: "converted",
              converted_client_id: c.id,
            }).eq("id", lead.id);

            // Link household member
            if (lead.household_id) {
              await supabase.from("household_members")
                .update({ client_id: c.id })
                .eq("lead_id", lead.id)
                .eq("household_id", lead.household_id);
            }

            // Notify admin that a lead has converted
            const leadName = [lead.first_name, lead.last_name].filter(Boolean).join(" ");
            let householdName: string | undefined;
            if (lead.household_id) {
              const { data: hh } = await supabase.from("households").select("name").eq("id", lead.household_id).maybeSingle();
              householdName = hh?.name ?? undefined;
            }
        } catch (err) {
          console.error("Warm-start error:", err);
        }
      }

      // Auto-apply promo code from URL if stored
      const savedPromo = sessionStorage.getItem("adam_promo_code");
      if (savedPromo && c) {
        sessionStorage.removeItem("adam_promo_code");
        try {
          const { data: promoCode } = await supabase
            .from("promo_codes")
            .select("*")
            .eq("code", savedPromo)
            .eq("active", true)
            .maybeSingle();

          if (promoCode) {
            const notExpired = !promoCode.expires_at || new Date(promoCode.expires_at) > new Date();
            const notMaxed = !promoCode.max_uses || promoCode.current_uses < promoCode.max_uses;

            if (notExpired && notMaxed) {
              const { data: existing } = await supabase
                .from("client_promo_codes")
                .select("id")
                .eq("client_id", c.id)
                .eq("promo_code_id", promoCode.id)
                .maybeSingle();

              if (!existing) {
                await supabase
                  .from("client_promo_codes")
                  .insert({ client_id: c.id, promo_code_id: promoCode.id });
                toast({
                  title: "Code applied!",
                  description: promoCode.description || "Your special rate is now active.",
                });
              }
            }
          }
        } catch (err) {
          console.error("Auto-apply promo error:", err);
        }
      }

      setClient(c);

      const [
        { data: bookingData },
        { count: propertyTotal },
        { data: viewedDashboardUpdates, error: viewedDashboardUpdatesError },
        { data: pricingRuleData },
        { data: rateOverrideData },
      ] = await Promise.all([
        supabase
          .from("bookings")
          .select("*")
          .eq("client_id", c.id)
          .order("start_date", { ascending: false }),
        supabase
          .from("properties")
          .select("id", { count: "exact", head: true })
          .eq("client_id", c.id),
        supabase
          .from("client_dashboard_update_views")
          .select("change_key, change_family_key")
          .eq("client_id", c.id),
        supabase.from("pricing_rules").select("*").order("service_type"),
        supabase.from("rate_overrides").select("*").order("start_date"),
      ]);
      const normalizedBookings = (bookingData || []).map((booking: any) => normalizeCancelledBooking(booking));
      setBookings(normalizedBookings);
      setPricingRules(pricingRuleData || []);
      setRateOverrides(rateOverrideData || []);
      setPropertyCount(propertyTotal || 0);
      if (!viewedDashboardUpdatesError) {
        setPersistedViewedRecentUpdateKeys(
          Array.from(
            new Set(
              (viewedDashboardUpdates || []).flatMap((entry: any) =>
                [entry.change_key, entry.change_family_key].filter((value): value is string => typeof value === "string" && value.length > 0),
              ),
            ),
          ),
        );
      } else {
        setPersistedViewedRecentUpdateKeys([]);
      }
      cacheBookingSnapshots(normalizedBookings);

      const allBookingIds = normalizedBookings.map((b: any) => b.id);
      const activeIds = normalizedBookings
        .filter((b: any) => ["confirmed", "active"].includes(b.status))
        .map((b: any) => b.id);

      if (activeIds.length) {
        setActiveBookingId(activeIds[0]);
      }

      if (allBookingIds.length) {
        const [taskRes, msgRes] = await Promise.all([
          supabase.from("tasks").select("*, task_types(name, category)")
            .in("booking_id", allBookingIds)
            .order("scheduled_time", { ascending: false }).limit(200),
          activeIds.length
            ? supabase.from("messages").select("*")
                .eq("booking_id", activeIds[0])
                .order("created_at", { ascending: true })
            : Promise.resolve({ data: [] }),
        ]);
        setTasks(taskRes.data || []);
        setMessages(msgRes.data || []);

        // Keep the badge simple and reliable instead of relying on
        // read-receipt tables that are currently policy-restricted.
        if (activeIds.length) {
          const allMsgs = msgRes.data || [];
          const otherMsgs = allMsgs.filter((m: any) => m.sender_id !== user.id);
          setUnreadCount(otherMsgs.length);
        } else {
          setUnreadCount(0);
        }
      }

      setLoading(false);
    };

    fetchData();
    const channel = supabase
      .channel("client-unified")
      .on("postgres_changes", { event: "*", schema: "public", table: "clients" }, () => fetchData())
      .on("postgres_changes", { event: "*", schema: "public", table: "bookings" }, () => fetchData())
      .on("postgres_changes", { event: "*", schema: "public", table: "properties" }, () => fetchData())
      .on("postgres_changes", { event: "*", schema: "public", table: "tasks" }, () => fetchData())
      .on("postgres_changes", { event: "INSERT", schema: "public", table: "messages" }, () => fetchData())
      .subscribe();
    return () => { cancelled = true; supabase.removeChannel(channel); };
  }, [user]);

  const persistViewedRecentUpdates = (nextKeys: string[]) => {
    setViewedRecentUpdateKeys(nextKeys);
    if (!user?.id) return;
    localStorage.setItem(getDashboardViewedUpdatesStorageKey(user.id), JSON.stringify(nextKeys));
  };

  const handleAcknowledgeRecentUpdate = async (booking: any, change: NonNullable<ReturnType<typeof getBookingChangeSummary>>) => {
    const acknowledgementKeys = getDashboardAcknowledgementKeys(booking.id, change);
    const nextKeys = Array.from(new Set([...viewedRecentUpdateKeys, ...acknowledgementKeys])).slice(-200);
    persistViewedRecentUpdates(nextKeys);
    setPersistedViewedRecentUpdateKeys((current) => Array.from(new Set([...current, ...acknowledgementKeys])).slice(-200));

    if (!client?.id) return;

    const changeKey = getDashboardChangeKey(booking.id, change);
    const changeFamilyKey = getDashboardChangeFamilyKey(booking.id, change);
    const { error } = await supabase.from("client_dashboard_update_views").insert({
      client_id: client.id,
      booking_id: booking.id,
      change_type: change.type,
      change_key: changeKey,
      change_family_key: changeFamilyKey,
    });

    if (error && error.code !== "23505") {
      console.error("Failed to persist dashboard acknowledgement", error);
    }
  };

  // Derived data
  const memberSince = getSafeDate(client?.created_at);
  const memberMonths = memberSince ? differenceInMonths(new Date(), memberSince) : 0;
  const tier = loyaltyTier(memberMonths);

  // Tier milestone confetti celebration
  const [showTierCelebration, setShowTierCelebration] = useState<{ label: string; icon: string } | null>(null);
  useEffect(() => {
    if (!client?.id || tier.label === "Member") return;
    const key = `adam_tier_seen_${client.id}`;
    const lastSeen = localStorage.getItem(key);
    if (lastSeen !== tier.label) {
      localStorage.setItem(key, tier.label);
      if (lastSeen) {
        setShowTierCelebration({ label: tier.label, icon: tier.icon });
        setTimeout(() => setShowTierCelebration(null), 4000);
      }
    }
  }, [client?.id, tier.label]);

  const todayTasks = tasks.filter((t) => new Date(t.scheduled_time).toDateString() === new Date().toDateString());
  const completedToday = todayTasks.filter((t) => t.status === "completed").length;
  const activeBooking = bookings.find((b) => ["active", "confirmed"].includes(b.status));
  const recurringFamilies = useMemo(() => {
    const map = new Map<string, any[]>();
    bookings.forEach((booking) => {
      const familyId = booking.parent_booking_id || booking.id;
      const current = map.get(familyId) || [];
      current.push(booking);
      map.set(familyId, current);
    });
    return map;
  }, [bookings]);
  const liveRequests = bookings
    .filter((b) => ["requested", "approved", "deposit_paid", "confirmed", "active"].includes(b.status))
    .sort((a, b) => {
      const aCreated = getSafeDate(a.created_at)?.getTime() || 0;
      const bCreated = getSafeDate(b.created_at)?.getTime() || 0;
      return bCreated - aCreated;
    });
  const pendingBookings = liveRequests;
  const primaryPaymentBooking = null;
  const completedBookingsList = bookings.filter((b) => b.status === "completed");
  const completedBookings = completedBookingsList.length;
  const hasPropertyOnFile = propertyCount > 0;
  const hasAddressOnFile = Boolean(parseAddress(client?.address || null).street.trim());
  const primaryBookingHref = "/client/book";
  const showFirstRunChecklist = bookings.length === 0;

  // Activity tab data
  const upcomingBookings = bookings.filter((b) => {
    const endDate = getSafeDate(b.end_date);
    return ["confirmed", "active"].includes(b.status) && !!endDate && endDate >= new Date();
  });
  const pendingApproval = bookings.filter((b) => ["requested", "approved", "deposit_paid"].includes(b.status));
  const pastBookings = completedBookingsList;
  const nextUpcomingBooking = upcomingBookings[0] || null;
  const liveJobIds = new Set(liveRequests.map((booking) => booking.id));
  const recentBookingChanges = bookings
    .map((booking) => {
      const change = getBookingChangeSummary(booking);
      const occurredDate = change?.occurredAt ? getSafeDate(change.occurredAt) : null;
      const changeKey = change ? getDashboardChangeKey(booking.id, change) : null;

      return {
        booking,
        change,
        changeKey,
        occurredDate,
      };
    })
    .filter((entry): entry is {
      booking: any;
      change: NonNullable<ReturnType<typeof getBookingChangeSummary>>;
      changeKey: string;
      occurredDate: Date | null;
    } => Boolean(entry.change && entry.changeKey))
    .filter((entry) => {
      if (!entry.occurredDate) return true;
      return differenceInHours(new Date(), entry.occurredDate) <= 168;
    })
    .sort((a, b) => (b.occurredDate?.getTime() || 0) - (a.occurredDate?.getTime() || 0));
  const allViewedRecentUpdateKeys = useMemo(
    () => Array.from(new Set([...viewedRecentUpdateKeys, ...persistedViewedRecentUpdateKeys])),
    [persistedViewedRecentUpdateKeys, viewedRecentUpdateKeys],
  );
  const { visible: visibleRecentBookingChanges, viewed: viewedRecentBookingChanges } = useMemo(
    () => partitionDashboardRecentChanges(recentBookingChanges, allViewedRecentUpdateKeys),
    [allViewedRecentUpdateKeys, recentBookingChanges],
  );
  const displayedRecentBookingChanges = showAllRecentUpdates
    ? visibleRecentBookingChanges
    : visibleRecentBookingChanges.slice(0, DASHBOARD_VISIBLE_UPDATES_LIMIT);
  const hasCollapsedRecentBookingChanges = visibleRecentBookingChanges.length > DASHBOARD_VISIBLE_UPDATES_LIMIT;
  const bookingChangeById = new Map(recentBookingChanges.map((entry) => [entry.booking.id, entry.change]));
  useEffect(() => {
    if (visibleRecentBookingChanges.length <= DASHBOARD_VISIBLE_UPDATES_LIMIT) {
      setShowAllRecentUpdates(false);
    }
  }, [visibleRecentBookingChanges.length]);

  const oldestPendingBooking = pendingApproval
    .slice()
    .sort((a, b) => (getSafeDate(a.created_at)?.getTime() || 0) - (getSafeDate(b.created_at)?.getTime() || 0))[0] || null;
  const stalePendingCount = pendingApproval.filter((b) => getRequestAgeState(b.created_at).tone !== "normal").length;
  const liveRequestCards = useMemo(() => {
    const grouped = new Map<string, any[]>();
    liveRequests.forEach((booking) => {
      const familyId = booking.parent_booking_id || booking.id;
      const current = grouped.get(familyId) || [];
      current.push(booking);
      grouped.set(familyId, current);
    });

    return Array.from(grouped.entries())
      .map(([familyId, familyBookings]) => {
        const sortedByDate = familyBookings
          .slice()
          .sort((a, b) => (getSafeDate(a.start_date)?.getTime() || 0) - (getSafeDate(b.start_date)?.getTime() || 0));
        const representative =
          sortedByDate.find((entry) => !hasCancellationMarker(entry) && (getSafeDate(entry.end_date)?.getTime() || 0) >= new Date().setHours(0, 0, 0, 0)) ||
          sortedByDate[0];
        const recurrenceRule = representative?.recurrence_rule || sortedByDate.find((entry) => entry.recurrence_rule)?.recurrence_rule || null;
        const activeFamily = sortedByDate.filter((entry) => !hasCancellationMarker(entry));
        const representativeStartMs = getSafeDate(representative?.start_date)?.getTime() || 0;
        const futureVisits = activeFamily.filter((entry) => {
          if (entry.id === representative?.id) return false;
          const startMs = getSafeDate(entry.start_date)?.getTime() || 0;
          return startMs >= representativeStartMs;
        }).length;

        return {
          familyId,
          representative,
          familyBookings: sortedByDate,
          recurrenceRule,
          totalVisits: activeFamily.length,
          futureVisits,
        };
      })
      .sort((a, b) => {
        const aCancellationRequested = getSafeDate(a.representative?.cancellation_requested_at)?.getTime() || 0;
        const bCancellationRequested = getSafeDate(b.representative?.cancellation_requested_at)?.getTime() || 0;
        if (aCancellationRequested !== bCancellationRequested) {
          return bCancellationRequested - aCancellationRequested;
        }
        const aCreated = getSafeDate(a.representative?.created_at)?.getTime() || 0;
        const bCreated = getSafeDate(b.representative?.created_at)?.getTime() || 0;
        return bCreated - aCreated;
      });
  }, [liveRequests]);
  const featuredBookingCard = liveRequestCards.find((entry) => isCancellationReviewPending(entry.representative))
    || liveRequestCards.find((entry) => entry.representative?.id === oldestPendingBooking?.id)
    || liveRequestCards.find((entry) => entry.representative?.id === activeBooking?.id)
    || liveRequestCards.find((entry) => entry.representative?.id === nextUpcomingBooking?.id)
    || liveRequestCards[0]
    || null;
  const featuredBooking = featuredBookingCard?.representative || null;
  const secondaryLiveRequests = featuredBookingCard
    ? liveRequestCards.filter((entry) => entry.familyId !== featuredBookingCard.familyId)
    : liveRequestCards;

  const latestBookingMessage = messages[messages.length - 1] || null;
  const latestCommunication = latestBookingMessage
    ? {
        type: "booking",
        content: latestBookingMessage.message,
        created_at: latestBookingMessage.created_at,
        byTeam: latestBookingMessage.sender_id !== user?.id,
      }
    : null;
  const propertyLabel = formatClientPropertyLabel(client?.address);
  const getRecurringSummary = (bookingLike?: any) => {
    if (!bookingLike) return null;
    const familyId = bookingLike.parent_booking_id || bookingLike.id;
    const family = recurringFamilies.get(familyId) || [bookingLike];
    const recurrenceRule = bookingLike.recurrence_rule || family.find((entry) => entry.recurrence_rule)?.recurrence_rule || null;
    const recurrenceLabel = getRecurrenceLabel(recurrenceRule);
    if (!recurrenceLabel && family.length <= 1) return null;
    const activeFamily = family.filter((entry) => !hasCancellationMarker(entry));
    const bookingStart = getSafeDate(bookingLike.start_date)?.getTime() || 0;
    const futureVisits = activeFamily.filter((entry) => {
      if (entry.id === bookingLike.id) return false;
      const startMs = getSafeDate(entry.start_date)?.getTime() || 0;
      return startMs >= bookingStart;
    }).length;

    return {
      label: recurrenceLabel || "Repeat plan",
      totalVisits: activeFamily.length,
      futureVisits,
    };
  };

  const handleKeepBooking = async (booking: any) => {
    const timestamp = new Date().toISOString();
    const parsedNotes = parseBookingTeamFromNotes(booking.notes, booking.assigned_caregiver);
    const cleanClientNotes = stripKeepMarkers(parsedNotes.clientNotes);
    const keepLine = `[Client keep · ${timestamp}] Keeping ${formatBookingSchedule(booking)} as booked.`;
    const nextClientNotes = [cleanClientNotes, keepLine].filter(Boolean).join("\n\n").trim();
    const nextNotes = buildBookingNotes(nextClientNotes, parsedNotes.team, booking.assigned_caregiver);

    setQuickActionBookingId(booking.id);

    const { error } = await supabase
      .from("bookings")
      .update({
        notes: nextNotes,
        updated_at: timestamp,
      })
      .eq("id", booking.id);

    setQuickActionBookingId(null);

    if (error) {
      toast({
        title: "Couldn't keep this job yet",
        description: error.message,
        variant: "destructive",
      });
      return;
    }

    setBookings((current) => {
      const next = current.map((entry) =>
        entry.id === booking.id
          ? { ...entry, notes: nextNotes, updated_at: timestamp }
          : entry,
      );
      cacheBookingSnapshots(next);
      return next;
    });

    toast({
      title: "Kept as scheduled",
      description: "We’ll leave this job exactly as it is.",
    });
  };

  const renderDashboardBookingCard = (entry: any, options?: { featured?: boolean }) => {
    const booking = entry?.representative;
    if (!booking) return null;

    const featured = options?.featured ?? false;
    const age = getRequestAgeState(booking.created_at);
    const cancellationPending = isCancellationReviewPending(booking);
    const isOld = age.tone !== "normal" && booking.status === "requested";
    const recentChange = bookingChangeById.get(booking.id);
    const visual = getServiceCardVisual(booking.service_type);
    const recurringSummary = getRecurringSummary(booking);
    const premiumSummary = getClientBookingPremiumSummary({
      endDate: booking.end_date,
      pricingRules,
      rateOverrides,
      serviceType: booking.service_type,
      startDate: booking.start_date,
    });
    const showManageActions =
      !cancellationPending && ["requested", "approved", "deposit_paid", "confirmed"].includes(booking.status);
    const updatedLabel =
      cancellationPending
        ? `Cancellation requested ${formatSafeRelative(booking.cancellation_requested_at) || "recently"}.`
        : booking.status === "requested"
        ? age.label
        : `Updated ${formatSafeRelative(booking.updated_at || booking.created_at) || "recently"}.`;
    const manageLabel = cancellationPending
      ? "View request"
      : booking.status === "requested"
        ? "Manage request"
        : "Manage booking";
    const statusBadgeLabel = cancellationPending ? "Cancellation requested" : getClientStatusLabel(booking.status);
    const statusNeedsAttention = cancellationPending || booking.status === "requested" || isOld;
    const statusHelperText = cancellationPending
      ? "Review in progress"
      : booking.status === "requested"
        ? "Adam needs to review this"
        : booking.status === "active"
          ? "Work is underway"
          : "No action needed";

    return (
      <div
        key={entry.familyId}
        className={cn(
          "overflow-hidden rounded-[1.75rem] border bg-card",
          featured ? "border-primary/15 shadow-md" : "border-border/60 shadow-sm",
          isOld ? "ring-1 ring-status-warning/30" : "",
        )}
      >
        <div className={cn("relative overflow-hidden", featured ? "h-44 sm:h-48" : "h-32 sm:h-36")}>
          <img
            src={visual.image}
            alt={formatServiceTypeLabel(booking.service_type)}
            className="absolute inset-0 h-full w-full object-cover"
          />
          <div className={cn("absolute inset-0 bg-gradient-to-t", visual.overlay)} />
          <div className="absolute inset-0 bg-black/10" />
          <div className="relative flex h-full flex-col justify-between p-4 sm:p-5 text-white">
            <div className="flex items-center gap-2 flex-wrap">
              {featured && (
                <Badge className="border-0 bg-white text-foreground">
                  Current job
                </Badge>
              )}
              <Badge className="border-0 bg-white/15 text-white backdrop-blur-sm">
                {visual.eyebrow}
              </Badge>
              <Badge
                className={cn(
                  "border-0 backdrop-blur-sm",
                  cancellationPending
                    ? "bg-status-warning text-status-warning-foreground"
                    : booking.status === "requested"
                    ? "bg-status-warning text-status-warning-foreground"
                    : booking.status === "active"
                      ? "bg-primary text-primary-foreground"
                      : "bg-white/15 text-white",
                )}
              >
                {statusBadgeLabel}
              </Badge>
              {recentChange?.type === "rescheduled" && (
                <Badge className="border-0 bg-white text-foreground">
                  Date changed
                </Badge>
              )}
              {recurringSummary && (
                <Badge className="border-0 bg-white/15 text-white backdrop-blur-sm">
                  {recurringSummary.label}
                </Badge>
              )}
              {premiumSummary && (
                <Badge className="border-0 bg-amber-200 text-amber-950">
                  {premiumSummary.compact}
                </Badge>
              )}
            </div>

            <div className="space-y-1">
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-white/75">
                {propertyLabel}
              </p>
              <h3 className={cn("font-semibold tracking-tight", featured ? "text-3xl sm:text-4xl" : "text-2xl")}>
                {formatServiceTypeLabel(booking.service_type)}
              </h3>
              <p className="text-sm font-sans text-white/85">
                {updatedLabel}
              </p>
            </div>
          </div>
        </div>

        <div className="p-4 sm:p-5 space-y-4">
          <div className={cn("grid gap-3", featured ? "sm:grid-cols-3" : "sm:grid-cols-3")}>
            <div className="rounded-[1.25rem] border border-border/70 bg-background px-4 py-3">
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-muted-foreground">
                Scheduled
              </p>
              <p className="mt-1 text-sm font-medium text-foreground">
                {formatBookingSchedule(booking)}
              </p>
            </div>
            <div className="rounded-[1.25rem] border border-border/70 bg-background px-4 py-3">
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-muted-foreground">
                Reference
              </p>
              <p className="mt-1 text-sm font-medium text-foreground">
                {getBookingRef(booking.id)}
              </p>
            </div>
            <div
              className={cn(
                "rounded-[1.25rem] border px-4 py-3",
                statusNeedsAttention
                  ? "border-status-warning/60 bg-status-warning-muted/70 shadow-[0_0_0_1px_rgba(217,119,6,0.12)]"
                  : booking.status === "active"
                    ? "border-primary/30 bg-primary/5"
                    : "border-border/70 bg-background",
              )}
            >
              <div className="flex items-start justify-between gap-2">
                <div>
                  <p
                    className={cn(
                      "text-[11px] font-sans uppercase tracking-[0.18em]",
                      statusNeedsAttention ? "text-status-warning-foreground" : "text-muted-foreground",
                    )}
                  >
                    Status
                  </p>
                  <p
                    className={cn(
                      "mt-1 font-semibold text-foreground",
                      statusNeedsAttention ? "text-lg leading-tight" : "text-sm",
                    )}
                  >
                    {statusBadgeLabel}
                  </p>
                  <p
                    className={cn(
                      "mt-1 text-xs font-sans",
                      statusNeedsAttention ? "font-medium text-status-warning-foreground" : "text-muted-foreground",
                    )}
                  >
                    {statusHelperText}
                  </p>
                </div>
                {statusNeedsAttention && (
                  <span className="mt-0.5 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-status-warning text-status-warning-foreground">
                    <Clock className="h-4 w-4" />
                  </span>
                )}
              </div>
              {recurringSummary && (
                <p className="mt-2 border-t border-border/60 pt-2 text-xs font-sans text-muted-foreground">
                  {recurringSummary.totalVisits} visit{recurringSummary.totalVisits === 1 ? "" : "s"} scheduled
                </p>
              )}
            </div>
          </div>

          {premiumSummary && (
            <div className="rounded-[1.35rem] border border-amber-300 bg-amber-50 px-4 py-4 text-amber-950">
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-amber-800">
                Holiday premium
              </p>
              <p className="mt-2 text-sm font-semibold font-sans">
                {premiumSummary.detail}
              </p>
            </div>
          )}

          {recentChange ? (
            <div
              className={cn(
                "rounded-[1.35rem] border px-4 py-4",
                recentChange.type === "cancelled"
                  ? "border-destructive/25 bg-destructive/5"
                  : recentChange.type === "cancellation_requested"
                    ? "border-status-warning/30 bg-status-warning-muted/50"
                  : "border-primary/15 bg-primary/5",
              )}
            >
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-muted-foreground">
                Latest change
              </p>
              <p className="mt-2 text-sm font-medium text-foreground">
                {recentChange.banner}
              </p>
              <p className="mt-1 text-sm font-sans text-muted-foreground">
                {recentChange.detail}
              </p>
            </div>
          ) : (
            <div
              className={cn(
                "rounded-[1.35rem] border px-4 py-4",
                isOld
                  ? "border-status-warning/30 bg-status-warning-muted/50"
                  : "border-border/70 bg-muted/20",
              )}
            >
              <p className="text-[11px] font-sans uppercase tracking-[0.18em] text-muted-foreground">
                Overview
              </p>
              <p className="mt-2 text-sm font-medium text-foreground">
                {booking.status === "requested"
                  ? "This request is waiting on review. Open it for updates, messages, or a quick follow-up."
                  : cancellationPending
                    ? "Your cancellation request is in review. Open it for the status, timeline, and any follow-up from Adam."
                  : "This booking is on your schedule. Open it for the timeline, messages, and anything that changes."}
              </p>
              {cancellationPending && booking.cancellation_requested_reason && (
                <p className="mt-2 text-xs text-muted-foreground font-sans">
                  Reason: {booking.cancellation_requested_reason}
                </p>
              )}
            </div>
          )}

          <div className="grid gap-2 sm:grid-cols-2">
            <Button asChild className="rounded-full">
              <Link to={`/client/booking/${booking.id}`}>
                {manageLabel}
              </Link>
            </Button>
            <Button asChild variant="outline" className="rounded-full">
              <a href={`mailto:AdamNarciso@gmail.com?subject=${encodeURIComponent(`Question about ${getBookingRef(booking.id)}`)}`}>
                Message Adam
              </a>
            </Button>
          </div>

          {showManageActions ? (
            <div className="grid grid-cols-3 gap-2">
              <Button
                type="button"
                variant="secondary"
                className="rounded-full"
                disabled={quickActionBookingId === booking.id}
                onClick={() => void handleKeepBooking(booking)}
              >
                {quickActionBookingId === booking.id ? "Keeping..." : "Keep"}
              </Button>
              <Button asChild variant="outline" className="rounded-full">
                <Link to={`/client/booking/${booking.id}?action=change-dates`}>
                  Change date
                </Link>
              </Button>
              <Button asChild variant="outline" className="rounded-full border-destructive/30 text-destructive hover:bg-destructive/5">
                <Link to={`/client/booking/${booking.id}?action=cancel`}>
                  Cancel
                </Link>
              </Button>
            </div>
          ) : cancellationPending ? (
            <Button
              asChild
              variant="outline"
              className="rounded-full w-full border-status-warning/30 text-status-warning-foreground hover:bg-status-warning-muted/70"
            >
              <Link to={`/client/booking/${booking.id}`}>View request status</Link>
            </Button>
          ) : booking.status === "requested" ? (
            <Button
              asChild
              variant="outline"
              className={cn(
                "rounded-full w-full",
                isOld
                  ? "border-destructive/30 text-destructive hover:bg-destructive/5"
                  : "border-status-warning/30 text-status-warning-foreground hover:bg-status-warning-muted/70",
              )}
            >
              <a href={`mailto:AdamNarciso@gmail.com?subject=${encodeURIComponent(`Update request for ${getBookingRef(booking.id)}`)}`}>
                Nudge Adam
              </a>
            </Button>
          ) : null}
        </div>
      </div>
    );
  };


  if (loading) {
    return (
      <DashboardLayout navItems={clientNavItems} title="Home" badgeCounts={photoBadges}>
        <div className="space-y-4">
          {[1, 2, 3].map((i) => <div key={i} className="h-32 bg-muted rounded-2xl animate-pulse" />)}
        </div>
      </DashboardLayout>
    );
  }

  // Client record not found — still provisioning or error
  if (!client) {
    return (
      <DashboardLayout navItems={clientNavItems} title="Home" badgeCounts={photoBadges}>
        <div className="flex flex-col items-center justify-center py-16 text-center">
          <div className="w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center mb-6">
            <Wrench className="h-8 w-8 text-primary" />
          </div>
          <h2 className="text-xl font-medium mb-2">Almost there!</h2>
          <p className="text-sm text-muted-foreground font-sans mb-2 max-w-sm">
            We're finishing setting up your <strong>client account</strong>. This usually takes just a moment.
          </p>
          <p className="text-xs text-muted-foreground/60 font-sans mb-6 max-w-sm">
            Logged in as: {user?.email}
          </p>
          <div className="flex gap-3">
            <Button onClick={() => window.location.reload()} variant="outline" className="rounded-full">
              Refresh
            </Button>
            <Button onClick={async () => { await supabase.auth.signOut(); window.location.href = "/"; }} variant="ghost" className="rounded-full text-muted-foreground">
              Sign Out
            </Button>
          </div>
          <p className="text-xs text-muted-foreground/50 font-sans mt-8 max-w-xs">
            If this persists, please contact us at adamnarciso@adamproservices.ca
          </p>
        </div>
      </DashboardLayout>
    );
  }

  const needsProfileSetup = !client.first_name?.trim() || !client.last_name?.trim() || !client.phone?.trim();

  // Onboarding wizard removed — not applicable for handyman service

  return (
    <DashboardLayout navItems={clientNavItems} title="Home" badgeCounts={photoBadges}>
      <div className="space-y-6 relative">
        {/* SMS opt-in nudge */}
        {!smsBannerDismissed && client && (!client.sms_consent || !client.phone) && (
          <div className="relative flex items-start gap-3 rounded-2xl border border-primary/20 bg-primary/5 px-4 py-3">
            <Bell className="h-5 w-5 text-primary mt-0.5 shrink-0" />
            <div className="flex-1 min-w-0">
              <p className="text-sm font-medium font-sans">
                {!client.phone ? "Add your phone number" : "Enable text notifications"}
              </p>
              <p className="text-xs text-muted-foreground font-sans mt-0.5">
                {!client.phone
                  ? "Get booking updates and project check-ins via text message."
                  : "Receive SMS alerts when your booking is approved, work begins, and more."}
              </p>
              <Link
                to="/client/settings"
                className="inline-flex items-center gap-1 text-xs font-medium text-primary mt-1.5 hover:underline"
              >
                Go to Settings <ArrowRight className="h-3 w-3" />
              </Link>
            </div>
            <button
              onClick={() => { setSmsBannerDismissed(true); sessionStorage.setItem("adam_sms_banner_dismissed", "1"); }}
              className="p-1 rounded-full hover:bg-muted/60 text-muted-foreground"
              aria-label="Dismiss"
            >
              <X className="h-4 w-4" />
            </button>
          </div>
        )}
        {needsProfileSetup && bookings.length > 0 && (
          <Card className="border-primary/20 bg-gradient-to-br from-primary/5 to-accent/10 shadow-sm">
            <CardContent className="p-4 sm:p-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
              <div className="space-y-1">
                <p className="text-sm font-semibold">You are in. Details can wait.</p>
                <p className="text-sm text-muted-foreground font-sans">
                  Your account is ready. Add your phone and profile details later if you want faster updates and easier repeat booking.
                </p>
              </div>
              <Button asChild variant="outline" className="rounded-full shrink-0">
                <Link to="/client/settings">Settings later</Link>
              </Button>
            </CardContent>
          </Card>
        )}
        {/* Tier milestone confetti celebration */}
        {showTierCelebration && (() => {
          const confettiColors = [
            'hsl(var(--primary))',
            'hsl(var(--accent))',
            '#f59e0b',
            '#8b5cf6',
            '#ec4899',
            '#10b981',
          ];
          const particles = Array.from({ length: 50 }, (_, i) => ({
            color: confettiColors[i % confettiColors.length],
            left: Math.random() * 100,
            delay: Math.random() * 1,
            duration: 1.5 + Math.random() * 1.5,
            size: 4 + Math.random() * 6,
            rotation: Math.random() * 360,
            drift: (Math.random() - 0.5) * 80,
          }));
          return (
            <div className="fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm animate-fade-in" onClick={() => setShowTierCelebration(null)}>
              {particles.map((p, i) => (
                <span
                  key={i}
                  className="absolute top-0 rounded-full pointer-events-none"
                  style={{
                    left: `${p.left}%`,
                    width: p.size,
                    height: p.size,
                    backgroundColor: p.color,
                    transform: `rotate(${p.rotation}deg)`,
                    '--drift': `${p.drift}px`,
                    animation: `confetti-fall ${p.duration}s ${p.delay}s ease-out forwards`,
                  } as React.CSSProperties}
                />
              ))}
              <div className="text-center animate-scale-in">
                <div className="text-6xl mb-4">{showTierCelebration.icon}</div>
                <h2 className="text-2xl md:text-3xl font-semibold mb-2">Congratulations!</h2>
                <p className="text-lg text-muted-foreground font-sans">
                  You've reached <span className="font-bold text-foreground">{showTierCelebration.label}</span> tier
                </p>
                <p className="text-sm text-muted-foreground/70 font-sans mt-1">Thank you for being a loyal ADAM Pro client ✨</p>
              </div>
            </div>
          );
        })()}
        {/* Welcome + Loyalty — compact header */}
        <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
          <div>
            <h1 className="text-2xl md:text-3xl font-medium tracking-tight">
              {completedBookings === 0 && !activeBooking
                ? `Welcome${client?.preferred_name ? `, ${client.preferred_name}` : client?.name ? `, ${client.name.split(" ")[0]}` : ""} 🌿`
                : `Welcome back${client?.preferred_name ? `, ${client.preferred_name}` : client?.name ? `, ${client.name.split(" ")[0]}` : ""} 👋`}
            </h1>
            <p className="text-sm text-muted-foreground font-sans mt-1">
              {"Here's what's happening with your projects."}
            </p>
            {authMethodDisplay && (
              <p className="mt-2 flex max-w-full items-center gap-2 text-xs text-muted-foreground font-sans">
                <Mail className="h-3.5 w-3.5 shrink-0 text-primary" aria-hidden="true" />
                <span className="min-w-0 truncate">{authMethodDisplay}</span>
              </p>
            )}
          </div>
          <div className="flex items-center gap-3 flex-wrap">
            {client?.vip && (
              <Badge className="bg-amber-50 text-amber-700 border border-amber-200 gap-1 px-3 py-1.5">
                <Star className="h-3 w-3 fill-amber-500" /> VIP
              </Badge>
            )}
            <div className="flex items-center gap-2 px-4 py-2 rounded-full border text-sm font-sans bg-gradient-to-r from-amber-50 to-amber-100/80 border-amber-300/60 text-amber-800 shadow-sm">
              <span className="text-base">{tier.icon}</span>
              <span className="font-semibold">{tier.label}</span>
              {memberSince && <span className="text-xs text-amber-600/70">· Since {format(memberSince, "yyyy")}</span>}
            </div>
          </div>
        </div>

        {!showFirstRunChecklist && (
          <Card className="rounded-[2rem] border-primary/15 bg-background/95 shadow-sm overflow-hidden">
            <CardContent className="p-5 sm:p-6 flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
              <div className="min-w-0">
                <div className="flex items-center gap-2 flex-wrap">
                  <Badge className="border-0 bg-primary text-primary-foreground">
                    Start something new
                  </Badge>
                  <span className="text-xs font-sans text-muted-foreground">
                    Your other bookings stay tracked right here
                  </span>
                </div>
                <h2 className="mt-3 text-2xl sm:text-3xl font-semibold tracking-tight">
                  Book a new service
                </h2>
                <p className="mt-2 max-w-2xl text-sm text-muted-foreground font-sans">
                  Repairs, installs, seasonal work, and one-off help can all start from one quick request.
                </p>
              </div>

              <div className="flex items-center gap-2">
                <Button asChild className="rounded-full shrink-0">
                  <Link to={primaryBookingHref}>
                    <CalendarDays className="h-4 w-4" />
                    Book Now
                  </Link>
                </Button>
              </div>
            </CardContent>
          </Card>
        )}

        {/* First-run welcome card — no bookings yet */}
        {showFirstRunChecklist && (
          <Card className="border-primary/20 bg-gradient-to-br from-primary/5 to-accent/10 shadow-sm overflow-hidden">
            <CardContent className="p-5 space-y-4">
              <div className="flex items-start gap-3">
                <div className="h-10 w-10 rounded-2xl bg-primary/10 flex items-center justify-center shrink-0">
                  <Sparkles className="h-5 w-5 text-primary" />
                </div>
                <div>
                  <h3 className="text-base font-medium">
                    {hasPropertyOnFile
                      ? "Your fastest path to a booking"
                      : hasAddressOnFile
                        ? "One quick confirmation, then you can book"
                        : "One quick setup item, then you can book"}
                  </h3>
                  <p className="text-sm text-muted-foreground font-sans mt-1">
                    {hasPropertyOnFile
                      ? "Three quick steps to send your first request. Profile details can wait."
                      : hasAddressOnFile
                        ? "We saved your address. Confirm it as your service property, then it is just service, date, and send request."
                        : "We need your property first. After that, it is just service, date, and send request."}
                  </p>
                </div>
              </div>
              <div className="space-y-2.5">
                {[
                  {
                    done: hasPropertyOnFile,
                    label: hasPropertyOnFile
                      ? "Property on file"
                      : hasAddressOnFile
                        ? "Confirm your property"
                        : "Add your property",
                    sub: hasPropertyOnFile
                      ? "You already have a service address saved"
                      : hasAddressOnFile
                        ? "We pre-filled your saved address for you"
                        : "Just the service address for now",
                    href: "/client/book",
                  },
                  {
                    done: false,
                    label: "Choose your service and date",
                    sub: "Pick what you need and the day that works",
                    href: "/client/book",
                  },
                  {
                    done: false,
                    label: "Send your request",
                    sub: "Adam gets it right away and updates you here",
                    href: "/client/book",
                  },
                ].map((step, i) => (
                  <Link
                    key={i}
                    to={step.href}
                    className={`flex items-center gap-3 rounded-xl px-3 py-2.5 transition-colors ${step.done ? "bg-primary/5" : "bg-background hover:bg-muted/50"}`}
                  >
                    {step.done ? (
                      <CheckCircle2 className="h-5 w-5 text-primary shrink-0" />
                    ) : (
                      <div className="h-5 w-5 rounded-full border-2 border-muted-foreground/30 shrink-0 flex items-center justify-center">
                        <span className="text-[10px] font-bold text-muted-foreground">{i + 1}</span>
                      </div>
                    )}
                    <div className="flex-1 min-w-0">
                      <p className={`text-sm font-medium ${step.done ? "text-muted-foreground line-through" : ""}`}>{step.label}</p>
                      <p className="text-xs text-muted-foreground font-sans">{step.done ? step.sub : step.sub}</p>
                    </div>
                    <ArrowRight className="h-4 w-4 text-muted-foreground shrink-0" />
                  </Link>
                ))}
              </div>
              {!hasPropertyOnFile && (
                <div className="rounded-xl bg-background/80 border border-primary/15 px-3.5 py-3">
                  <p className="text-xs font-medium text-foreground font-sans">Why we ask for the property first</p>
                  <p className="text-xs text-muted-foreground font-sans mt-1">
                    Your property helps Adam quote accurately, evaluate the work, and keep your request moving without extra back-and-forth.
                  </p>
                </div>
              )}
              {needsProfileSetup && (
                <div className="rounded-xl bg-background/70 border border-border/60 px-3.5 py-3">
                  <p className="text-xs font-medium text-foreground font-sans">Optional later</p>
                  <p className="text-xs text-muted-foreground font-sans mt-1">
                    Phone, address details, and preferences can wait until after you have sent your first request.
                  </p>
                  <Link to="/client/settings" className="inline-flex items-center gap-1 text-xs font-medium text-primary mt-2 hover:underline">
                    Open settings later <ArrowRight className="h-3 w-3" />
                  </Link>
                </div>
              )}
            </CardContent>
          </Card>
        )}

        {/* ===== REBOOK BANNER — pattern-based suggestion ===== */}
        {(() => {
          if (bookings.length === 0) return null;
          const completed = bookings.filter(b => b.status === "completed");
          const last = bookings[0]; // most recent
          const lastStart = getSafeDate(last.start_date);
          if (!lastStart) return null;
          const daysSince = differenceInDays(new Date(), lastStart);
          if (daysSince < 60) return null;
          // Check for anniversary pattern
          const nextYear = new Date(lastStart);
          nextYear.setFullYear(nextYear.getFullYear() + 1);
          const daysUntilAnniversary = differenceInDays(nextYear, new Date());
          const isAnniversary = daysUntilAnniversary > 0 && daysUntilAnniversary <= 60;
          return (
            <div className="rounded-2xl bg-gradient-to-r from-primary/10 via-primary/5 to-accent/10 border border-primary/15 px-4 py-3.5 flex items-center gap-3 animate-fade-in">
              <div className="w-10 h-10 rounded-full bg-primary/15 flex items-center justify-center shrink-0">
                <RotateCcw className="h-5 w-5 text-primary" />
              </div>
              <div className="flex-1 min-w-0">
                <p className="text-sm font-medium">
                  {isAnniversary
                    ? "Same time as last year? Book your next service"
                    : "It's been a while — time to book your next service?"}
                </p>
                <p className="text-xs text-muted-foreground font-sans mt-0.5 capitalize">
                  Last: {last.service_type.replace(/_/g, " ")} · {format(lastStart, "MMM d, yyyy")}
                  {isAnniversary && ` → Suggested: ${format(nextYear, "MMM d")}`}
                </p>
              </div>
              <Button asChild size="sm" className="rounded-full shrink-0">
                <Link to={`/client/book?service=${last.service_type}${isAnniversary ? `&date=${format(nextYear, "yyyy-MM-dd")}` : ""}`}>
                  Rebook
                </Link>
              </Button>
            </div>
          );
        })()}

        {visibleRecentBookingChanges.length > 0 && (
          <Card className="rounded-[2rem] border-primary/15 bg-background/95 shadow-sm overflow-hidden">
            <CardContent className="p-5 sm:p-6 space-y-4">
              <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
                <div>
                  <div className="flex items-center gap-2 flex-wrap">
                    <Badge className="border-0 bg-primary/10 text-primary">
                      Recent updates
                    </Badge>
                    <span className="text-xs font-sans text-muted-foreground">
                      Something changed on {visibleRecentBookingChanges.length} booking{visibleRecentBookingChanges.length === 1 ? "" : "s"}
                    </span>
                  </div>
                  <h2 className="mt-2 text-xl sm:text-2xl font-semibold tracking-tight">
                    We changed something on your jobs.
                  </h2>
                  <p className="text-sm text-muted-foreground font-sans mt-1 max-w-2xl">
                    Cancellations and date changes show up here first, so you always know what changed. Once you acknowledge them, they move out of Home and remain part of your History.
                  </p>
                </div>
                <div className="flex flex-wrap items-center gap-2">
                  {hasCollapsedRecentBookingChanges && (
                    <Button
                      type="button"
                      variant="outline"
                      className="rounded-full"
                      onClick={() => setShowAllRecentUpdates((current) => !current)}
                    >
                      {showAllRecentUpdates ? "Show fewer" : `Show all (${visibleRecentBookingChanges.length})`}
                    </Button>
                  )}
                  {viewedRecentBookingChanges.length > 0 && (
                    <Button asChild type="button" variant="outline" className="rounded-full">
                      <Link to="/client/care-history">Open history</Link>
                    </Button>
                  )}
                </div>
              </div>

                <div className="space-y-3">
                  {displayedRecentBookingChanges.map(({ booking, change, changeKey, occurredDate }) => {
                    const isCancelled = change.type === "cancelled";
                    const accent = getDashboardUpdateAccent(booking.service_type);
                    const scheduledDateLabel = formatSafeDate(booking.start_date, "EEEE, MMM d, yyyy") || "Date TBD";
                    const bookedDateLabel = formatSafeDate(booking.created_at, "MMM d, yyyy") || "Unknown";
                    const changeDateLabel =
                      change.type === "cancelled"
                        ? formatSafeDate(booking.cancelled_at || booking.cancellation_reviewed_at || change.occurredAt, "MMM d, yyyy") || "Recently"
                        : change.type === "cancellation_requested"
                          ? formatSafeDate(booking.cancellation_requested_at || change.occurredAt, "MMM d, yyyy") || "Recently"
                          : formatSafeDate(change.occurredAt, "MMM d, yyyy") || "Recently";
                    const changeDateTitle =
                      change.type === "cancelled"
                        ? "Cancelled"
                        : change.type === "cancellation_requested"
                          ? "Requested"
                          : "Changed";
                    const relativeLabel =
                      change.type === "cancelled"
                        ? "Cancelled"
                        : change.type === "cancellation_requested"
                          ? "Requested"
                          : "Updated";

                    return (
                      <div
                        key={changeKey}
                        className={cn(
                          "relative overflow-hidden rounded-[1.5rem] border px-4 py-4 shadow-sm transition-colors",
                          isCancelled
                            ? "border-destructive/25 bg-destructive/5"
                            : change.type === "cancellation_requested"
                              ? "border-status-warning/30 bg-status-warning-muted/50"
                            : "border-primary/20 bg-primary/5",
                        )}
                      >
                        <div className={cn("absolute inset-y-4 left-0 w-1 rounded-r-full", accent.rail)} />
                        <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
                          <div className="space-y-2 min-w-0">
                            <div className="flex items-center gap-2 flex-wrap">
                              <Badge
                                className={cn(
                                  "border-0",
                                  isCancelled
                                    ? "bg-destructive text-destructive-foreground"
                                    : change.type === "cancellation_requested"
                                      ? "bg-status-warning text-status-warning-foreground"
                                    : "bg-primary text-primary-foreground",
                                )}
                              >
                                {change.banner}
                              </Badge>
                              <p className="text-base sm:text-lg font-semibold font-sans text-foreground">
                                {change.title}
                              </p>
                              <Badge className={cn("border text-[11px] font-medium", accent.chip)}>
                                {getBookingRef(booking.id)}
                              </Badge>
                            </div>
                            <p className="text-sm text-muted-foreground font-sans">
                              {change.detail}
                            </p>
                            <div className="grid gap-2 sm:grid-cols-3">
                              <div className={cn("rounded-[1rem] border px-3 py-2", accent.panel)}>
                                <p className="text-[10px] font-sans uppercase tracking-[0.16em] text-muted-foreground">
                                  Scheduled
                                </p>
                                <p className="mt-1 text-sm font-medium text-foreground">
                                  {scheduledDateLabel}
                                </p>
                              </div>
                              <div className={cn("rounded-[1rem] border px-3 py-2", accent.panel)}>
                                <p className="text-[10px] font-sans uppercase tracking-[0.16em] text-muted-foreground">
                                  Booked
                                </p>
                                <p className="mt-1 text-sm font-medium text-foreground">
                                  {bookedDateLabel}
                                </p>
                              </div>
                              <div className={cn("rounded-[1rem] border px-3 py-2", accent.panel)}>
                                <p className="text-[10px] font-sans uppercase tracking-[0.16em] text-muted-foreground">
                                  {changeDateTitle}
                                </p>
                                <p className="mt-1 text-sm font-medium text-foreground">
                                  {changeDateLabel}
                                </p>
                              </div>
                            </div>
                            <p className="text-xs font-sans text-muted-foreground">
                              {occurredDate
                                ? `${relativeLabel} ${formatDistanceToNow(occurredDate, { addSuffix: true })}.`
                                : `${relativeLabel} recently.`}
                            </p>
                          </div>

                          <div className="flex flex-wrap items-center gap-2 lg:justify-end">
                            <Button
                              type="button"
                              variant="outline"
                              className="rounded-full"
                              onClick={() => void handleAcknowledgeRecentUpdate(booking, change)}
                            >
                              Acknowledge
                            </Button>
                            <Button asChild className="rounded-full">
                              <Link to={`/client/booking/${booking.id}`}>View update</Link>
                            </Button>
                          </div>
                        </div>
                      </div>
                    );
                  })}
                </div>
            </CardContent>
          </Card>
        )}

        {/* Profile nudge section removed — pet-specific content not applicable */}

        {(liveRequestCards.length > 0 || nextUpcomingBooking) && (
          <div className="space-y-4">
            <Card className="rounded-[2rem] border-border/70 bg-background shadow-sm overflow-hidden">
              <CardContent className="p-5 sm:p-6 space-y-5">
                <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
                  <div>
                    <div className="flex items-center gap-2 flex-wrap">
                      <Badge className="border-0 bg-primary text-primary-foreground">
                        Current job
                      </Badge>
                      <span className="text-xs font-sans text-muted-foreground">
                        {liveRequestCards.length} live job{liveRequestCards.length === 1 ? "" : "s"}
                      </span>
                      {stalePendingCount > 0 && (
                        <Badge className="border-0 bg-status-warning text-status-warning-foreground">
                          {stalePendingCount} needs attention
                        </Badge>
                      )}
                    </div>
                    <h2 className="mt-2 text-2xl sm:text-3xl font-semibold tracking-tight">
                      Track one job at a time.
                    </h2>
                    <p className="text-sm text-muted-foreground font-sans mt-1 max-w-2xl">
                      Your main booking stays front and center, with quick actions and clear details instead of a busy dashboard.
                    </p>
                  </div>

                  <a
                    href="mailto:AdamNarciso@gmail.com"
                    className="text-sm text-primary underline underline-offset-2 font-sans"
                  >
                    Need help? Email Adam
                  </a>
                </div>

                {featuredBooking && (
                  renderDashboardBookingCard(featuredBookingCard, { featured: true })
                )}

                {secondaryLiveRequests.length > 0 && (
                  <div className="space-y-3">
                    <div className="flex items-center gap-2">
                      <Badge className="border-0 bg-primary/10 text-primary">More jobs</Badge>
                      <span className="text-xs font-sans text-muted-foreground">
                        {secondaryLiveRequests.length} more job{secondaryLiveRequests.length === 1 ? "" : "s"}
                      </span>
                    </div>
                    <div className="space-y-4">
                      {secondaryLiveRequests.map((entry) => renderDashboardBookingCard(entry))}
                    </div>
                  </div>
                )}
              </CardContent>
            </Card>
          </div>
        )}

        {/* ===== ACTION BANNERS — Book Service + Messages ===== */}
        <div className={showFirstRunChecklist ? "grid grid-cols-1 gap-3" : "grid grid-cols-2 gap-3"}>
          {!showFirstRunChecklist && (
            <Link to={primaryBookingHref} className="group">
              <div className="rounded-2xl border border-primary/20 bg-gradient-to-br from-primary/10 via-primary/5 to-accent/10 p-4 h-full flex flex-col justify-between gap-3 hover:border-primary/40 hover:shadow-md transition-all">
                <div className="w-10 h-10 rounded-xl bg-primary/15 flex items-center justify-center">
                  <CalendarDays className="h-5 w-5 text-primary" />
                </div>
                <div>
                  <h3 className="text-sm font-semibold">Book Service</h3>
                  <p className="text-[11px] text-muted-foreground font-sans mt-0.5 leading-snug">
                    {pendingBookings.length > 0
                      ? `${pendingBookings.length} active booking${pendingBookings.length > 1 ? "s" : ""}`
                      : hasPropertyOnFile
                        ? "Repairs, installs & more"
                        : hasAddressOnFile
                          ? "Confirm your saved address first"
                          : "Add your property first"}
                  </p>
                </div>
                <div className="flex items-center gap-1 text-xs font-medium text-primary">
                  {pendingBookings.length > 0
                    ? "Book again"
                    : hasPropertyOnFile
                      ? "Get started"
                      : hasAddressOnFile
                        ? "Finish property"
                        : "Add property"} <ArrowRight className="h-3 w-3 group-hover:translate-x-0.5 transition-transform" />
                </div>
              </div>
            </Link>
          )}

          <Link to={activeBookingId ? `/client/booking/${activeBookingId}` : "/client/book"} className="group">
            <div className="rounded-2xl border border-border/40 bg-gradient-to-br from-accent/10 via-muted/30 to-muted/10 p-4 h-full flex flex-col justify-between gap-3 hover:border-primary/30 hover:shadow-md transition-all relative">
              <div className="w-10 h-10 rounded-xl bg-accent/20 flex items-center justify-center relative">
                <MessageCircle className="h-5 w-5 text-primary" />
                {unreadCount > 0 && (
                  <span className="absolute -top-1 -right-1 h-5 min-w-[20px] px-1 rounded-full bg-destructive text-destructive-foreground text-[10px] font-bold flex items-center justify-center">
                    {unreadCount}
                  </span>
                )}
              </div>
              <div>
                <h3 className="text-sm font-semibold">Messages</h3>
                <p className="text-[11px] text-muted-foreground font-sans mt-0.5 leading-snug">
                  {unreadCount > 0
                    ? `${unreadCount} unread message${unreadCount > 1 ? "s" : ""}`
                    : latestCommunication
                      ? `Last: ${formatSafeDate(latestCommunication.created_at, "MMM d") || "recently"}`
                      : "Chat with your service team"}
                </p>
              </div>
              <div className="flex items-center gap-1 text-xs font-medium text-primary">
                {unreadCount > 0 ? "Read now" : "Open chat"} <ArrowRight className="h-3 w-3 group-hover:translate-x-0.5 transition-transform" />
              </div>
            </div>
          </Link>
        </div>

        {/* Pet section removed — not applicable for handyman service */}

        {/* Secondary quick actions */}
        <div className="flex gap-2 flex-wrap items-center">
          <Button variant="outline" className="rounded-full gap-1.5 text-xs" size="sm" asChild>
            <Link to="/client/payments"><FileText className="h-3.5 w-3.5" /> Invoices & Statements</Link>
          </Button>
          <Button variant="outline" className="rounded-full gap-1.5 text-xs" size="sm" asChild>
            <Link to="/client/photos">Project Photos</Link>
          </Button>
        </div>
        <div className="grid gap-4 md:grid-cols-2">

          {/* ── Large tile: Today's Jobs (if any) ── */}
          {todayTasks.length > 0 && (
            <Card className="rounded-2xl md:col-span-2">
              <CardContent className="py-4 space-y-3">
                <div className="flex items-center gap-3">
                  <div className="w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center text-primary">
                    <CheckCircle2 className="h-4 w-4" />
                  </div>
                  <h3 className="text-sm font-medium">Today's Jobs</h3>
                  <Badge variant="secondary" className="text-[10px]">{completedToday}/{todayTasks.length}</Badge>
                </div>
                <Progress value={todayTasks.length ? (completedToday / todayTasks.length) * 100 : 0} className="h-1.5" />
                {todayTasks.map((task) => (
                  <div key={task.id} className="flex items-center justify-between py-2 border-b border-border/30 last:border-0">
                    <div className="flex items-center gap-3">
                      <div className={`w-5 h-5 rounded-full flex items-center justify-center ${task.status === "completed" ? "bg-primary text-primary-foreground" : "border-2 border-border"}`}>
                        {task.status === "completed" && <CheckCircle2 className="h-3 w-3" />}
                      </div>
                      <div>
                        <p className="text-sm font-sans capitalize">{task.task_types?.name?.replace("_", " ")}</p>
                        <p className="text-xs text-muted-foreground font-sans">{formatSafeDate(task.scheduled_time, "h:mm a") || "Time TBD"}</p>
                      </div>
                    </div>
                    {task.photo_url && (
                      <div className="w-8 h-8 rounded-lg overflow-hidden">
                        <SignedImage storagePath={task.photo_url} alt="" className="w-full h-full object-cover" />
                      </div>
                    )}
                  </div>
                ))}
              </CardContent>
            </Card>
          )}

          {/* ── Activity Tabs: Upcoming · Past · Pending ── */}
          <Card className="rounded-2xl md:col-span-2">
            <CardContent className="py-4 space-y-3">
              <div className="flex items-center gap-3">
                <div className="w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center text-primary">
                  <CalendarDays className="h-4 w-4" />
                </div>
                <h3 className="text-sm font-medium">Activity</h3>
              </div>

              {/* Tab buttons */}
              <div className="flex gap-1 bg-muted/50 rounded-xl p-1">
                {([
                  { key: "upcoming" as const, label: "Upcoming", count: upcomingBookings.length },
                  { key: "past" as const, label: "Past", count: pastBookings.length },
                  { key: "pending" as const, label: "Pending", count: pendingApproval.length },
                ]).map(({ key, label, count }) => (
                  <button
                    key={key}
                    onClick={() => setActivityTab(key)}
                    className={`flex-1 text-xs font-sans font-medium py-2 px-3 rounded-lg transition-all ${
                      activityTab === key
                        ? key === "pending" && count > 0
                          ? "bg-status-warning-muted text-status-warning-foreground shadow-sm ring-1 ring-status-warning/30"
                          : "bg-background text-foreground shadow-sm"
                        : "text-muted-foreground hover:text-foreground"
                    }`}
                  >
                    {label}
                    {count > 0 && (
                      <Badge variant={activityTab === key ? "default" : "secondary"} className="ml-1.5 text-[9px] px-1.5 py-0">
                        {count}
                      </Badge>
                    )}
                  </button>
                ))}
              </div>

              {/* Tab content */}
              <div className="space-y-2 min-h-[100px]">
                {activityTab === "upcoming" && (
                  upcomingBookings.length === 0 ? (
                    <div className="text-center py-6">
                      <CalendarDays className="h-8 w-8 mx-auto text-muted-foreground/30 mb-2" />
                      <p className="text-sm text-muted-foreground font-sans">No upcoming bookings</p>
                      <Button asChild size="sm" className="rounded-full mt-3 gap-1.5">
                        <Link to="/client/book"><Sparkles className="h-3 w-3" /> Book Service</Link>
                      </Button>
                    </div>
                  ) : (
                    upcomingBookings.map((b) => {
                      const statusLabel: Record<string, string> = { confirmed: "Confirmed", active: "In Progress" };
                      return (
                        <Link key={b.id} to={`/client/booking/${b.id}`} className="block">
                          <div className="flex items-center justify-between py-3 px-3 rounded-xl hover:bg-muted/30 transition-colors border border-border/30">
                            <div className="flex items-center gap-3">
                              <div className="w-9 h-9 rounded-lg bg-primary/10 flex items-center justify-center">
                                {b.status === "active" ? <CheckCircle2 className="h-4 w-4 text-primary" /> : <Clock className="h-4 w-4 text-primary" />}
                              </div>
                               <div>
                                <div className="flex items-center gap-2">
                                  <p className="text-sm font-sans font-medium capitalize">{b.service_type.replace(/_/g, " ")}</p>
                                  <span className="text-[9px] font-mono text-muted-foreground/60">{getBookingRef(b.id)}</span>
                                </div>
                                <p className="text-xs text-muted-foreground font-sans">
                                  {formatSafeDate(b.start_date, "MMM d") || "Date TBD"} — {formatSafeDate(b.end_date, "MMM d") || "TBD"}
                                </p>
                              </div>
                            </div>
                            <Badge className={`text-[10px] border-0 ${b.status === "active" ? "bg-primary text-primary-foreground" : "bg-primary/10 text-primary"}`}>
                              {statusLabel[b.status] || b.status}
                            </Badge>
                          </div>
                        </Link>
                      );
                    })
                  )
                )}

                {activityTab === "past" && (
                  pastBookings.length === 0 ? (
                    <div className="text-center py-6">
                      <Clock className="h-8 w-8 mx-auto text-muted-foreground/30 mb-2" />
                      <p className="text-sm text-muted-foreground font-sans">No completed bookings yet</p>
                    </div>
                  ) : (
                    pastBookings.slice(0, 6).map((b) => (
                      <div key={b.id} className="flex items-center justify-between py-3 px-3 rounded-xl border border-border/30">
                         <div>
                          <div className="flex items-center gap-2">
                            <p className="text-sm font-sans capitalize">{b.service_type.replace(/_/g, " ")}</p>
                            <span className="text-[9px] font-mono text-muted-foreground/60">{getBookingRef(b.id)}</span>
                          </div>
                          <p className="text-xs text-muted-foreground font-sans">
                            {formatSafeDate(b.start_date, "MMM d") || "Date TBD"} — {formatSafeDate(b.end_date, "MMM d, yyyy") || "TBD"}
                          </p>
                        </div>
                        <Badge variant="secondary" className="text-[10px] gap-1">Completed</Badge>
                      </div>
                    ))
                  )
                )}

                {activityTab === "pending" && (
                  pendingApproval.length === 0 ? (
                    <div className="text-center py-6">
                      <Clock className="h-8 w-8 mx-auto text-muted-foreground/30 mb-2" />
                      <p className="text-sm text-muted-foreground font-sans">No pending requests</p>
                    </div>
                  ) : (
                    pendingApproval.map((b) => (
                      <div key={b.id} className="rounded-2xl border border-status-warning/30 bg-gradient-to-r from-status-warning-muted/90 via-status-warning-muted/50 to-background px-4 py-4 shadow-sm">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex items-start gap-3 min-w-0">
                            <div className="mt-1 w-2.5 h-2.5 rounded-full bg-status-warning animate-pulse shrink-0" />
                            <div className="min-w-0 space-y-1.5">
                              <div className="flex items-center gap-2 flex-wrap">
                                <p className="text-base font-semibold font-sans capitalize text-foreground">{b.service_type.replace(/_/g, " ")}</p>
                                <span className="text-[9px] font-mono text-muted-foreground/70">{getBookingRef(b.id)}</span>
                              </div>
                              <p className="text-xs text-muted-foreground font-sans">
                                {formatSafeDate(b.start_date, "MMM d") || "Date TBD"} — {formatSafeDate(b.end_date, "MMM d") || "TBD"}
                              </p>
                              <p className="text-xs font-sans font-medium text-status-warning-foreground">
                                Waiting {formatSafeRelative(b.created_at) || "for an update"}
                              </p>
                            </div>
                          </div>
                          <Badge
                            variant="secondary"
                            className="text-[10px] bg-status-warning text-status-warning-foreground border-0 shrink-0"
                          >
                            {b.status === "approved"
                              ? "Booked"
                              : b.status === "deposit_paid"
                                ? "Booked"
                                : "Awaiting Review"}
                          </Badge>
                        </div>
                        <div className="mt-3 flex flex-wrap items-center gap-2">
                          <Link to={`/client/booking/${b.id}`}>
                            <Button size="sm" className="rounded-full h-8 text-xs gap-1.5">
                              View Status <ArrowRight className="h-3 w-3" />
                            </Button>
                          </Link>
                          <a
                            href={`mailto:AdamNarciso@gmail.com?subject=${encodeURIComponent(`Question about booking ${getBookingRef(b.id)}`)}`}
                            className="inline-flex items-center gap-1.5 rounded-full border border-status-warning/30 px-3 py-1.5 text-xs font-medium text-status-warning-foreground hover:bg-status-warning-muted/80 transition-colors"
                          >
                            <Mail className="h-3.5 w-3.5" />
                            Nudge Adam
                          </a>
                        </div>
                      </div>
                    ))
                  )
                )}
              </div>
            </CardContent>
          </Card>

          {/* ── Small tile: Quick Stats ── */}
          <Card className="rounded-2xl">
            <CardContent className="py-4 space-y-3">
              <p className="text-xs font-medium text-muted-foreground font-sans uppercase tracking-wider">At a Glance</p>
              <div className="grid grid-cols-2 gap-3">
                {[
                  { icon: <Award className="h-4 w-4" />, value: completedBookings, label: "Jobs" },
                  { icon: <Wrench className="h-4 w-4" />, value: completedBookings + pendingBookings.length, label: "Total" },
                  { icon: <CheckCircle2 className="h-4 w-4" />, value: `${completedToday}/${todayTasks.length}`, label: "Today" },
                  { icon: <Clock className="h-4 w-4" />, value: activeBooking ? "Active" : "—", label: "Booking" },
                ].map((s, i) => (
                  <div key={i} className="flex items-center gap-2">
                    <div className="w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center text-primary shrink-0">{s.icon}</div>
                    <div>
                      <p className="text-base font-medium leading-none">{s.value}</p>
                      <p className="text-[10px] text-muted-foreground font-sans">{s.label}</p>
                    </div>
                  </div>
                ))}
              </div>
            </CardContent>
          </Card>

        </div>
      </div>
    </DashboardLayout>
  );
};

export default ClientDashboard;
