// PROTOTYPE — Variant B: "Insights Studio"
// Visual language: Tech Mahindra brand — red #e31837 (their identity color)
// with navy #061f5c as structural supporting. Poppins typography on a cream
// #f6f2ea canvas. Left sidebar, hero KPI cards, big charts as centerpiece,
// table below as support. DV: full-page replace with hero card + collapsible
// section groups.

import React, { useEffect, useMemo, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
  ChevronLeft, ChevronRight, Search, ArrowUp, ArrowDown, X, RefreshCw,
  CheckCircle2, LogOut, Sparkles, Car, ClipboardList, PhoneOutgoing,
  CalendarCheck2, MessageSquareHeart, Trophy, ArrowLeft, ChevronDown, ChevronUp,
  Plus, PlayCircle, ExternalLink, Inbox, Star, ThumbsUp, ThumbsDown, User, Hash,
} from "lucide-react";
import {
  BarChart as RBarChart, Bar, XAxis, YAxis, Tooltip, CartesianGrid,
  ResponsiveContainer, Cell, PieChart as RPieChart, Pie, Legend,
} from "recharts";
import { useAuthContext } from "../../hooks/AuthContext";
import {
  useHeaderConfig, useActiveScreenRecordView, useRecordView,
  useDetailView, useInstanceMeta,
  evalShowConditions, fmtCellText, fmtLabel,
  type ActionButton, type AnalyticsSpec, type ScreenButton,
} from "../../hooks/usePrototypeData";
import FormModal from "../FormModal";
import { SCREEN_TO_DV, DETAIL_VIEW_IDS, ACTIVITY_IDS, STATE_IDS, DEMO_SLOTS_SCREEN_UUID } from "../../config";
import { CalendarView } from "./Calendar";

// ---------------------------------------------------------------------------
// Palette — Tech Mahindra brand. Red is the identity color (the "Tech" in
// their logo, their CTAs). Navy is structural/supporting. Wine deepens the
// red. Cream is the canvas.
// ---------------------------------------------------------------------------

const ACCENT       = "#e31837";  // TM red — primary identity
const ACCENT_DARK  = "#5f0229";  // TM wine — gradient end / depth
const ACCENT_SOFT  = "#fde2e8";  // TM red soft tint
const TM_NAVY      = "#061f5c";  // TM navy — structural supporting
const SURFACE      = "#ffffff";  // sidebar: pure white, separated by TM border
const SURFACE_ALT  = "#fafafa";  // hover/subtle wash on white surfaces
const TM_BORDER    = "#e4e4ed";  // TM neutral border (from techmahindra.com CSS)
const INK          = "#17181a";  // TM body text

// Chart palette — TM red leads, navy + slate support, wine + bright red round it out.
const PALETTE = ["#e31837", "#061f5c", "#5f0229", "#3b4f61", "#bc2130", "#5b7a95"];

// TM signature visual treatments — pulled from techmahindra.com CSS.
// They use sharp 0px corners, hard offset shadows (4px 4px 0 #color, no blur),
// and red eyebrow labels with -0.02em tracking.
// Flat card chrome — 1px TM border instead of the brutalist hard offset shadow.
// In a dense dashboard the offset shadows competed with the data; a hairline
// border gives definition without the visual noise.
const CARD_BORDER     = `1px solid ${TM_BORDER}`;
const EYEBROW_CLS     = "text-[14px] font-semibold tracking-[-0.02em] leading-[110%]";
const EYEBROW_STYLE   = { color: ACCENT };            // TM red eyebrow

const STATE_TONE: Record<string, { bg: string; fg: string; dot: string }> = {
  "Awaiting Scheduler Call":  { bg: "#FEF3C7", fg: "#92400E", dot: "#e6ab2e" },
  "Scheduled":                { bg: "#FEF3C7", fg: "#92400E", dot: "#e6ab2e" },
  "Awaiting Feedback Call":   { bg: "#FEF3C7", fg: "#92400E", dot: "#e6ab2e" },
  "Expert TD Scheduled":      { bg: "#FEF3C7", fg: "#92400E", dot: "#e6ab2e" },
  "Feedback Collected":       { bg: "#DCFCE7", fg: "#166534", dot: "#27a846" },
  "Scheduling Call Failed":   { bg: ACCENT_SOFT, fg: ACCENT_DARK, dot: ACCENT },
  "Feedback Call Failed":     { bg: ACCENT_SOFT, fg: ACCENT_DARK, dot: ACCENT },
  "End State":                { bg: "#F5F5F4", fg: "#57534E", dot: "#81818c" },
};
function tone(name: string) { return STATE_TONE[name] || { bg: "#F5F5F4", fg: "#57534E", dot: "#A8A29E" }; }

