/**
 * AttributionDashboard — spend, CPL, cost-per-appointment, show rate, close rate,
 * revenue, and ROAS by source/campaign (spec §8, §10). Analytics are built from CRM
 * events (the analyticsDaily series), not impression-level assumptions.
 */
import React, { useMemo, useState, useCallback } from 'react';
import {
    BarChart3, DollarSign, Users, CalendarCheck, TrendingUp, Percent, Eye, Trophy,
    Zap, FileText, Crown, Activity, Filter, X, Star, Gift, Repeat, Route,
    ThumbsDown, Copy, CalendarX, Pause, Check, ShieldAlert,
} from 'lucide-react';
import {
    BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell,
    LineChart, Line, CartesianGrid, Legend,
} from 'recharts';
import { useSocialAds } from '../SocialAdsContext.jsx';
import { totals, metrics, metricsBy, metricsByFn, timeSeries, liveMetrics, reviewTotals, reviewsByFn, attributionByModel, budgetPacing } from '../engine/attribution.js';
import { getPlatform } from '../data/platforms.js';
import { Card, KpiTile, SectionHeader, PlatformBadge } from '../components/ui.jsx';

const money = (n) => `$${Math.round(n).toLocaleString('en-US')}`;
const pct = (n) => `${Math.round(n * 100)}%`;
const mmss = (s) => s == null ? '—' : `${Math.floor(s / 60)}m ${String(s % 60).padStart(2, '0')}s`;

const MODEL_NOTE = {
    first: 'First-touch credits 100% to the source that first introduced the customer.',
    last: 'Last-touch credits 100% to the final source before the sale (the default single-touch view).',
    multi: 'Multi-touch splits credit evenly (linear) across every source in the journey.',
};

const ANOMALY_META = {
    cpl_spike: { label: 'CPL spike', icon: TrendingUp, tone: 'red' },
    quality_drop: { label: 'Lead quality drop', icon: ThumbsDown, tone: 'amber' },
    duplicate_rate: { label: 'Abnormal duplicate rate', icon: Copy, tone: 'amber' },
    appt_decline: { label: 'Source-to-appointment decline', icon: CalendarX, tone: 'red' },
};
const PACE_CHIP = {
    over: 'text-red-600 dark:text-red-400 bg-red-500/10',
    on: 'text-emerald-600 dark:text-emerald-400 bg-emerald-500/10',
    under: 'text-amber-600 dark:text-amber-400 bg-amber-500/10',
};
const PACE_LABEL = { over: 'Pacing hot', on: 'On track', under: 'Under-pacing' };