function iconFor(label: string) {
  const k = label.toLowerCase();
  if (k.includes("lead")) return <ClipboardList size={15} />;
  if (k.includes("active") || k.includes("scheduling")) return <PhoneOutgoing size={15} />;
  if (k.includes("scheduled")) return <CalendarCheck2 size={15} />;
  if (k.includes("feedback")) return <MessageSquareHeart size={15} />;
  if (k.includes("completed") || k.includes("done")) return <Trophy size={15} />;
  return <Car size={15} />;
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

export default function VariantB() {
  const navigate = useNavigate();
  const params = useParams();
  const activeScreenId = params.screenId || null;
  const detailInstanceId = params.instanceId || null;
  const { navItems } = useHeaderConfig();
  const [refreshKey, setRefreshKey] = useState(0);
  const [formModal, setFormModal] = useState<{ activityId: string; instanceId?: string; title: string } | null>(null);

  useEffect(() => {
    if (!activeScreenId && !detailInstanceId && navItems.length > 0) {
      navigate(`/screen/${navItems[0].screen_uuid}?variant=B`, { replace: true });
    }
  }, [activeScreenId, detailInstanceId, navItems, navigate]);

  const goTo = (uuid: string) => navigate(`/screen/${uuid}?variant=B`);
  const openDetail = (id: string) => navigate(`/screen/${activeScreenId}/detail/${id}?variant=B`);
  const back = () => navigate(`/screen/${activeScreenId}?variant=B`);
  const activeNav = navItems.find((n) => n.screen_uuid === activeScreenId);

  return (
    <div className="min-h-screen flex bg-white">
      {/* Sidebar — cream, gives the TM warmth a permanent home */}
      <Sidebar navItems={navItems} activeScreenId={activeScreenId} onNavigate={goTo} />

      {/* Main — clean white canvas for data */}
      <div className="flex-1 min-w-0 ml-[240px] overflow-x-hidden">
        <main className="px-7 py-6 max-w-[1440px]">
          {detailInstanceId && activeScreenId ? (
            <DetailPage
              screenUuid={activeScreenId}
              instanceId={detailInstanceId}
              refreshKey={refreshKey}
              onBack={back}
              onAction={(a) => setFormModal(a)}
              breadcrumbLabel={activeNav?.label ?? "Pipeline"}
            />
          ) : activeScreenId === DEMO_SLOTS_SCREEN_UUID ? (
            <CalendarView />
          ) : activeScreenId ? (
            <>
              <h1 className="text-[22px] font-semibold tracking-tight leading-tight mb-5" style={{ color: INK }}>
                {activeNav?.label ?? "Dashboard"}
              </h1>
              <DashboardContent
                activeScreenId={activeScreenId}
                onRowClick={openDetail}
                onOpenForm={(a) => setFormModal(a)}
                refreshKey={refreshKey}
              />
            </>
          ) : null}
        </main>
      </div>

      {formModal && (
        <FormModal
          activityId={formModal.activityId}
          instanceId={formModal.instanceId}
          title={formModal.title}
          onClose={() => setFormModal(null)}
          onSuccess={() => { setFormModal(null); setRefreshKey((k) => k + 1); }}
        />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Sidebar
// ---------------------------------------------------------------------------

function Sidebar({
  navItems, activeScreenId, onNavigate,
}: { navItems: any[]; activeScreenId: string | null; onNavigate: (u: string) => void }) {
  const { user, logout } = useAuthContext();
  const navigate = useNavigate();
  const initials = (user?.name || "U").split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase();
  const role = user?.roles?.[0] ?? "";
  const handleLogout = () => { logout(); navigate("/login"); };

  return (
    <aside
      className="fixed top-0 left-0 bottom-0 w-[240px] flex flex-col z-40"
      style={{
        background: "linear-gradient(180deg, #fdfbfb 0%, #fef2f4 100%)",
        borderRight: `1px solid ${TM_BORDER}`,
      }}
    >
      <div className="px-5 pt-6 pb-5 border-b border-stone-200/60">
        <div className="leading-tight">
          <img src={`${import.meta.env.BASE_URL}zino.svg`} alt="Zino" className="h-5 w-auto" />
          <div className="text-[10.5px] uppercase tracking-[0.18em] text-stone-500 mt-2">AI Sales Ops</div>
        </div>
      </div>

      <div className="flex-1 px-3 py-4 overflow-y-auto">
        <div className="px-3 mb-3 text-[11px] font-semibold tracking-[-0.02em] leading-[110%]" style={{ color: ACCENT }}>Pipeline</div>
        <nav className="space-y-1">
          {navItems.map((item: any) => {
            const active = activeScreenId === item.screen_uuid;
            return (
              <button
                key={item.id}
                onClick={() => onNavigate(item.screen_uuid)}
                className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg text-[13px] font-medium transition-all group ${
                  active
                    ? ""
                    : "text-stone-600 hover:bg-white/70"
                }`}
                style={active ? { background: ACCENT_SOFT, color: ACCENT } : undefined}
              >
                <span
                  className={`flex items-center justify-center w-7 h-7 rounded-lg shrink-0 transition-colors ${
                    active
                      ? ""
                      : "bg-white text-stone-500 shadow-sm group-hover:text-[#e31837]"
                  }`}
                  style={active ? { background: "#fbcfd7", color: ACCENT } : undefined}
                >
                  {iconFor(item.label)}
                </span>
                <span className="truncate">{item.label}</span>
              </button>
            );
          })}
        </nav>
      </div>

      <div className="px-3 py-3 border-t border-stone-200/60">
        <div
          onClick={handleLogout}
          className="flex items-center gap-3 px-2.5 py-2 rounded-lg cursor-pointer hover:bg-[#fafafa] transition-colors group"
        >
          <div className="w-9 h-9 rounded-full flex items-center justify-center text-[11px] font-bold text-white shrink-0" style={{ background: `linear-gradient(135deg, ${ACCENT} 0%, ${ACCENT_DARK} 100%)` }}>
            {initials}
          </div>
          <div className="flex-1 min-w-0">
            <div className="text-[12.5px] font-semibold text-stone-800 truncate leading-tight">{user?.name}</div>
            <div className="text-[10.5px] text-stone-500 truncate">{role}</div>
          </div>
          <LogOut size={13} className="text-stone-300 group-hover:text-stone-600 shrink-0" />
        </div>
      </div>
    </aside>
  );
}

// ---------------------------------------------------------------------------
// Dashboard content
// ---------------------------------------------------------------------------

function DashboardContent({
  activeScreenId, onRowClick, onOpenForm, refreshKey,
}: {
  activeScreenId: string;
  onRowClick: (id: string) => void;
  onOpenForm: (a: { activityId: string; instanceId?: string; title: string }) => void;
  refreshKey: number;
}) {
  const { viewId, screenButtons } = useActiveScreenRecordView(activeScreenId);
  const rv = useRecordView(viewId);
  useEffect(() => { if (refreshKey > 0) rv.refetch(); /* eslint-disable-next-line */ }, [refreshKey]);

  if (!viewId) return <div className="text-[13px] text-stone-400 py-12 text-center">Loading…</div>;

  const tileSpecs  = rv.analytics.filter((a): a is Extract<AnalyticsSpec, { kind: "tile" }>  => a.kind === "tile");
  const chartSpecs = rv.analytics.filter((a): a is Extract<AnalyticsSpec, { kind: "chart" }> => a.kind === "chart");

  return (
    <div className="space-y-7">
      {/* Hero KPI cards */}
      {tileSpecs.length > 0 && (
        <div className="grid gap-5 grid-cols-2 lg:grid-cols-4">
          {tileSpecs.map((t, i) => {
            const v = rv.tileValues.find((tv) => tv.tile_uid === t.uid);
            const display = v?.value == null ? "—" : typeof v.value === "number" ? v.value.toLocaleString("en-IN") : String(v.value);
            const isPrimary = i === 0;
            return (
              <div
                key={t.uid}
                className="rounded-2xl p-5 transition-all hover:-translate-y-0.5 relative overflow-hidden"
                style={{
                  background: isPrimary ? `linear-gradient(135deg, ${ACCENT} 0%, ${ACCENT_DARK} 100%)` : "white",
                  color: isPrimary ? "white" : "inherit",
                  border: isPrimary ? "none" : "1px solid #f1f1ee",
                  boxShadow: isPrimary
                    ? "0 8px 24px -8px rgba(227,24,55,0.35)"
                    : "0 1px 2px rgba(6,31,92,0.04), 0 8px 24px -12px rgba(6,31,92,0.08)",
                }}
              >
                {/* Navy structural accent in the corner of the primary red tile */}
                {isPrimary && (
                  <span
                    className="absolute top-0 right-0 w-20 h-20 -mt-10 -mr-10 rounded-full"
                    style={{ background: `radial-gradient(circle at 30% 70%, ${TM_NAVY}66 0%, transparent 70%)` }}
                  />
                )}
                <div
                  className="text-[12.5px] font-semibold tracking-[-0.02em] leading-[110%] mb-2"
                  style={{ color: isPrimary ? "#ffd9de" : ACCENT }}
                >
                  {t.title}
                </div>
                <div
                  className="text-[30px] font-bold tabular-nums leading-none"
                  style={{ color: isPrimary ? "white" : INK }}
                >
                  {rv.loading || rv.dataLoading
                    ? <span className="inline-block h-8 w-14 bg-white/20 rounded animate-pulse" />
                    : display}
                </div>
                <div className={`text-[11px] mt-1.5 ${isPrimary ? "text-white/70" : "text-stone-500"}`}>
                  total this week
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* Big charts as centerpiece */}
      {chartSpecs.length > 0 && (
        <div className="grid gap-5 lg:grid-cols-2">
          {chartSpecs.map((c) => {
            const cd = rv.chartData.find((d) => d.chart_uid === c.uid);
            const data = (cd?.rows ?? [])
              .map((r) => ({ name: String(r.dimension ?? "—"), value: Number(r.value ?? 0) }))
              .filter((d) => d.name !== "—" && d.value > 0);
            return (
              <div key={c.uid} className="bg-white rounded-2xl p-6" style={{ border: "1px solid #f1f1ee", boxShadow: "0 1px 2px rgba(6,31,92,0.04), 0 8px 24px -12px rgba(6,31,92,0.08)" }}>
                <div className={EYEBROW_CLS} style={EYEBROW_STYLE}>Insight</div>
                <div className="text-[18px] font-bold leading-tight mt-2 mb-5" style={{ color: INK }}>{c.title}</div>
                {rv.loading || rv.dataLoading ? (
                  <div className="h-[260px] bg-stone-50 rounded-xl animate-pulse" />
                ) : data.length === 0 ? (
                  <div className="h-[260px] flex items-center justify-center text-[13px] text-stone-400">No data yet</div>
                ) : (
                  <div
                    style={{ width: "100%", height: 260 }}
                    className="[&_.recharts-sector]:outline-none [&_.recharts-rectangle]:outline-none [&_.recharts-surface]:outline-none"
                  >
                    <ResponsiveContainer>
                      {c.chartType === "pie" ? (
                        <RPieChart>
                          <Pie data={data} dataKey="value" nameKey="name" innerRadius={55} outerRadius={95} paddingAngle={3}>
                            {data.map((_, i) => <Cell key={i} fill={PALETTE[i % PALETTE.length]} />)}
                          </Pie>
                          <Tooltip contentStyle={{ fontSize: 12, borderRadius: 12, border: "none", boxShadow: "0 4px 12px rgba(0,0,0,0.1)" }} />
                          <Legend verticalAlign="middle" align="right" layout="vertical" iconType="circle" wrapperStyle={{ fontSize: 12 }} />
                        </RPieChart>
                      ) : (
                        <RBarChart data={data} margin={{ top: 5, right: 10, left: -10, bottom: 50 }}>
                          <CartesianGrid strokeDasharray="3 3" stroke="#f5f5f4" vertical={false} />
                          <XAxis
                            dataKey="name"
                            tick={{ fontSize: 11, fill: "#78716c" }}
                            interval={0}
                            angle={-25}
                            textAnchor="end"
                            height={60}
                            axisLine={false}
                            tickLine={false}
                          />
                          <YAxis tick={{ fontSize: 11, fill: "#78716c" }} allowDecimals={false} axisLine={false} tickLine={false} />
                          <Tooltip cursor={{ fill: ACCENT_SOFT }} contentStyle={{ fontSize: 12, borderRadius: 12, border: "none", boxShadow: "0 4px 12px rgba(0,0,0,0.1)" }} />
                          <Bar dataKey="value" radius={[8, 8, 0, 0]}>
                            {data.map((_, i) => <Cell key={i} fill={PALETTE[i % PALETTE.length]} />)}
                          </Bar>
                        </RBarChart>
                      )}
                    </ResponsiveContainer>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}

      <RecordTable rv={rv} onRowClick={onRowClick} onOpenForm={onOpenForm} screenButtons={screenButtons} />
    </div>
  );
}

// Per-column max width (px). Long-text columns get the widest cap; the rest
// stay tight so a single overflowing summary can't push the whole table wide.
function colMaxWidth(dataType: string, fieldKey: string): number {
  const k = fieldKey.toLowerCase();
  if (dataType === "longtext") return 360;
  if (k.includes("summary") || k.includes("reason") || k.includes("transcript") || k.includes("recording")) return 320;
  if (k === "instance_id" || k.endsWith("_id")) return 110;
  if (dataType === "number") return 130;
  if (dataType === "date" || dataType === "datetime") return 140;
  if (k.includes("email")) return 220;
  if (k.includes("phone")) return 160;
  return 200;
}

function RecordTable({
  rv, onRowClick, onOpenForm, screenButtons,
}: {
  rv: ReturnType<typeof useRecordView>;
  onRowClick: (id: string) => void;
  onOpenForm: (a: { activityId: string; instanceId?: string; title: string }) => void;
  screenButtons: ScreenButton[];
}) {
  const [searchInput, setSearchInput] = useState("");
  const { fields, rows, columnLabels, actionColumns, pagination, query, dataLoading, error } = rv;
  const { page, total_count, total_pages, limit } = pagination;
  const from = total_count > 0 ? (page - 1) * limit + 1 : 0;
  const to = Math.min(page * limit, total_count);

  const handleSort = (k: string) =>
    rv.setQuery((q) => ({ ...q, page: 1, sort_by: k, sort_dir: q.sort_by === k && q.sort_dir === "asc" ? "desc" : "asc" }));
  const submitSearch = (e: React.FormEvent) => { e.preventDefault(); rv.setQuery((q) => ({ ...q, page: 1, search: searchInput })); };

  return (
    <div className="bg-white rounded-2xl overflow-hidden" style={{ border: "1px solid #f1f1ee", boxShadow: "0 1px 2px rgba(6,31,92,0.04), 0 4px 16px -8px rgba(6,31,92,0.08)" }}>
      <div className="px-6 py-3.5 flex items-center justify-between gap-4 border-b border-stone-100">
        <div className="flex items-baseline gap-3 min-w-0">
          <div className="text-[15px] font-bold leading-none truncate" style={{ color: INK }}>All leads</div>
          <div className="text-[12px] text-stone-500 tabular-nums whitespace-nowrap">
            {total_count} records · showing {from}–{to}
          </div>
        </div>
        <div className="flex items-center gap-2">
          {screenButtons.map((b) => (
            <button
              key={b.activityId}
              onClick={() => onOpenForm({ activityId: b.activityId, title: b.label })}
              className="h-9 px-4 text-[13px] font-semibold text-white inline-flex items-center gap-1.5 transition-opacity hover:opacity-90 rounded"
              style={{ background: ACCENT }}
            >
              <Plus size={14} strokeWidth={2.5} />{b.label}
            </button>
          ))}
          <button
            onClick={() => rv.refetch()}
            className="w-9 h-9 rounded-lg flex items-center justify-center text-stone-400 hover:text-stone-700 hover:bg-stone-50 transition-colors"
            title="Refresh"
          >
            <RefreshCw size={14} className={dataLoading ? "animate-spin" : ""} />
          </button>
          <form onSubmit={submitSearch}>
            <div className="relative">
              <Search size={13} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-stone-400" />
              <input
                value={searchInput}
                onChange={(e) => setSearchInput(e.target.value)}
                placeholder="Search leads…"
                className="w-56 h-9 pl-9 pr-3 text-[13px] border border-stone-200 rounded-lg bg-stone-50 text-stone-800 focus:outline-none focus:bg-white"
                style={{ borderColor: searchInput ? ACCENT : undefined }}
              />
              {searchInput && (
                <button
                  type="button"
                  onClick={() => { setSearchInput(""); rv.setQuery((q) => ({ ...q, page: 1, search: "" })); }}
                  className="absolute right-3 top-1/2 -translate-y-1/2 text-stone-400 hover:text-stone-700"
                ><X size={12} /></button>
              )}
            </div>
          </form>
        </div>
      </div>

      {error ? (
        <div className="p-10 text-center text-[13px] text-red-600">{error}</div>
      ) : (
        <div className="overflow-x-auto relative">
          {dataLoading && (
            <div className="absolute inset-0 bg-white/50 z-10 flex items-center justify-center backdrop-blur-[1px]">
              <div className="w-5 h-5 border-2 border-rose-200 border-t-[#e31837] rounded-full animate-spin" />
            </div>
          )}
          <table className="w-full" style={{ tableLayout: "fixed" }}>
            <colgroup>
              {fields.map((f) => (
                <col key={f.field_key} style={{ width: colMaxWidth(f.data_type, f.field_key) }} />
              ))}
              {actionColumns.length > 0 && <col style={{ width: 180 }} />}
            </colgroup>
            <thead>
              <tr className="border-b-2 border-stone-200/70">
                {fields.map((f, i) => {
                  const sorted = query.sort_by === f.field_key;
                  return (
                    <th
                      key={f.field_key}
                      onClick={() => handleSort(f.field_key)}
                      className={`py-3 text-left text-[11.5px] font-semibold cursor-pointer select-none whitespace-nowrap group/th transition-colors ${
                        i === 0 ? "pl-7 pr-4" : "px-4"
                      } ${sorted ? "text-[#e31837]" : "text-stone-500 hover:text-stone-800"}`}
                    >
                      <span className="inline-flex items-center gap-1">
                        {columnLabels[f.field_key] || f.output_label || f.field_key}
                        {sorted
                          ? (query.sort_dir === "asc" ? <ArrowUp size={10} /> : <ArrowDown size={10} />)
                          : <ArrowDown size={10} className="text-stone-300 opacity-0 group-hover/th:opacity-100 transition-opacity" />}
                      </span>
                    </th>
                  );
                })}
                {actionColumns.length > 0 && (
                  <th className="py-3 px-4 text-left text-[11.5px] font-semibold text-stone-500 whitespace-nowrap">Action</th>
                )}
              </tr>
            </thead>
            <tbody className="divide-y divide-stone-200/60">
              {rows.length === 0 ? (
                <tr>
                  <td colSpan={fields.length + (actionColumns.length > 0 ? 1 : 0)} className="py-20 text-center">
                    <div className="flex flex-col items-center gap-3">
                      <div
                        className="w-14 h-14 rounded-2xl flex items-center justify-center"
                        style={{ background: `linear-gradient(135deg, ${ACCENT_SOFT}, #fbcfd7)` }}
                      >
                        <Inbox size={22} className="text-[#e31837]" />
                      </div>
                      <div>
                        <div className="text-[14px] font-semibold text-stone-700">No leads here yet</div>
                        <div className="text-[12px] text-stone-400 mt-1">
                          {query.search ? "Try a different search term" : "New leads will show up here as they come in"}
                        </div>
                      </div>
                      {query.search && (
                        <button
                          onClick={() => { setSearchInput(""); rv.setQuery((q) => ({ ...q, page: 1, search: "" })); }}
                          className="text-[12px] font-semibold text-[#e31837] hover:text-[#5f0229] transition-colors"
                        >
                          Clear search
                        </button>
                      )}
                    </div>
                  </td>
                </tr>
              ) : rows.map((row, i) => (
                <tr
                  key={String(row.instance_id ?? i)}
                  onClick={() => onRowClick(String(row.instance_id))}
                  className="group/row cursor-pointer hover:bg-[#f6f2ea]/60 transition-colors"
                >
                  {fields.map((f, fi) => (
                    <td
                      key={f.field_key}
                      className={`py-3.5 text-[13.5px] ${
                        fi === 0
                          ? "pl-7 pr-4 font-semibold text-stone-900 border-l-2 border-l-transparent group-hover/row:border-l-[#e31837] transition-colors"
                          : "px-4 text-stone-600"
                      }`}
                    >
                      <div
                        className="truncate"
                        title={typeof row[f.field_key] === "string" ? String(row[f.field_key]) : undefined}
                      >
                        {renderCell(row[f.field_key], f.data_type, f.field_key)}
                      </div>
                    </td>
                  ))}
                  {actionColumns.length > 0 && (
                    <td className="px-4 py-3 whitespace-nowrap" onClick={(e) => e.stopPropagation()}>
                      <div className="inline-flex items-center gap-2">
                        {actionColumns.flatMap((ac) =>
                          ac.buttons.filter((b) => evalShowConditions(b.show_conditions, row))
                        ).map((b: ActionButton, bi) => {
                          const aid = b.params?.activity_uid;
                          if (!aid) return null;
                          return (
                            <button
                              key={bi}
                              onClick={() => onOpenForm({ activityId: aid, instanceId: String(row.instance_id), title: b.name })}
                              className="h-9 px-4 text-[13px] font-semibold rounded-lg inline-flex items-center gap-2 transition-colors hover:bg-[#fbcfd7]"
                              style={{ background: ACCENT_SOFT, color: ACCENT, border: `1px solid ${ACCENT}33` }}
                            >
                              {b.name}
                            </button>
                          );
                        })}
                      </div>
                    </td>
                  )}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {total_count > 0 && (
        <div className="px-6 py-3 border-t border-stone-100 flex items-center justify-between gap-4">
          <div className="flex items-center gap-3 text-[12px] text-stone-500">
            <div className="flex items-center gap-1.5">
              Show
              <select
                value={limit}
                onChange={(e) => rv.setQuery((q) => ({ ...q, page: 1, limit: Number(e.target.value) }))}
                className="h-7 px-2 text-[12px] border border-stone-200 rounded-lg bg-white text-stone-600 font-medium focus:outline-none cursor-pointer"
              >
                <option value={10}>10</option>
                <option value={25}>25</option>
                <option value={50}>50</option>
              </select>
              per page
            </div>
            <span className="pl-3 border-l border-stone-200 tabular-nums">{from}–{to} of {total_count}</span>
          </div>

          {total_pages > 1 && (
            <div className="flex items-center gap-0.5">
              <button
                disabled={page <= 1}
                onClick={() => rv.setQuery((q) => ({ ...q, page: page - 1 }))}
                className="w-7 h-7 rounded-lg flex items-center justify-center text-stone-400 hover:text-[#e31837] hover:bg-rose-50 disabled:opacity-30 disabled:pointer-events-none transition-colors"
              ><ChevronLeft size={15} /></button>

              {pageList(page, total_pages).map((p, idx) =>
                p === "…" ? (
                  <span key={`e${idx}`} className="w-7 h-7 flex items-center justify-center text-[12px] text-stone-300 select-none">…</span>
                ) : (
                  <button
                    key={p}
                    onClick={() => rv.setQuery((q) => ({ ...q, page: p as number }))}
                    className={`w-7 h-7 rounded-lg text-[12px] font-medium transition-colors ${
                      p === page
                        ? "text-white"
                        : "text-stone-500 hover:text-[#e31837] hover:bg-rose-50"
                    }`}
                    style={p === page ? { background: ACCENT } : undefined}
                  >
                    {p}
                  </button>
                )
              )}

              <button
                disabled={page >= total_pages}
                onClick={() => rv.setQuery((q) => ({ ...q, page: page + 1 }))}
                className="w-7 h-7 rounded-lg flex items-center justify-center text-stone-400 hover:text-[#e31837] hover:bg-rose-50 disabled:opacity-30 disabled:pointer-events-none transition-colors"
              ><ChevronRight size={15} /></button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

const AVATAR_PALETTE: { bg: string; fg: string }[] = [
  { bg: "#fde2e8", fg: "#9d0d24" }, // soft rose
  { bg: "#e3e8f5", fg: "#1e3a8a" }, // soft navy
  { bg: "#e8f0e3", fg: "#3f6212" }, // soft olive
  { bg: "#f5ead3", fg: "#854d0e" }, // soft amber
  { bg: "#e5dff5", fg: "#5b21b6" }, // soft violet
  { bg: "#d6ecec", fg: "#155e75" }, // soft teal
  { bg: "#f5e0d3", fg: "#9a3412" }, // soft terracotta
  { bg: "#e6e8ec", fg: "#334155" }, // soft slate
];

function avatarColor(name: string): { bg: string; fg: string } {
  let h = 0;
  for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0;
  return AVATAR_PALETTE[h % AVATAR_PALETTE.length];
}

const MODEL_DOT: Record<string, string> = {
  "Thar Roxx":  "#9d0d24",
  "XUV700":     "#1e3a8a",
  "XUV3XO":     "#155e75",
  "Scorpio-N":  "#5b21b6",
  "Bolero Neo": "#854d0e",
};

function modelColor(model: string): string {
  if (MODEL_DOT[model]) return MODEL_DOT[model];
  let h = 0;
  for (let i = 0; i < model.length; i++) h = (h * 31 + model.charCodeAt(i)) >>> 0;
  const fallback = ["#9d0d24", "#1e3a8a", "#155e75", "#5b21b6", "#854d0e", "#3f6212"];
  return fallback[h % fallback.length];
}

function pageList(current: number, total: number): (number | "…")[] {
  if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
  const pages: (number | "…")[] = [1];
  const start = Math.max(2, current - 1);
  const end = Math.min(total - 1, current + 1);
  if (start > 2) pages.push("…");
  for (let i = start; i <= end; i++) pages.push(i);
  if (end < total - 1) pages.push("…");
  pages.push(total);
  return pages;
}

function renderCell(value: unknown, dataType: string, fieldKey: string): React.ReactNode {
  if (value == null || value === "") return <span className="text-stone-300">—</span>;
  if (fieldKey === "current_state_name") {
    const t = tone(String(value));
    return (
      <span className="inline-flex items-center gap-2 px-3 py-1 rounded-full text-[11.5px] font-semibold" style={{ background: t.bg, color: t.fg }}>
        <span className="w-1.5 h-1.5 rounded-full" style={{ background: t.dot }} />
        {String(value)}
      </span>
    );
  }
  if (fieldKey === "instance_id") {
    return <span className="font-mono text-[11px] text-stone-400">#{String(value).slice(0, 8)}</span>;
  }
  if (fieldKey === "customer_name") {
    const name = String(value);
    const initials = name.split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase();
    const c = avatarColor(name);
    return (
      <span className="inline-flex items-center gap-2.5">
        <span
          className="w-7 h-7 rounded-full flex items-center justify-center text-[10.5px] font-semibold shrink-0"
          style={{ background: c.bg, color: c.fg }}
        >
          {initials}
        </span>
        <span className="font-semibold text-stone-900">{name}</span>
      </span>
    );
  }
  if (fieldKey === "customer_phone" || fieldKey === "phone") {
    const phone = typeof value === "object" && value !== null
      ? String((value as any).phone_with_dial_code ?? (value as any).phone ?? "")
      : String(value);
    if (!phone) return <span className="text-stone-300">—</span>;
    return <span className="text-stone-600 tabular-nums">{phone}</span>;
  }
  if (fieldKey === "model_interest" || fieldKey === "model") {
    const dot = modelColor(String(value));
    return (
      <span
        className="inline-flex items-center gap-2 px-2.5 py-1 rounded-full border bg-white"
        style={{ borderColor: `${dot}33` }}
      >
        <span className="w-2 h-2 rounded-full shrink-0" style={{ background: `${dot}cc` }} />
        <span className="text-[12.5px] text-stone-700 tracking-[-0.01em]">{String(value)}</span>
      </span>
    );
  }
  if (fieldKey === "feedback_rating") {
    const n = Number(value);
    if (!Number.isFinite(n)) return <span className="text-stone-300">—</span>;
    // Render as 5 stars (rating is /10; halve to /5).
    const filled = Math.round(n / 2);
    return (
      <span className="inline-flex items-center gap-1.5">
        <span className="inline-flex items-center gap-0.5">
          {Array.from({ length: 5 }, (_, i) => (
            <Star
              key={i}
              size={13}
              fill={i < filled ? "#f59e0b" : "transparent"}
              stroke={i < filled ? "#f59e0b" : "#d6d3d1"}
              strokeWidth={2}
            />
          ))}
        </span>
        <span className="text-[12px] tabular-nums text-stone-500 font-medium">{n.toFixed(n % 1 === 0 ? 0 : 1)}</span>
      </span>
    );
  }
  if (fieldKey === "feedback_would_recommend") {
    const v = value === true || value === "true" || value === 1 || value === "1";
    const no = value === false || value === "false" || value === 0 || value === "0";
    if (!v && !no) return <span className="text-stone-300">—</span>;
    return v
      ? <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[12px] font-semibold" style={{ background: "#e7f3eb", color: "#15803d" }}><ThumbsUp size={12} /> Yes</span>
      : <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[12px] font-semibold" style={{ background: "#fde2e8", color: "#9d0d24" }}><ThumbsDown size={12} /> No</span>;
  }
  if (dataType === "number") return <span className="tabular-nums font-medium text-stone-900">{fmtCellText(value, dataType, fieldKey)}</span>;
  return fmtCellText(value, dataType, fieldKey);
}

// ---------------------------------------------------------------------------
// Detail page (full-width replace)
// ---------------------------------------------------------------------------

function DetailPage({
  screenUuid, instanceId, refreshKey, onBack, onAction, breadcrumbLabel,
}: {
  screenUuid: string;
  instanceId: string;
  refreshKey: number;
  onBack: () => void;
  onAction: (a: { activityId: string; instanceId: string; title: string }) => void;
  breadcrumbLabel: string;
}) {
  const dvViewId = SCREEN_TO_DV[screenUuid] || DETAIL_VIEW_IDS.INSTANCE_DETAIL;
  const dv = useDetailView(dvViewId, instanceId);
  const { instanceState, audit } = useInstanceMeta(instanceId, refreshKey);

  const actions = useMemo(() => {
    if (!instanceState) return [] as Array<{ id: string; label: string; icon: React.ReactNode }>;
    if (instanceState === STATE_IDS.SCHEDULED)              return [{ id: ACTIVITY_IDS.MARK_TEST_DRIVE_DONE, label: "Mark Test Drive Done", icon: <CheckCircle2 size={14} /> }];
    if (instanceState === STATE_IDS.SCHEDULING_CALL_FAILED) return [{ id: ACTIVITY_IDS.RETRY_SCHEDULING_CALL, label: "Retry Scheduling Call", icon: <RefreshCw size={14} /> }];
    if (instanceState === STATE_IDS.FEEDBACK_CALL_FAILED)   return [{ id: ACTIVITY_IDS.RETRY_FEEDBACK_CALL,   label: "Retry Feedback Call",   icon: <RefreshCw size={14} /> }];
    if (instanceState === STATE_IDS.EXPERT_TD_SCHEDULED)    return [{ id: ACTIVITY_IDS.MARK_EXPERT_TD_DONE,   label: "Mark Expert TD Done",   icon: <CheckCircle2 size={14} /> }];
    return [];
  }, [instanceState]);

  const aiInFlight = instanceState === STATE_IDS.AWAITING_SCHEDULER_CALL || instanceState === STATE_IDS.AWAITING_FEEDBACK_CALL;

  if (dv.loading) return <div className="text-[14px] text-stone-400 py-20 text-center">Loading lead…</div>;
  if (!dv.data) return null;

  const heroValue = String(dv.data["customer_name"] ?? "");
  const stateName = String(dv.data["current_state_name"] ?? "");
  const t = tone(stateName);
  const model = String(dv.data["model_interest"] ?? "");

  // Group fields by prefix. Recording-URL fields are pulled out separately so
  // they can surface in the narrow lane as a "Play call" quick action instead of
  // being buried inside the Feedback/AI section.
  const groups: Record<string, typeof dv.fields> = { customer: [], vehicle: [], booking: [], feedback: [], ai: [], other: [] };
  const recordings: typeof dv.fields = [];
  const sys = new Set(["instance_id", "current_state_name", "created_at", "updated_at", "customer_name", "model_interest", "analysis_so_far"]);
  for (const f of dv.fields) {
    if (sys.has(f.field_key)) continue;
    if (/recording_url$/i.test(f.field_key)) { recordings.push(f); continue; }
    // Drop plumbing IDs (feedback_call_id, scheduling_call_id, …) from DV sections.
    if (/_call_id$/i.test(f.field_key)) continue;
    const k = f.field_key.toLowerCase();
    if (k.startsWith("customer_") || k === "phone" || k === "email" || k === "lead_source") groups.customer.push(f);
    else if (k.startsWith("vehicle_") || k === "variant" || k === "color" || k === "fuel_type") groups.vehicle.push(f);
    else if (k.startsWith("booking_") || k === "dealer_name" || k === "dealer_id" || k.includes("slot")) groups.booking.push(f);
    else if (k.startsWith("feedback_") || k === "rating" || k === "would_recommend" || k === "test_drive_outcome") groups.feedback.push(f);
    else if (k.startsWith("ai_") || k.startsWith("call_") || k.includes("summary") || k.includes("confidence") || k.includes("reasoning") || k.includes("failure_reason") || k.includes("escalation")) groups.ai.push(f);
    else groups.other.push(f);
  }

  // Lead age — relative-time string from created_at. Empty if no timestamp.
  const leadAgeLabel = (() => {
    const ts = dv.data["created_at"];
    if (!ts) return "";
    const ms = Date.now() - new Date(String(ts)).getTime();
    if (!Number.isFinite(ms) || ms < 0) return "";
    const mins = Math.floor(ms / 60000);
    if (mins < 1) return "just now";
    if (mins < 60) return `${mins} min${mins === 1 ? "" : "s"} ago`;
    const hrs = Math.floor(mins / 60);
    if (hrs < 24) return `${hrs} hour${hrs === 1 ? "" : "s"} ago`;
    const days = Math.floor(hrs / 24);
    if (days < 30) return `${days} day${days === 1 ? "" : "s"} ago`;
    const months = Math.floor(days / 30);
    if (months < 12) return `${months} month${months === 1 ? "" : "s"} ago`;
    const years = Math.floor(days / 365);
    return `${years} year${years === 1 ? "" : "s"} ago`;
  })();
  const playableRecordings = recordings
    .map((f) => ({ field: f, url: dv.data[f.field_key] }))
    .filter((r) => r.url != null && r.url !== "" && r.url !== "—") as { field: typeof recordings[number]; url: string }[];
  const hasQuickInfo = !!leadAgeLabel || playableRecordings.length > 0;

  const phone = (() => {
    const v = dv.data["customer_phone"];
    if (typeof v === "object" && v !== null) return String((v as any).phone_with_dial_code ?? (v as any).phone ?? "");
    return v ? String(v) : "";
  })();
  const createdDate = dv.data["created_at"]
    ? new Date(String(dv.data["created_at"])).toLocaleDateString("en-IN", { day: "2-digit", month: "short", year: "numeric" })
    : "";

  return (
    <div className="space-y-6">
      {/* Breadcrumb above the card, on the page surface */}
      <div className="flex items-center gap-2 text-[12px] font-medium text-stone-400">
        <button onClick={onBack} className="inline-flex items-center gap-1.5 hover:text-[#e31837] transition-colors">
          <ChevronLeft size={14} />
          {breadcrumbLabel}
        </button>
        <span className="text-stone-300">/</span>
        <span className="text-stone-600 font-semibold">{heroValue || `#${instanceId}`}</span>
      </div>

      {aiInFlight && (
        <div className="rounded-xl px-5 py-4 flex items-center gap-3" style={{ background: ACCENT_SOFT, border: `1px solid #fbb4be` }}>
          <div className="w-9 h-9 rounded-lg flex items-center justify-center shrink-0" style={{ background: ACCENT }}>
            <Sparkles size={15} className="text-white" />
          </div>
          <div>
            <div className="text-[13px] font-semibold text-[#e31837]">Maya is on the call</div>
            <div className="text-[12px] text-[#5f0229]">The AI scheduler is handling this lead. This page refreshes when complete.</div>
          </div>
        </div>
      )}

      {/* Unified card — hero on top, hairline divider, then sub-section grid. */}
      <div className="bg-white rounded-2xl" style={{ border: CARD_BORDER }}>
        {/* Hero region — avatar + name + inline state pill on the left, actions on the right.
            Metadata row uses small inline icons instead of middots for clarity. */}
        <div className="px-7 py-6 flex items-start justify-between gap-6 flex-wrap">
          <div className="min-w-0 flex-1 flex items-start gap-4">
            {/* Avatar circle — first two initials of the customer name */}
            <div
              className="w-14 h-14 rounded-full flex items-center justify-center shrink-0 text-[18px] font-bold tracking-tight"
              style={{ background: ACCENT_SOFT, color: ACCENT_DARK }}
            >
              {(() => {
                const src = heroValue || `#${instanceId}`;
                const parts = src.replace(/[#]/g, "").trim().split(/\s+/).filter(Boolean);
                const initials = parts.length >= 2
                  ? (parts[0][0] + parts[1][0])
                  : (parts[0] || "?").slice(0, 2);
                return initials.toUpperCase();
              })()}
            </div>
            <div className="min-w-0 flex-1 pt-0.5">
              <h2 className="text-[26px] font-bold leading-none tracking-tight" style={{ color: INK }}>
                {heroValue || `#${instanceId}`}
              </h2>
              {/* Metadata row — small inline icons, less ornament than middots */}
              <div className="mt-3 flex items-center gap-x-5 gap-y-1.5 text-[12.5px] text-stone-500 flex-wrap">
                {phone && (
                  <span className="inline-flex items-center gap-1.5 tabular-nums">
                    <PhoneOutgoing size={13} strokeWidth={2.25} className="text-stone-400" />
                    {phone}
                  </span>
                )}
                {model && (
                  <span className="inline-flex items-center gap-1.5 font-medium text-stone-600">
                    <Car size={13} strokeWidth={2.25} className="text-stone-400" />
                    {model}
                  </span>
                )}
                {createdDate && (
                  <span className="inline-flex items-center gap-1.5">
                    <CalendarCheck2 size={13} strokeWidth={2.25} className="text-stone-400" />
                    {createdDate}
                  </span>
                )}
                <span className="inline-flex items-center gap-1 tabular-nums text-stone-400">
                  <Hash size={12} strokeWidth={2.25} />
                  {instanceId}
                </span>
              </div>
            </div>
          </div>

          <div className="flex items-center gap-2 shrink-0 flex-wrap justify-end">
            {stateName && (
              <span
                className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[11.5px] font-semibold"
                style={{ background: t.bg, color: t.fg }}
              >
                <span className="w-1.5 h-1.5 rounded-full" style={{ background: t.dot }} />
                {stateName}
              </span>
            )}
            {actions.length > 0 && actions.map((a, i) => (
                <button
                  key={a.id}
                  onClick={() => onAction({ activityId: a.id, instanceId, title: a.label })}
                  className="h-9 px-4 text-[13px] font-semibold rounded-lg inline-flex items-center gap-2 transition-colors"
                  style={
                    i === 0
                      ? { background: ACCENT, color: "white" }
                      : { background: "white", color: INK, border: `1px solid ${TM_BORDER}` }
                  }
                >
                  {a.icon}{a.label}
                </button>
              ))}
          </div>
        </div>

        {/* Sub-section grid — inside the unified card, separated from hero by a hairline.
            Hide the AI analysis block on the Scheduled Test Drives view; the dealer is
            the audience there and the AI fields would just be noise. */}
        {(() => {
          const visible = Object.entries(groups).filter(
            ([key, fs]) => fs.length > 0 && !(screenUuid === "98af93e0-0f66-444b-a007-129b322be86b" && key === "ai")
          );
          const wide = visible.filter(([key]) => SECTION_LANE[key] !== "narrow");
          const narrow = visible.filter(([key]) => SECTION_LANE[key] === "narrow");
          if (visible.length === 0 && !hasQuickInfo) return null;
          const hasBoth = wide.length > 0 && (narrow.length > 0 || hasQuickInfo);
          const quickInfo = hasQuickInfo ? (
            <div>
              <div className="text-[11px] font-bold uppercase tracking-[0.12em] mb-4" style={{ color: ACCENT }}>
                At a Glance
              </div>
              <div className="space-y-3">
                {leadAgeLabel && (
                  <div className="flex items-center gap-3">
                    <div className="w-9 h-9 rounded-lg flex items-center justify-center shrink-0" style={{ background: ACCENT_SOFT, color: ACCENT_DARK }}>
                      <CalendarCheck2 size={16} strokeWidth={2.25} />
                    </div>
                    <div className="min-w-0">
                      <div className="text-[11.5px] font-medium text-stone-400">Lead age</div>
                      <div className="text-[14px] font-semibold leading-snug" style={{ color: INK }}>{leadAgeLabel}</div>
                    </div>
                  </div>
                )}
                {playableRecordings.map((r) => (
                  <a
                    key={r.field.field_key}
                    href={r.url}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="flex items-center gap-3 rounded-lg px-2 py-1.5 -mx-2 hover:bg-stone-50 transition-colors group"
                  >
                    <div className="w-9 h-9 rounded-lg flex items-center justify-center shrink-0" style={{ background: ACCENT_SOFT, color: ACCENT_DARK }}>
                      <PlayCircle size={16} strokeWidth={2.25} />
                    </div>
                    <div className="min-w-0">
                      <div className="text-[11.5px] font-medium text-stone-400">{fmtLabel(r.field.output_label) || "Recording"}</div>
                      <div className="text-[14px] font-semibold leading-snug group-hover:underline underline-offset-4" style={{ color: ACCENT_DARK }}>
                        Play call
                      </div>
                    </div>
                    <ExternalLink size={12} strokeWidth={2.25} className="ml-auto shrink-0 text-stone-300" />
                  </a>
                ))}
              </div>
            </div>
          ) : null;
          return (
            <div className="px-7 py-6 border-t border-stone-200">
              {hasBoth ? (
                <div className="grid grid-cols-3 gap-x-10">
                  <div className="col-span-2 [&>*+*]:mt-8 [&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-stone-200">
                    {wide.map(([key, fs]) => (
                      <SubSection key={key} sectionKey={key} fields={fs} data={dv.data!} lane="wide" />
                    ))}
                  </div>
                  <div className="col-span-1 pl-10 border-l border-stone-200 [&>*+*]:mt-8 [&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-stone-200">
                    {quickInfo}
                    {narrow.map(([key, fs]) => (
                      <SubSection key={key} sectionKey={key} fields={fs} data={dv.data!} lane="narrow" />
                    ))}
                  </div>
                </div>
              ) : (
                <div className="[&>*+*]:mt-8 [&>*+*]:pt-8 [&>*+*]:border-t [&>*+*]:border-stone-200">
                  {quickInfo}
                  {visible.map(([key, fs]) => (
                    <SubSection key={key} sectionKey={key} fields={fs} data={dv.data!} lane={SECTION_LANE[key] === "narrow" ? "narrow" : "wide"} />
                  ))}
                </div>
              )}
            </div>
          );
        })()}
      </div>

      {audit.length > 0 && (
        <div className="bg-white rounded-2xl p-6" style={{ border: CARD_BORDER }}>
          <div className="flex items-center gap-3 mb-5">
            <span className="text-[11px] font-bold tabular-nums px-1.5 py-0.5 text-white" style={{ background: ACCENT, letterSpacing: "0.04em" }}>LOG</span>
            <div className="text-[17px] font-bold tracking-tight leading-none" style={{ color: INK }}>Activity timeline</div>
            <div className="text-[11.5px] font-medium tabular-nums text-stone-400">{audit.length} {audit.length === 1 ? "event" : "events"}</div>
          </div>
          <ol className="relative">
            {/* Vertical rail down the timeline */}
            <span className="absolute left-[5px] top-2 bottom-2 w-px" style={{ background: TM_BORDER }} />
            {audit.map((e, i) => {
              const meta = ACTIVITY_LABELS[e.activity_id];
              const label = meta?.label ?? "Workflow step";
              const tone = meta?.tone ?? "system";
              const isLast = i === audit.length - 1;
              const dotColor = isLast ? ACCENT : tone === "ai" ? TM_NAVY : tone === "user" ? "#57534e" : "#a8a29e";
              const actor = tone === "ai" ? "AI · Maya" : (e.user_roles?.[0] ?? "System");
              return (
                <li key={e.id} className="relative pl-7 pb-4 last:pb-0 text-[13px]">
                  <span
                    className="absolute left-0 top-1 w-[11px] h-[11px] rounded-full"
                    style={{ background: dotColor, boxShadow: `0 0 0 3px white` }}
                  />
                  <div className="flex items-baseline justify-between gap-4">
                    <div className="min-w-0">
                      <div className="font-semibold leading-tight" style={{ color: INK }}>{label}</div>
                      <div className="text-[11.5px] uppercase tracking-[0.04em] text-stone-400 mt-1">
                        {actor}{e.execution_state && e.execution_state !== "completed" ? ` · ${e.execution_state}` : ""}
                      </div>
                    </div>
                    <span className="text-stone-400 tabular-nums shrink-0 text-[12px]">
                      {new Date(e.created_at).toLocaleString("en-IN", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" })}
                    </span>
                  </div>
                </li>
              );
            })}
          </ol>
        </div>
      )}
    </div>
  );
}

// Section titles — single strong word, no subtitle (cleaner editorial feel).
// Human labels for activity UUIDs that appear in the audit log. Anything not
// in this map falls back to "Workflow step".
const ACTIVITY_LABELS: Record<string, { label: string; tone: "user" | "ai" | "system" }> = {
  [ACTIVITY_IDS.INIT_ACTIVITY]:                  { label: "Lead captured",              tone: "user" },
  [ACTIVITY_IDS.MARK_TEST_DRIVE_DONE]:           { label: "Test drive marked done",     tone: "user" },
  [ACTIVITY_IDS.AI_CONFIRM_SCHEDULING_SUCCESS]:  { label: "Scheduling call succeeded",  tone: "ai" },
  [ACTIVITY_IDS.AI_CONFIRM_SCHEDULING_FAILED]:   { label: "Scheduling call failed",     tone: "ai" },
  [ACTIVITY_IDS.RETRY_SCHEDULING_CALL]:          { label: "Retried scheduling call",    tone: "user" },
  [ACTIVITY_IDS.AI_CONFIRM_FEEDBACK_COLLECTED]:  { label: "Feedback collected",         tone: "ai" },
  [ACTIVITY_IDS.AI_CONFIRM_FEEDBACK_FAILED]:     { label: "Feedback call failed",       tone: "ai" },
  [ACTIVITY_IDS.RETRY_FEEDBACK_CALL]:            { label: "Retried feedback call",      tone: "user" },
  [ACTIVITY_IDS.CONCERN_EXPERT_TD_BOOKED]:       { label: "Concern → Expert TD booked", tone: "ai" },
  [ACTIVITY_IDS.MARK_EXPERT_TD_DONE]:            { label: "Expert TD marked done",      tone: "user" },
};

const SECTION_TITLE: Record<string, string> = {
  customer: "Customer",
  vehicle:  "Vehicle",
  booking:  "Booking",
  feedback: "Feedback",
  ai:       "AI · Call Outcome",
  other:    "Other",
};

// Lane assignment for the DV sub-section grid. Sections with long-form text or
// many fields go in the wide (left, col-span-2) lane; short metadata sections
// stack in the narrow (right) lane.
const SECTION_LANE: Record<string, "wide" | "narrow"> = {
  customer: "narrow",
  vehicle:  "narrow",
  booking:  "wide",
  feedback: "wide",
  ai:       "wide",
  other:    "wide",
};

const SECTION_EMPTY: Record<string, { icon: React.ReactNode; title: string; body: string }> = {
  customer: {
    icon: <User size={18} strokeWidth={2} />,
    title: "No customer details yet",
    body:  "Captured when the lead is created.",
  },
  vehicle: {
    icon: <Car size={18} strokeWidth={2} />,
    title: "No vehicle interest recorded",
    body:  "Filled in once the customer picks a model.",
  },
  booking: {
    icon: <CalendarCheck2 size={18} strokeWidth={2} />,
    title: "No booking yet",
    body:  "Fills in once a test drive is scheduled.",
  },
  feedback: {
    icon: <MessageSquareHeart size={18} strokeWidth={2} />,
    title: "No feedback yet",
    body:  "Captured automatically after the post-test-drive call.",
  },
  ai: {
    icon: <Sparkles size={18} strokeWidth={2} />,
    title: "No AI call activity",
    body:  "Maya's call summary appears here once she's connected.",
  },
  other: {
    icon: <Inbox size={18} strokeWidth={2} />,
    title: "Nothing recorded here yet",
    body:  "Fields will appear as the workflow progresses.",
  },
};

function SubSection({
  sectionKey, fields, data, lane,
}: {
  sectionKey: string;
  fields: any[];
  data: Record<string, unknown>;
  lane: "wide" | "narrow";
}) {
  const title = SECTION_TITLE[sectionKey] ?? "Other";
  const populated = fields.filter((f) => {
    const r = data[f.field_key];
    return r != null && r !== "" && r !== "—";
  }).length;
  const isEmpty = populated === 0;
  const [expanded, setExpanded] = useState<Record<string, boolean>>({});
  const LONGTEXT_PREVIEW = 220;
  const gridClass = lane === "narrow"
    ? "grid grid-cols-1 gap-y-5"
    : "grid grid-cols-2 gap-x-8 gap-y-5";

  return (
    <div>
      {/* Section header — small pink/red uppercase letter-spaced label */}
      <div className="text-[11px] font-bold uppercase tracking-[0.12em] mb-5" style={{ color: ACCENT }}>
        {title}
      </div>

      {isEmpty ? (
        (() => {
          const e = SECTION_EMPTY[sectionKey] ?? SECTION_EMPTY.other;
          return (
            <div className="flex items-start gap-3 rounded-xl px-4 py-3.5" style={{ border: `1px dashed ${TM_BORDER}` }}>
              <div className="w-9 h-9 rounded-lg flex items-center justify-center shrink-0 text-stone-400">
                {e.icon}
              </div>
              <div className="min-w-0">
                <div className="text-[13px] font-semibold leading-tight" style={{ color: INK }}>{e.title}</div>
                <div className="text-[12px] text-stone-500 mt-1 leading-snug">{e.body}</div>
              </div>
            </div>
          );
        })()
      ) : (
        <div className={gridClass}>
          {fields
            .filter((f) => {
              const r = data[f.field_key];
              return r != null && r !== "" && r !== "—";
            })
            .map((f) => {
            const raw = data[f.field_key];
            const empty = raw == null || raw === "" || raw === "—";
            const text = empty ? "—" : fmtCellText(raw, f.data_type, f.field_key);
            const isRecording = !empty && /recording_url$/i.test(f.field_key);
            const isUrl = !empty && !isRecording && typeof raw === "string" && /^https?:\/\//i.test(raw);
            const isLongText = !empty && f.data_type === "longtext" && text.length > LONGTEXT_PREVIEW;
            // Any prose-style value (longtext data_type, or just a long string) reads
            // as a paragraph — kill the bold weight and let it breathe.
            const isProse = !empty && (f.data_type === "longtext" || text.length > 80);
            const isRecommend = !empty && f.field_key === "feedback_would_recommend";
            // UUID-ish identifiers (current_state_id, workflow_id, …) read as
            // plumbing — render compact monospaced chips instead of bold values.
            const isIdChip = !empty && (/_id$/i.test(f.field_key) || /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(String(raw)));
            // Short enum-ish status fields (scheduling_ended_reason, feedback_failure,
            // test_drive_outcome, …) read as status chips, tone derived from the value.
            const isStatusChip = !empty && !isIdChip && /_(reason|failure|outcome|status)$/i.test(f.field_key);
            const statusTone = isStatusChip ? (() => {
              const v = String(raw).toLowerCase();
              if (/(fail|error|reject|cancel|abort|no_answer|busy|unreach)/.test(v)) return { bg: "#fde2e8", fg: "#9d0d24" };
              if (/(success|complete|done|book|confirm|positive|good|happy)/.test(v))  return { bg: "#e7f3eb", fg: "#15803d" };
              return { bg: "#f5f5f4", fg: "#57534e" };
            })() : null;
            const isOpen = !!expanded[f.field_key];
            const spanFull = lane === "wide" && isProse;
            return (
              <div
                key={f.field_key}
                className={spanFull ? "col-span-2" : ""}
              >
                <div className="text-[11.5px] font-semibold uppercase tracking-[0.06em] text-stone-400 mb-2">
                  {fmtLabel(f.output_label)}
                </div>
                <div
                  className={`text-[14px] break-words ${isProse ? "leading-relaxed max-w-[68ch]" : "leading-snug"}`}
                  style={{ color: empty ? "#c8c6c2" : isProse ? "#44403c" : INK, fontWeight: empty || isRecording || isUrl || isProse || isRecommend || isIdChip || isStatusChip ? 400 : 600 }}
                >
                  {isStatusChip && statusTone ? (
                    <span
                      className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[12px] font-semibold"
                      style={{ background: statusTone.bg, color: statusTone.fg }}
                    >
                      <span className="w-1.5 h-1.5 rounded-full" style={{ background: statusTone.fg, opacity: 0.7 }} />
                      {text}
                    </span>
                  ) : isIdChip ? (
                    <span
                      className="inline-flex items-center px-2 py-0.5 rounded-md text-[11px] font-mono tabular-nums tracking-tight"
                      style={{ background: "#f5f5f4", color: "#57534e", border: "1px solid #e7e5e4" }}
                    >
                      {text}
                    </span>
                  ) : isRecommend ? (
                    (raw === true || String(raw).toLowerCase() === "true" || String(raw).toLowerCase() === "yes") ? (
                      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[12px] font-semibold" style={{ background: "#e7f3eb", color: "#15803d" }}>
                        <ThumbsUp size={12} strokeWidth={2.25} /> Yes
                      </span>
                    ) : (
                      <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[12px] font-semibold" style={{ background: "#fde2e8", color: "#9d0d24" }}>
                        <ThumbsDown size={12} strokeWidth={2.25} /> No
                      </span>
                    )
                  ) : isRecording ? (
                    <a
                      href={String(raw)}
                      target="_blank"
                      rel="noopener noreferrer"
                      className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-[12.5px] font-semibold transition-opacity hover:opacity-90"
                      style={{ background: ACCENT_SOFT, color: ACCENT_DARK }}
                    >
                      <PlayCircle size={14} strokeWidth={2.25} />
                      Play recording
                    </a>
                  ) : isUrl ? (
                    <a
                      href={String(raw)}
                      target="_blank"
                      rel="noopener noreferrer"
                      className="inline-flex items-center gap-1 underline decoration-stone-300 underline-offset-4 hover:decoration-stone-700"
                      style={{ color: ACCENT_DARK }}
                    >
                      <span className="truncate max-w-[420px]">{text}</span>
                      <ExternalLink size={12} strokeWidth={2.25} className="shrink-0 opacity-70" />
                    </a>
                  ) : isLongText ? (
                    <span>
                      <span className="whitespace-pre-wrap">
                        {isOpen ? text : text.slice(0, LONGTEXT_PREVIEW).trimEnd() + "…"}
                      </span>
                      <button
                        type="button"
                        onClick={() => setExpanded((m) => ({ ...m, [f.field_key]: !isOpen }))}
                        className="ml-2 text-[12px] font-semibold underline-offset-4 hover:underline"
                        style={{ color: ACCENT_DARK }}
                      >
                        {isOpen ? "Show less" : "Show more"}
                      </button>
                    </span>
                  ) : (
                    text
                  )}
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}