export default function AttributionDashboard() {
    const { analyticsDaily, campaigns, creatives, leads, reviews, journeys, anomalies, resolveAnomaly } = useSocialAds();
    const [view, setView] = useState('platform'); // platform | campaign | creative | playbook
    const [selected, setSelected] = useState(null); // drill-down: a key within the current view
    const [model, setModel] = useState('last');     // attribution model: first | last | multi

    // Lookups for the creative + playbook breakdowns (spec §10 dimensions).
    const campById = useMemo(() => Object.fromEntries(campaigns.map(c => [c.id, c])), [campaigns]);
    const creativeById = useMemo(() => Object.fromEntries(creatives.map(c => [c.id, c])), [creatives]);
    const primaryCreativeByCampaign = useMemo(() => {
        const m = {};
        for (const cr of creatives) if (!m[cr.campaignId]) m[cr.campaignId] = cr;
        return m;
    }, [creatives]);

    // The dimension key for any object carrying { platform, campaignId } — works for
    // both analyticsDaily rows and leads, so a drill-down filters both consistently.
    const keyOf = useCallback((v, o) => {
        if (v === 'platform') return o.platform;
        if (v === 'campaign') return o.campaignId;
        if (v === 'creative') return primaryCreativeByCampaign[o.campaignId]?.id || `nocre:${o.campaignId}`;
        return campById[o.campaignId]?.playbook || 'Unmapped';
    }, [primaryCreativeByCampaign, campById]);

    // Scope spend + leads to the drilled-down entity (top KPIs + trend), if any.
    const switchView = (v) => { setView(v); setSelected(null); };
    const filteredDaily = useMemo(() => selected ? analyticsDaily.filter(r => keyOf(view, r) === selected) : analyticsDaily, [analyticsDaily, selected, view, keyOf]);
    const filteredLeads = useMemo(() => selected ? leads.filter(l => keyOf(view, l) === selected) : leads, [leads, selected, view, keyOf]);
    const filteredReviews = useMemo(() => selected ? reviews.filter(r => keyOf(view, r) === selected) : reviews, [reviews, selected, view, keyOf]);

    // Review & referral lift (spec §10) — totals scope to the drill-down; the breakdown
    // groups all reviews by the current dimension.
    const reviewAgg = useMemo(() => reviewTotals(filteredReviews), [filteredReviews]);
    const reviewsBreakdown = useMemo(() => reviewsByFn(reviews, r => keyOf(view, r)).sort((a, b) => b.count - a.count), [reviews, view, keyOf]);

    // Multi-touch attribution by model (spec §11), grouped by the current dimension.
    const modelRows = useMemo(() => attributionByModel(journeys, t => keyOf(view, t)).sort((a, b) => b[model] - a[model]), [journeys, view, keyOf, model]);
    const modelTotal = useMemo(() => modelRows.reduce((s, r) => s + r[model], 0), [modelRows, model]);

    // Budget pacing + open anomaly alerts (spec §11).
    const pacing = useMemo(() => budgetPacing(campaigns, analyticsDaily), [campaigns, analyticsDaily]);
    const openAlerts = useMemo(() => anomalies.filter(a => a.status === 'open'), [anomalies]);

    // Spend/ROAS = platform-reported; lead→won + rates = live CRM events (spec §6, §10).
    // Both honor the active drill-down filter so the KPI cards reconcile with it.
    const reported = useMemo(() => metrics(totals(filteredDaily)), [filteredDaily]);
    const live = useMemo(() => liveMetrics(filteredLeads), [filteredLeads]);
    const m = useMemo(() => ({
        ...live,
        spend: reported.spend,
        cpl: live.leads ? reported.spend / live.leads : 0,
        costPerAppt: live.appointments ? reported.spend / live.appointments : 0,
        roas: reported.spend ? live.revenue / reported.spend : 0,
    }), [reported, live]);
    const bySource = useMemo(() => {
        if (view === 'platform') return metricsBy(analyticsDaily, 'platform');
        if (view === 'campaign') return metricsBy(analyticsDaily, 'campaignId');
        if (view === 'creative') return metricsByFn(analyticsDaily, r => primaryCreativeByCampaign[r.campaignId]?.id || `nocre:${r.campaignId}`);
        if (view === 'playbook') return metricsByFn(analyticsDaily, r => campById[r.campaignId]?.playbook || 'Unmapped');
        return [];
    }, [analyticsDaily, view, primaryCreativeByCampaign, campById]);

    const revenueSeries = useMemo(() => {
        // Merge revenue + spend per date for a dual-line chart (respects drill-down).
        const rev = timeSeries(filteredDaily, 'revenue');
        const spend = timeSeries(filteredDaily, 'spend');
        return rev.map((r, i) => ({ date: r.date, revenue: r.value, spend: spend[i]?.value || 0 }));
    }, [filteredDaily]);

    const campName = (id) => campById[id]?.name || id;

    // Full + short labels for whichever dimension is selected.
    const labelFor = (k) => {
        if (view === 'platform') return getPlatform(k)?.name || k;
        if (view === 'campaign') return campName(k);
        if (view === 'creative') return k.startsWith('nocre:') ? `${campName(k.slice(6))} — no creative on file` : (creativeById[k]?.headline || k);
        return k; // playbook key is the name itself
    };
    const shortLabel = (k) => {
        if (view === 'platform') return getPlatform(k)?.short || k;
        if (view === 'campaign') return campName(k).slice(0, 10);
        if (view === 'creative') return (k.startsWith('nocre:') ? campName(k.slice(6)) : (creativeById[k]?.headline || k)).slice(0, 12);
        return k.split(' ').slice(0, 2).join(' ');
    };
    const barColor = (k) => {
        if (view === 'platform') return getPlatform(k)?.color || '#3b82f6';
        if (view === 'creative' && !k.startsWith('nocre:')) return getPlatform(creativeById[k]?.platform)?.color || '#3b82f6';
        return '#3b82f6';
    };

    // ROAS leaderboard
    const ranked = [...bySource].sort((a, b) => b.roas - a.roas);

    return (
        <div className="space-y-6">
            <SectionHeader icon={BarChart3} title="Attribution Dashboard" description="Source-to-close economics built from CRM events — leads alone are not enough.">
                <div className="flex flex-wrap rounded-lg overflow-hidden border border-zinc-200 dark:border-white/10">
                    {['platform', 'campaign', 'creative', 'playbook'].map(v => (
                        <button key={v} onClick={() => switchView(v)}
                            className={`px-3 py-1.5 text-xs font-semibold capitalize ${view === v ? 'bg-amber-500 text-white' : 'bg-white dark:bg-zinc-900 text-zinc-500'}`}>
                            By {v}
                        </button>
                    ))}
                </div>
            </SectionHeader>

            {/* Live banner + drill-down filter chip */}
            <div className="flex flex-wrap items-center justify-between gap-2 -mb-2">
                <div className="flex items-center gap-2 text-[11px] text-emerald-600 dark:text-emerald-400">
                    <Activity size={13} className="animate-pulse" />
                    <span className="font-semibold">Live</span>
                    <span className="text-zinc-400">— lead-to-won metrics update from CRM events as you act in the Lead Inbox. Spend is platform-reported.</span>
                </div>
                {selected && (
                    <button onClick={() => setSelected(null)}
                        className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[11px] font-semibold bg-amber-500/15 text-amber-700 dark:text-amber-400 hover:bg-amber-500/25 transition-colors">
                        <Filter size={12} /> {labelFor(selected)} <span className="text-amber-500/60">· by {view}</span> <X size={13} />
                    </button>
                )}
            </div>

            {/* Budget pacing & anomaly alerts (spec §11) */}
            <Card title="Budget pacing & anomaly alerts" subtitle="AI flags spend/quality anomalies; you pause or review" icon={ShieldAlert}>
                {/* Alerts */}
                {openAlerts.length === 0 ? (
                    <div className="flex items-center gap-2 text-sm text-emerald-600 dark:text-emerald-400 mb-4">
                        <Check size={16} /> No open anomalies — all campaigns within guardrails.
                    </div>
                ) : (
                    <div className="space-y-2 mb-5">
                        {openAlerts.map(a => {
                            const meta = ANOMALY_META[a.type] || ANOMALY_META.cpl_spike;
                            const AIcon = meta.icon;
                            const toneCls = meta.tone === 'red' ? 'text-red-500 bg-red-500/10' : 'text-amber-500 bg-amber-500/10';
                            return (
                                <div key={a.id} className="flex flex-col sm:flex-row sm:items-center gap-3 p-3 rounded-xl border border-zinc-200 dark:border-white/10 bg-zinc-50 dark:bg-white/[0.02]">
                                    <span className={`p-2 rounded-lg shrink-0 self-start ${toneCls}`}>{AIcon && <AIcon size={16} />}</span>
                                    <div className="min-w-0 flex-1">
                                        <div className="flex items-center gap-2 flex-wrap">
                                            <span className="font-bold text-sm text-zinc-900 dark:text-white">{campName(a.campaignId)}</span>
                                            <span className={`text-[10px] font-bold uppercase tracking-wider px-1.5 py-0.5 rounded ${a.severity === 'high' ? 'text-red-600 dark:text-red-400 bg-red-500/10' : 'text-amber-600 dark:text-amber-400 bg-amber-500/10'}`}>{a.severity}</span>
                                            <span className="text-[11px] text-zinc-400">{meta.label}</span>
                                        </div>
                                        <p className="text-xs font-mono text-zinc-700 dark:text-zinc-200 mt-0.5">{a.metric}</p>
                                        <p className="text-[11px] text-zinc-500 dark:text-zinc-400">{a.detail}</p>
                                        <p className="text-[11px] text-purple-500 mt-0.5 flex items-center gap-1"><Activity size={11} /> AI recommends: <b>{a.recommendation === 'pause' ? 'pause the campaign' : 'review & optimize'}</b></p>
                                    </div>
                                    <div className="flex items-center gap-1.5 shrink-0 self-start sm:self-center">
                                        <button onClick={() => resolveAnomaly(a.id, 'paused')} title="Pause campaign"
                                            className={`inline-flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-xs font-semibold ${a.recommendation === 'pause' ? 'bg-red-500/10 text-red-600 dark:text-red-400 hover:bg-red-500/20' : 'bg-zinc-100 dark:bg-white/5 text-zinc-600 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-white/10'}`}>
                                            <Pause size={13} /> Pause
                                        </button>
                                        <button onClick={() => resolveAnomaly(a.id, 'reviewed')} title="Mark reviewed"
                                            className="inline-flex items-center gap-1 px-2.5 py-1.5 rounded-lg text-xs font-semibold bg-zinc-100 dark:bg-white/5 text-zinc-600 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-white/10">
                                            <Check size={13} /> Review
                                        </button>
                                        <button onClick={() => resolveAnomaly(a.id, 'dismissed')} title="Dismiss" className="p-1.5 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200"><X size={15} /></button>
                                    </div>
                                </div>
                            );
                        })}
                    </div>
                )}

                {/* Budget pacing per active campaign */}
                <p className="text-[10px] font-bold uppercase tracking-wider text-zinc-400 mb-2">Budget pacing — active campaigns</p>
                <div className="space-y-2">
                    {pacing.map(p => (
                        <div key={p.id} className="flex items-center gap-3">
                            <span className="text-xs font-semibold text-zinc-700 dark:text-zinc-200 w-40 sm:w-52 truncate shrink-0" title={p.name}>{p.name}</span>
                            <div className="flex-1 min-w-0">
                                <div className="h-2 rounded-full bg-zinc-200 dark:bg-zinc-700 overflow-hidden">
                                    <div className={`h-full ${p.status === 'over' ? 'bg-red-500' : p.status === 'under' ? 'bg-amber-500' : 'bg-emerald-500'}`} style={{ width: `${Math.min(100, p.pacePct * 100)}%` }} />
                                </div>
                            </div>
                            <span className="text-[11px] font-mono text-zinc-400 w-28 text-right shrink-0 hidden sm:block">{money(p.projected)} / {money(p.monthlyCap)}</span>
                            <span className={`text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-full shrink-0 ${PACE_CHIP[p.status]}`}>{PACE_LABEL[p.status]}</span>
                        </div>
                    ))}
                </div>
            </Card>

            {/* KPI row */}
            <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
                <KpiTile label="Spend (reported)" value={money(m.spend)} icon={DollarSign} color="amber" />
                <KpiTile label="CPL" value={money(m.cpl)} icon={Users} color="blue" sub={`${m.leads} leads`} />
                <KpiTile label="Cost / appt" value={money(m.costPerAppt)} icon={CalendarCheck} color="purple" sub={`${m.appointments} appts`} />
                <KpiTile label="ROAS" value={`${m.roas.toFixed(1)}×`} icon={TrendingUp} color="emerald" sub={money(m.revenue)} />
            </div>
            <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
                <KpiTile label="Appt rate" value={pct(m.apptRate)} icon={CalendarCheck} color="blue" />
                <KpiTile label="Show rate" value={pct(m.showRate)} icon={Eye} color="cyan" />
                <KpiTile label="Estimate rate" value={pct(m.estimateRate)} icon={FileText} color="blue" sub={`${m.estimates} sent`} />
                <KpiTile label="Close rate" value={pct(m.closeRate)} icon={Percent} color="emerald" sub={`${m.wins} won`} />
            </div>
            <div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
                <KpiTile label="Speed-to-lead" value={mmss(m.avgSpeedToLead)} icon={Zap} color="amber" sub="avg to first contact" />
                <KpiTile label="Premium mix" value={pct(m.premiumMix)} icon={Crown} color="purple" sub={`${m.premiumWins} premium`} />
                <KpiTile label="Qualified leads" value={m.qualified} icon={Users} color="emerald" sub={`spam ${pct(m.spamRate)}`} />
                <KpiTile label="Revenue (won)" value={money(m.revenue)} icon={Trophy} color="amber" />
            </div>

            {/* Revenue vs spend */}
            <Card title="Revenue vs. spend" subtitle="Daily, all sources" icon={TrendingUp}>
                <ResponsiveContainer width="100%" height={240}>
                    <LineChart data={revenueSeries} margin={{ top: 5, right: 10, left: 0, bottom: 0 }}>
                        <CartesianGrid strokeDasharray="3 3" stroke="#71717a22" vertical={false} />
                        <XAxis dataKey="date" tick={{ fill: '#71717a', fontSize: 11 }} axisLine={false} tickLine={false} />
                        <YAxis tick={{ fill: '#71717a', fontSize: 11 }} axisLine={false} tickLine={false} />
                        <Tooltip contentStyle={{ background: 'rgba(24,24,27,0.95)', border: '1px solid #3f3f46', borderRadius: 12, fontSize: 12 }} labelStyle={{ color: '#fff' }} formatter={(v, n) => [money(v), n === 'revenue' ? 'Revenue' : 'Spend']} />
                        <Legend wrapperStyle={{ fontSize: 12 }} />
                        <Line type="monotone" dataKey="revenue" stroke="#10b981" strokeWidth={2.5} dot={false} name="Revenue" />
                        <Line type="monotone" dataKey="spend" stroke="#f59e0b" strokeWidth={2} dot={false} name="Spend" />
                    </LineChart>
                </ResponsiveContainer>
            </Card>

            <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
                {/* CPL by source */}
                <Card title={`Cost per lead by ${view}`} icon={Users}>
                    <ResponsiveContainer width="100%" height={240}>
                        <BarChart data={bySource} margin={{ top: 5, right: 20, left: -10, bottom: 0 }}>
                            <CartesianGrid strokeDasharray="3 3" stroke="#71717a22" vertical={false} />
                            <XAxis dataKey="key" tick={{ fill: '#71717a', fontSize: 10 }} axisLine={false} tickLine={false}
                                interval={0} tickFormatter={shortLabel} />
                            <YAxis tick={{ fill: '#71717a', fontSize: 11 }} axisLine={false} tickLine={false} />
                            <Tooltip cursor={{ fill: 'transparent' }} contentStyle={{ background: 'rgba(24,24,27,0.95)', border: '1px solid #3f3f46', borderRadius: 12, fontSize: 12 }}
                                formatter={(v) => [money(v), 'CPL']} labelFormatter={labelFor} />
                            <Bar dataKey="cpl" radius={[6, 6, 0, 0]} barSize={36}>
                                {bySource.map((s, i) => <Cell key={i} fill={barColor(s.key)} />)}
                            </Bar>
                        </BarChart>
                    </ResponsiveContainer>
                </Card>

                {/* ROAS leaderboard */}
                <Card title="ROAS leaderboard" subtitle="Ranked by return — click a row to filter" icon={Trophy}>
                    <div className="space-y-2">
                        {ranked.map((s, i) => (
                            <div key={s.key} onClick={() => setSelected(sel => sel === s.key ? null : s.key)}
                                title="Click to filter the dashboard to this row"
                                className={`flex items-center gap-3 px-3 py-2 rounded-lg cursor-pointer transition-colors ${selected === s.key ? 'bg-amber-50 dark:bg-amber-500/10 ring-1 ring-amber-400/60' : 'bg-zinc-50 dark:bg-white/5 hover:bg-zinc-100 dark:hover:bg-white/10'}`}>
                                <span className="text-xs font-bold text-zinc-400 w-4">{i + 1}</span>
                                {view === 'platform'
                                    ? <PlatformBadge platformId={s.key} />
                                    : <span className="text-sm font-semibold text-zinc-700 dark:text-zinc-200 truncate flex-1" title={labelFor(s.key)}>{labelFor(s.key)}</span>}
                                <div className="flex items-center gap-3 ml-auto text-xs">
                                    <span className="text-zinc-400">{money(s.revenue)}</span>
                                    <span className={`font-mono font-bold w-12 text-right ${s.roas >= 1 ? 'text-emerald-500' : 'text-red-500'}`}>{s.roas.toFixed(1)}×</span>
                                </div>
                            </div>
                        ))}
                    </div>
                </Card>
            </div>

            {/* Review & referral lift (spec §8 "reviews"; §10 review/referral lift) */}
            <Card title="Review & referral lift" subtitle={`Post-job reviews attributed back to source${selected ? ` · filtered to ${labelFor(selected)}` : ''}`} icon={Star}>
                <div className="grid grid-cols-3 gap-2 mb-4">
                    <LiftStat icon={Star} color="text-amber-500" value={reviewAgg.count} label="Reviews" sub={reviewAgg.count ? `${reviewAgg.avgRating.toFixed(1)}★ avg` : 'no reviews'} />
                    <LiftStat icon={Gift} color="text-emerald-500" value={reviewAgg.referralLeads} label="Referral leads" sub="generated" />
                    <LiftStat icon={Repeat} color="text-purple-500" value={money(reviewAgg.reactivationRevenue)} label="Reactivation $" sub="repeat revenue" />
                </div>

                <div className="overflow-x-auto">
                    <table className="w-full text-xs">
                        <thead>
                            <tr className="text-left text-[10px] uppercase tracking-wider text-zinc-400 border-b border-zinc-100 dark:border-white/5">
                                <th className="py-2 pr-3 font-bold">{view}</th>
                                <th className="py-2 px-2 font-bold text-right">Reviews</th>
                                <th className="py-2 px-2 font-bold text-right">Avg rating</th>
                                <th className="py-2 px-2 font-bold text-right">Referral leads</th>
                                <th className="py-2 pl-2 font-bold text-right">Reactivation $</th>
                            </tr>
                        </thead>
                        <tbody>
                            {reviewsBreakdown.length === 0 && <tr><td colSpan={5} className="py-4 text-center text-zinc-400">No reviews for this dimension yet.</td></tr>}
                            {reviewsBreakdown.map(b => (
                                <tr key={b.key} onClick={() => setSelected(sel => sel === b.key ? null : b.key)}
                                    className={`border-b border-zinc-50 dark:border-white/5 cursor-pointer transition-colors ${selected === b.key ? 'bg-amber-50 dark:bg-amber-500/10' : 'hover:bg-zinc-50 dark:hover:bg-white/5'}`}>
                                    <td className="py-2 pr-3">
                                        {view === 'platform' ? <PlatformBadge platformId={b.key} size="sm" /> : <span className="font-semibold text-zinc-700 dark:text-zinc-200">{labelFor(b.key)}</span>}
                                    </td>
                                    <td className="py-2 px-2 text-right font-mono">{b.count}</td>
                                    <td className="py-2 px-2 text-right font-mono text-amber-600 dark:text-amber-400">{b.avgRating.toFixed(1)}★</td>
                                    <td className="py-2 px-2 text-right font-mono text-emerald-600 dark:text-emerald-400">{b.referralLeads}</td>
                                    <td className="py-2 pl-2 text-right font-mono">{money(b.reactivationRevenue)}</td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            </Card>

            {/* Multi-touch attribution models (spec §11) */}
            <Card title="Multi-touch attribution" subtitle={`How closed-won revenue is credited across sources, by ${view}`} icon={Route}
                action={
                    <div className="flex rounded-lg overflow-hidden border border-zinc-200 dark:border-white/10">
                        {[['first', 'First-touch'], ['last', 'Last-touch'], ['multi', 'Multi-touch']].map(([m, label]) => (
                            <button key={m} onClick={() => setModel(m)}
                                className={`px-2.5 py-1.5 text-[11px] font-semibold ${model === m ? 'bg-amber-500 text-white' : 'bg-white dark:bg-zinc-900 text-zinc-500'}`}>
                                {label}
                            </button>
                        ))}
                    </div>
                }>
                <p className="text-[11px] text-zinc-500 dark:text-zinc-400 mb-3 flex items-start gap-1.5">
                    <Route size={13} className="text-amber-500 mt-0.5 shrink-0" />
                    {MODEL_NOTE[model]} Highlighted column is the active model; compare to see how credit shifts.
                </p>
                <div className="overflow-x-auto">
                    <table className="w-full text-xs">
                        <thead>
                            <tr className="text-left text-[10px] uppercase tracking-wider text-zinc-400 border-b border-zinc-100 dark:border-white/5">
                                <th className="py-2 pr-3 font-bold">{view}</th>
                                <th className={`py-2 px-2 font-bold text-right ${model === 'first' ? 'text-amber-600 dark:text-amber-400' : ''}`}>First-touch</th>
                                <th className={`py-2 px-2 font-bold text-right ${model === 'last' ? 'text-amber-600 dark:text-amber-400' : ''}`}>Last-touch</th>
                                <th className={`py-2 pl-2 font-bold text-right ${model === 'multi' ? 'text-amber-600 dark:text-amber-400' : ''}`}>Multi-touch</th>
                            </tr>
                        </thead>
                        <tbody>
                            {modelRows.length === 0 && <tr><td colSpan={4} className="py-4 text-center text-zinc-400">No closed-won journeys for this dimension yet.</td></tr>}
                            {modelRows.map(r => (
                                <tr key={r.key} onClick={() => setSelected(sel => sel === r.key ? null : r.key)}
                                    className={`border-b border-zinc-50 dark:border-white/5 cursor-pointer transition-colors ${selected === r.key ? 'bg-amber-50 dark:bg-amber-500/10' : 'hover:bg-zinc-50 dark:hover:bg-white/5'}`}>
                                    <td className="py-2 pr-3">
                                        {view === 'platform' ? <PlatformBadge platformId={r.key} size="sm" /> : <span className="font-semibold text-zinc-700 dark:text-zinc-200">{labelFor(r.key)}</span>}
                                    </td>
                                    <td className={`py-2 px-2 text-right font-mono ${model === 'first' ? 'font-bold text-amber-600 dark:text-amber-400' : 'text-zinc-500'}`}>{money(r.first)}</td>
                                    <td className={`py-2 px-2 text-right font-mono ${model === 'last' ? 'font-bold text-amber-600 dark:text-amber-400' : 'text-zinc-500'}`}>{money(r.last)}</td>
                                    <td className={`py-2 pl-2 text-right font-mono ${model === 'multi' ? 'font-bold text-amber-600 dark:text-amber-400' : 'text-zinc-500'}`}>{money(r.multi)}</td>
                                </tr>
                            ))}
                        </tbody>
                        {modelRows.length > 0 && (
                            <tfoot>
                                <tr className="text-[11px] font-bold text-zinc-600 dark:text-zinc-300">
                                    <td className="py-2 pr-3">Total ({model}-touch)</td>
                                    <td colSpan={3} className="py-2 pl-2 text-right font-mono text-emerald-600 dark:text-emerald-400">{money(modelTotal)}</td>
                                </tr>
                            </tfoot>
                        )}
                    </table>
                </div>
            </Card>

            {/* Detail table */}
            <Card title={`Performance by ${view}`} subtitle="Click a row to filter the KPIs above" icon={BarChart3}>
                <div className="overflow-x-auto">
                    <table className="w-full text-xs">
                        <thead>
                            <tr className="text-left text-[10px] uppercase tracking-wider text-zinc-400 border-b border-zinc-100 dark:border-white/5">
                                <th className="py-2 pr-3 font-bold">{view}</th>
                                <th className="py-2 px-2 font-bold text-right">Spend</th>
                                <th className="py-2 px-2 font-bold text-right">Leads</th>
                                <th className="py-2 px-2 font-bold text-right">CPL</th>
                                <th className="py-2 px-2 font-bold text-right">Appts</th>
                                <th className="py-2 px-2 font-bold text-right">Show</th>
                                <th className="py-2 px-2 font-bold text-right">Close</th>
                                <th className="py-2 px-2 font-bold text-right">Revenue</th>
                                <th className="py-2 pl-2 font-bold text-right">ROAS</th>
                            </tr>
                        </thead>
                        <tbody>
                            {bySource.map(s => (
                                <tr key={s.key} onClick={() => setSelected(sel => sel === s.key ? null : s.key)}
                                    className={`border-b border-zinc-50 dark:border-white/5 cursor-pointer transition-colors ${selected === s.key ? 'bg-amber-50 dark:bg-amber-500/10' : 'hover:bg-zinc-50 dark:hover:bg-white/5'}`}>
                                    <td className="py-2 pr-3">
                                        {view === 'platform' ? <PlatformBadge platformId={s.key} size="sm" /> : <span className="font-semibold text-zinc-700 dark:text-zinc-200">{labelFor(s.key)}</span>}
                                    </td>
                                    <td className="py-2 px-2 text-right font-mono">{money(s.spend)}</td>
                                    <td className="py-2 px-2 text-right font-mono">{s.leads}</td>
                                    <td className="py-2 px-2 text-right font-mono">{money(s.cpl)}</td>
                                    <td className="py-2 px-2 text-right font-mono">{s.appointments}</td>
                                    <td className="py-2 px-2 text-right font-mono">{pct(s.showRate)}</td>
                                    <td className="py-2 px-2 text-right font-mono">{pct(s.closeRate)}</td>
                                    <td className="py-2 px-2 text-right font-mono text-emerald-600 dark:text-emerald-400">{money(s.revenue)}</td>
                                    <td className={`py-2 pl-2 text-right font-mono font-bold ${s.roas >= 1 ? 'text-emerald-500' : 'text-red-500'}`}>{s.roas.toFixed(1)}×</td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            </Card>
        </div>
    );
}

function LiftStat({ icon: Icon, color, value, label, sub }) {
    return (
        <div className="rounded-xl bg-zinc-50 dark:bg-white/5 p-3 text-center">
            {Icon && <Icon size={16} className={`${color} mx-auto mb-1`} />}
            <p className="text-lg font-mono font-bold text-zinc-800 dark:text-zinc-100">{value}</p>
            <p className="text-[10px] uppercase tracking-wider text-zinc-400">{label}</p>
            {sub && <p className="text-[10px] text-zinc-400 mt-0.5">{sub}</p>}
        </div>
    );
}
