import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  User,
  Zap,
  Play,
  ArrowLeft,
  Monitor,
  Users,
  CheckCircle2,
  AlertCircle,
  ChevronRight,
  Shuffle,
  Upload,
  FileSpreadsheet,
  Loader2,
  Search,
  Film,
} from 'lucide-react';
import { PerceptionPlayer } from '@/components/modules/sentinel/PerceptionPlayer';
import { API_URL } from '@/lib/api';
import { fetchContacts } from '@/lib/crmApi';
import { cn } from '@/lib/utils';
import type { MarketingVideo } from '@/types';
import type { CrmContactListItem } from '@/types/crmTypes';

// ── Local static video catalog (served from public/videos/) ──────────────────
// Used as primary source when the remote backend is unreachable.
const LOCAL_VIDEOS: MarketingVideo[] = [
  {
    id: 'eden-devprayag',
    title: 'Eden Devprayag — Landmark Riverfront Living',
    property_name: 'Eden Devprayag',
    unit_number: '3-4BHK',
    type: 'Property Walkthrough',
    duration_seconds: 0,
    video_url: '/videos/eden-devprayag.mp4',
    thumbnail_color: '#3b82f6',
  },
  {
    id: 'sugam-prakriti',
    title: 'Sugam Prakriti — Nature-Inspired Urban Homes',
    property_name: 'Sugam Prakriti',
    unit_number: '2-3BHK',
    type: 'Property Walkthrough',
    duration_seconds: 0,
    video_url: '/videos/sugam-prakriti.mp4',
    thumbnail_color: '#10b981',
  },
  {
    id: 'atri-aqua',
    title: 'Atri Aqua — Premium Waterside Residences',
    property_name: 'Atri Aqua',
    unit_number: '2-3BHK',
    type: 'Property Walkthrough',
    duration_seconds: 0,
    video_url: '/videos/atri-aqua.mp4',
    thumbnail_color: '#06b6d4',
  },
  {
    id: 'atri-suryatoron',
    title: 'Atri Suryatoron — Sun-Drenched Elevated Living',
    property_name: 'Atri Suryatoron',
    unit_number: '2-3BHK',
    type: 'Property Walkthrough',
    duration_seconds: 0,
    video_url: '/videos/atri-suryatoron.mp4',
    thumbnail_color: '#f59e0b',
  },
];

/**
 * Resolve the full playback URL for a video.
 * Local catalog videos (starting with /videos/) are served directly by Vite
 * from public/. Remote videos from the backend already carry a full /assets/… path
 * that goes through the Vite proxy.
 */
function resolveVideoUrl(video_url: string): string {
  if (video_url.startsWith('/videos/')) {
    // Served from public/ by Vite — no proxy prefixing needed.
    return video_url;
  }
  // Remote asset — prefix with API_URL so it routes through the Vite /assets proxy.
  return `${API_URL}${video_url}`;
}

type SessionMode = 'assigned' | 'auto';
type Step = 'select-video' | 'select-mode' | 'select-lead' | 'session' | 'summary';

interface SentinelClient {
  personId: string;
  leadId: string | null;
  legacyLiId: string | null;
  name: string;
  phone: string | null;
  buyerType: string | null;
  leadStatus: string | null;
  budget: string | null;
  interest: string | null;
  tags: string[];
  currentQdScore: number;
  priorInteractionCount: number;
}

function apiAuthHeaders() {
  const token = localStorage.getItem('velocity-api-token');
  const headers: Record<string, string> = {};
  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }
  return headers;
}

function formatDuration(totalSeconds: number) {
  const mins = Math.floor(totalSeconds / 60);
  const secs = totalSeconds % 60;
  return `${mins}:${secs.toString().padStart(2, '0')}`;
}

function mapContactToSentinelClient(contact: CrmContactListItem): SentinelClient {
  const inferredTags = [
    contact.buyer_type,
    contact.lead_status,
    contact.urgency,
  ].filter(Boolean) as string[];

  return {
    personId: contact.person_id,
    leadId: contact.lead_id,
    legacyLiId: contact.legacy_li_id,
    name: contact.full_name,
    phone: contact.primary_phone,
    buyerType: contact.buyer_type,
    leadStatus: contact.lead_status,
    budget: contact.budget_band,
    interest: contact.primary_interest,
    tags: inferredTags,
    currentQdScore: Math.round(Math.max(contact.engagement_score, contact.intent_score, 0.5) * 100),
    priorInteractionCount: contact.interaction_count,
  };
}

function VideoCard({
  video,
  isSelected,
  onClick,
}: {
  video: MarketingVideo;
  isSelected: boolean;
  onClick: () => void;
}) {
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const hoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  // isPreviewing tracks whether we are actively playing a hover-preview.
  const [isPreviewing, setIsPreviewing] = useState(false);
  // srcLoaded tracks whether we have set the src attribute yet (lazy load).
  const [srcLoaded, setSrcLoaded] = useState(false);
  const [isReady, setIsReady] = useState(false);

  const resolvedSrc = resolveVideoUrl(video.video_url);

  // Stop playback and reset state.  Keep src so the browser can reuse the
  // cached data next time the card is hovered.
  const stopPreview = useCallback(() => {
    if (hoverTimerRef.current) {
      clearTimeout(hoverTimerRef.current);
      hoverTimerRef.current = null;
    }
    const el = videoRef.current;
    setIsPreviewing(false);
    if (el) {
      el.pause();
      // Snap back to a good thumbnail frame without forcing a full seek.
      if (isFinite(el.duration) && el.duration > 0) {
        el.currentTime = Math.min(5, el.duration * 0.05);
      }
    }
  }, []);

  // On mouse-enter: lazily assign src for the first time, then play after a
  // short delay so rapid hover-throughs don't start loading all videos at once.
  const startPreview = useCallback(() => {
    const el = videoRef.current;
    if (!el) return;

    // First hover — assign src and set preload to auto so the browser starts
    // buffering just this one video.
    if (!srcLoaded) {
      el.src = resolvedSrc;
      el.preload = 'auto';
      setSrcLoaded(true);
    }

    // Small delay so a quick mouse-over doesn't trigger playback.
    hoverTimerRef.current = setTimeout(() => {
      if (!el) return;
      el.muted = true;
      el.playbackRate = 1.0;
      void el.play().then(() => setIsPreviewing(true)).catch(() => null);
    }, 350);
  }, [srcLoaded, resolvedSrc]);

  // Cleanup on unmount.
  useEffect(() => {
    return () => {
      if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
      const el = videoRef.current;
      if (el) {
        el.pause();
        el.removeAttribute('src');
        el.load();
      }
    };
  }, []);

  return (
    <motion.button
      whileHover={{ scale: 1.015, y: -2 }}
      whileTap={{ scale: 0.985 }}
      onClick={onClick}
      onMouseEnter={startPreview}
      onMouseLeave={stopPreview}
      className={cn(
        'relative flex flex-col gap-3 p-3 rounded-2xl text-left transition-all w-full',
        isSelected ? 'ring-2 ring-blue-500' : 'hover:bg-white/[0.04]',
      )}
      style={{
        background: isSelected ? 'rgba(59,130,246,0.12)' : 'rgba(255,255,255,0.03)',
        border: isSelected ? '1px solid rgba(59,130,246,0.4)' : '1px solid rgba(255,255,255,0.07)',
      }}
    >
      <div
        className="w-full aspect-video rounded-xl flex items-center justify-center relative overflow-hidden"
        style={{ background: `linear-gradient(135deg, ${video.thumbnail_color}22, ${video.thumbnail_color}44)` }}
      >
        {/*
          The <video> element is always rendered but starts with NO src (preload=none).
          src is assigned lazily on first hover via startPreview().
          This prevents the browser from fetching all 4 video files on mount.
        */}
        <video
          ref={videoRef}
          muted
          playsInline
          preload="none"
          className={cn(
            'absolute inset-0 h-full w-full object-cover transition-opacity duration-300',
            isReady ? 'opacity-100' : 'opacity-0',
          )}
          onLoadedData={(e) => {
            const el = e.currentTarget;
            setIsReady(true);
            if (isFinite(el.duration) && el.duration > 0) {
              el.currentTime = Math.min(5, el.duration * 0.05);
            }
          }}
        />
        <div
          className="absolute inset-0 pointer-events-none"
          style={{ background: `radial-gradient(ellipse at center, ${video.thumbnail_color}25 0%, rgba(8,10,18,0.2) 62%, rgba(8,10,18,0.55) 100%)` }}
        />
        {/* Placeholder icon shown until the first hover loads the video */}
        {!isReady && (
          <div className="absolute inset-0 flex items-center justify-center">
            <Film className="w-7 h-7" style={{ color: video.thumbnail_color, opacity: 0.6 }} />
          </div>
        )}
        <div
          className="absolute bottom-2 right-2 px-2 py-0.5 rounded-md text-[10px] font-medium"
          style={{ background: 'rgba(0,0,0,0.68)', color: '#dbeafe' }}
        >
          {video.duration_seconds > 0 ? formatDuration(video.duration_seconds) : 'Video'}
        </div>
        {isPreviewing && (
          <div className="absolute top-2 left-2 px-2 py-0.5 rounded-md text-[10px] font-semibold bg-cyan-500/20 border border-cyan-400/30 text-cyan-300">
            Preview
          </div>
        )}
        {isSelected && (
          <div className="absolute inset-0 flex items-center justify-center">
            <div className="w-10 h-10 rounded-full bg-blue-500/20 flex items-center justify-center backdrop-blur-md">
              <CheckCircle2 className="w-5 h-5 text-blue-300" />
            </div>
          </div>
        )}
      </div>

      <div>
        <p className="text-sm font-semibold text-white leading-tight line-clamp-2">{video.title}</p>
        <p className="text-[11px] text-zinc-500 mt-0.5">{video.type} · {video.property_name}</p>
      </div>
    </motion.button>
  );
}

function LeadRow({
  lead,
  isSelected,
  onClick,
}: {
  lead: SentinelClient;
  isSelected: boolean;
  onClick: () => void;
}) {
  const initials = lead.name.split(' ').map((n) => n[0]).join('').slice(0, 2);
  const qd = lead.currentQdScore;

  return (
    <motion.button
      whileHover={{ x: 4 }}
      onClick={onClick}
      className={cn(
        'flex items-center gap-3 w-full px-4 py-3 rounded-xl transition-all text-left',
        isSelected ? 'ring-1 ring-blue-500' : 'hover:bg-white/[0.04]',
      )}
      style={{
        background: isSelected ? 'rgba(59,130,246,0.10)' : 'rgba(255,255,255,0.02)',
        border: `1px solid ${isSelected ? 'rgba(59,130,246,0.3)' : 'rgba(255,255,255,0.06)'}`,
      }}
    >
      <div
        className="w-9 h-9 rounded-xl flex items-center justify-center text-xs font-bold flex-shrink-0"
        style={{ background: 'rgba(59,130,246,0.15)', color: '#60a5fa' }}
      >
        {initials}
      </div>
      <div className="flex-1 min-w-0">
        <p className="text-sm font-semibold text-white truncate">{lead.name}</p>
        <p className="text-[11px] text-zinc-500">{lead.interest ?? lead.phone ?? 'No interest specified'}</p>
      </div>
      <div className="flex gap-1 flex-shrink-0">
        {lead.tags?.map((tag) => (
          <span
            key={tag}
            className="text-[9px] px-1.5 py-0.5 rounded-md font-bold uppercase tracking-wide"
            style={{ background: 'rgba(251,191,36,0.15)', color: '#fbbf24', border: '1px solid rgba(251,191,36,0.2)' }}
          >
            {tag}
          </span>
        ))}
        {qd !== undefined && (
          <span
            className="text-[9px] px-1.5 py-0.5 rounded-md font-bold"
            style={{
              background: qd >= 75 ? 'rgba(34,197,94,0.15)' : 'rgba(59,130,246,0.15)',
              color: qd >= 75 ? '#4ade80' : '#60a5fa',
              border: `1px solid ${qd >= 75 ? 'rgba(34,197,94,0.3)' : 'rgba(59,130,246,0.3)'}`,
            }}
          >
            QD {qd}
          </span>
        )}
      </div>
      {isSelected && <ChevronRight className="w-4 h-4 text-blue-400 flex-shrink-0" />}
    </motion.button>
  );
}

function SessionSummary({
  lead,
  finalQdScore,
  sessionMode,
  onNewSession,
}: {
  lead?: SentinelClient;
  finalQdScore: number;
  sessionMode: SessionMode;
  onNewSession: () => void;
}) {
  const qColor = finalQdScore >= 75 ? '#22c55e' : finalQdScore >= 50 ? '#3b82f6' : '#f59e0b';
  const verdict =
    finalQdScore >= 80 ? 'Strongly engaged - priority follow-up' :
    finalQdScore >= 65 ? 'Engaged - schedule viewing' :
    finalQdScore >= 45 ? 'Neutral - send brochure' :
    'Low interest - reassess approach';

  return (
    <motion.div
      initial={{ opacity: 0, scale: 0.95 }}
      animate={{ opacity: 1, scale: 1 }}
      className="flex flex-col items-center gap-6 py-10 px-8 max-w-md mx-auto text-center"
    >
      <div className="relative w-28 h-28">
        <svg width="112" height="112" className="-rotate-90">
          <circle cx="56" cy="56" r="46" fill="none" stroke="rgba(255,255,255,0.06)" strokeWidth="8" />
          <motion.circle
            cx="56"
            cy="56"
            r="46"
            fill="none"
            stroke={qColor}
            strokeWidth="8"
            strokeLinecap="round"
            strokeDasharray={2 * Math.PI * 46}
            initial={{ strokeDashoffset: 2 * Math.PI * 46 }}
            animate={{ strokeDashoffset: 2 * Math.PI * 46 * (1 - finalQdScore / 100) }}
            transition={{ duration: 1.2, ease: 'easeOut', delay: 0.3 }}
            style={{ filter: `drop-shadow(0 0 10px ${qColor})` }}
          />
        </svg>
        <div className="absolute inset-0 flex flex-col items-center justify-center">
          <span className="text-3xl font-bold" style={{ color: qColor }}>{finalQdScore}</span>
          <span className="text-[10px] text-zinc-500 font-medium">QD SCORE</span>
        </div>
      </div>

      <div>
        <h3 className="text-xl font-bold text-white mb-1">Session Complete</h3>
        {lead && <p className="text-sm text-zinc-400 mb-2">Client: {lead.name}</p>}
        {sessionMode === 'auto' && (
          <div
            className="flex items-center gap-2 justify-center mb-3 px-4 py-2 rounded-xl"
            style={{ background: 'rgba(251,191,36,0.1)', border: '1px solid rgba(251,191,36,0.2)' }}
          >
            <AlertCircle className="w-4 h-4 text-amber-400" />
            <span className="text-xs text-amber-400">Auto mode finalized and lead match requested</span>
          </div>
        )}
        <p className="text-sm font-semibold" style={{ color: qColor }}>{verdict}</p>
      </div>

      <motion.button
        whileHover={{ scale: 1.03 }}
        whileTap={{ scale: 0.97 }}
        onClick={onNewSession}
        className="px-6 py-2.5 rounded-xl text-sm font-semibold text-white"
        style={{ background: 'linear-gradient(135deg, #3b82f6, #06b6d4)', boxShadow: '0 0 20px rgba(59,130,246,0.3)' }}
      >
        New Session
      </motion.button>
    </motion.div>
  );
}

export function SentinelLiveSession() {
  const [step, setStep] = useState<Step>('select-video');
  const [videos, setVideos] = useState<MarketingVideo[]>([]);
  const [videosLoading, setVideosLoading] = useState(true);
  const [videosError, setVideosError] = useState<string>('');
  const [selectedVideo, setSelectedVideo] = useState<MarketingVideo | null>(null);
  const [sessionMode, setSessionMode] = useState<SessionMode>('assigned');
  const [clients, setClients] = useState<SentinelClient[]>([]);
  const [clientsLoading, setClientsLoading] = useState(true);
  const [clientsError, setClientsError] = useState('');
  const [selectedLead, setSelectedLead] = useState<SentinelClient | null>(null);
  const [leadSearch, setLeadSearch] = useState('');
  const [finalQdScore, setFinalQdScore] = useState(50);
  const [sceneFile, setSceneFile] = useState<File | null>(null);
  const [sceneUploadState, setSceneUploadState] = useState<'idle' | 'uploading' | 'done' | 'error'>('idle');
  const [sceneMessage, setSceneMessage] = useState<string>('');

  useEffect(() => {
    let cancelled = false;
    const loadVideos = async () => {
      setVideosLoading(true);
      setVideosError('');
      try {
        // Try the remote backend first (5-second timeout so we fail fast when offline).
        const controller = new AbortController();
        const timeout = setTimeout(() => controller.abort(), 5000);
        const response = await fetch(`${API_URL}/api/videos/marketing`, {
          signal: controller.signal,
        });
        clearTimeout(timeout);
        if (!response.ok) {
          throw new Error(`Failed to load videos (${response.status})`);
        }
        const data = await response.json() as { videos?: MarketingVideo[] };
        if (!cancelled) {
          const nextVideos = data.videos ?? [];
          // If the backend returned nothing, fall back to the local catalog.
          const resolved = nextVideos.length > 0 ? nextVideos : LOCAL_VIDEOS;
          setVideos(resolved);
          setSelectedVideo((current) => current ?? resolved[0] ?? null);
        }
      } catch {
        // Backend unreachable — silently serve the local static catalog.
        if (!cancelled) {
          setVideos(LOCAL_VIDEOS);
          setSelectedVideo((current) => current ?? LOCAL_VIDEOS[0] ?? null);
        }
      } finally {
        if (!cancelled) {
          setVideosLoading(false);
        }
      }
    };
    void loadVideos();
    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    let cancelled = false;
    const loadClients = async () => {
      setClientsLoading(true);
      setClientsError('');
      try {
        const data = await fetchContacts({ limit: 200, offset: 0 });
        if (!cancelled) {
          setClients(data.contacts.map(mapContactToSentinelClient));
        }
      } catch (error) {
        if (!cancelled) {
          setClients([]);
          setClientsError(error instanceof Error ? error.message : 'Failed to load CRM contacts.');
        }
      } finally {
        if (!cancelled) {
          setClientsLoading(false);
        }
      }
    };
    void loadClients();
    return () => {
      cancelled = true;
    };
  }, []);

  const selectedVideoSceneStatus = useMemo(() => {
    if (!selectedVideo) {
      return 'No video selected';
    }
    if (sceneUploadState === 'done') {
      return sceneMessage || 'Scene map uploaded';
    }
    if (sceneUploadState === 'error') {
      return sceneMessage || 'Scene upload failed';
    }
    return sceneMessage || 'No scene CSV uploaded in this session';
  }, [sceneMessage, sceneUploadState, selectedVideo]);

  const filteredLeads = useMemo(() => {
    const query = leadSearch.trim().toLowerCase();
    if (!query) {
      return clients;
    }
    return clients.filter((lead) => {
      const haystack = [
        lead.name,
        lead.phone,
        lead.interest,
        lead.budget,
        ...(lead.tags ?? []),
      ]
        .filter(Boolean)
        .join(' ')
        .toLowerCase();
      return haystack.includes(query);
    });
  }, [clients, leadSearch]);

  const handleVideoSelect = (video: MarketingVideo) => setSelectedVideo(video);
  const handleVideoConfirm = () => {
    if (selectedVideo) {
      setStep('select-mode');
    }
  };

  const handleModeSelect = (mode: SessionMode) => {
    setSessionMode(mode);
    if (mode === 'assigned') {
      setStep('select-lead');
      return;
    }
    setSelectedLead(null);
    setStep('session');
  };

  const handleLeadConfirm = () => {
    if (selectedLead) {
      setStep('session');
    }
  };

  const handleSessionComplete = useCallback((score: number) => {
    setFinalQdScore(score);
    setStep('summary');
  }, []);

  const handleNewSession = () => {
    setStep('select-video');
    setSelectedVideo(videos[0] ?? null);
    setSelectedLead(null);
    setLeadSearch('');
    setFinalQdScore(50);
    setSceneFile(null);
    setSceneUploadState('idle');
    setSceneMessage('');
  };

  const handleSceneUpload = async () => {
    if (!selectedVideo || !sceneFile) {
      return;
    }
    setSceneUploadState('uploading');
    setSceneMessage('');
    const form = new FormData();
    form.append('file', sceneFile);
    try {
      const response = await fetch(`${API_URL}/api/scenes/upload?video_asset_id=${encodeURIComponent(selectedVideo.id)}`, {
        method: 'POST',
        headers: apiAuthHeaders(),
        body: form,
      });
      if (!response.ok) {
        const detail = await response.text();
        throw new Error(detail || 'Upload failed');
      }
      const data = await response.json() as { row_count?: number };
      setSceneUploadState('done');
      setSceneMessage(`Uploaded ${data.row_count ?? 0} scene rows for ${selectedVideo.property_name}`);
    } catch (error) {
      setSceneUploadState('error');
      setSceneMessage(error instanceof Error ? error.message : 'Upload failed');
    }
  };

  const goBack = () => {
    if (step === 'select-mode') {
      setStep('select-video');
    } else if (step === 'select-lead') {
      setStep('select-mode');
    } else if (step === 'session') {
      setStep('select-mode');
    }
  };

  return (
    <div
      className="rounded-2xl overflow-hidden"
      style={{
        background: 'rgba(255,255,255,0.02)',
        border: '1px solid rgba(255,255,255,0.07)',
        minHeight: 500,
      }}
    >
      <div
        className="flex items-center gap-3 px-5 py-4"
        style={{ borderBottom: '1px solid rgba(255,255,255,0.06)' }}
      >
        {step !== 'select-video' && step !== 'summary' && (
          <button
            onClick={goBack}
            className="p-1.5 rounded-lg text-zinc-500 hover:text-white hover:bg-white/5 transition-colors"
          >
            <ArrowLeft className="w-4 h-4" />
          </button>
        )}
        <div className="flex items-center gap-2">
          <div
            className="w-7 h-7 rounded-lg flex items-center justify-center"
            style={{ background: 'rgba(59,130,246,0.15)', border: '1px solid rgba(59,130,246,0.25)' }}
          >
            <Monitor className="w-3.5 h-3.5 text-blue-400" />
          </div>
          <div>
            <h2 className="text-sm font-semibold text-white">Live Perception Session</h2>
            <p className="text-[10px] text-zinc-500">
              {step === 'select-video' && 'Select a property video and optional scene CSV'}
              {step === 'select-mode' && `Selected: ${selectedVideo?.title}`}
              {step === 'select-lead' && 'Choose a client from your CRM'}
              {step === 'session' && (sessionMode === 'assigned' ? `Assigned: ${selectedLead?.name}` : 'Auto mode - gathering visitor intelligence')}
              {step === 'summary' && 'Session Summary'}
            </p>
          </div>
        </div>

        <div className="ml-auto flex items-center gap-1.5">
          {(['select-video', 'select-mode', 'select-lead', 'session'] as Step[]).map((s, i) => (
            <div
              key={s}
              className="w-1.5 h-1.5 rounded-full transition-colors"
              style={{
                background:
                  step === s ? '#3b82f6' :
                  ['select-video', 'select-mode', 'select-lead', 'session'].indexOf(step) > i
                    ? 'rgba(59,130,246,0.4)' : 'rgba(255,255,255,0.15)',
              }}
            />
          ))}
        </div>
      </div>

      <div className="p-5">
        <AnimatePresence mode="wait">
          {step === 'select-video' && (
            <motion.div
              key="select-video"
              initial={{ opacity: 0, x: 20 }}
              animate={{ opacity: 1, x: 0 }}
              exit={{ opacity: 0, x: -20 }}
              transition={{ duration: 0.2 }}
              className="space-y-5"
            >
              {videosLoading ? (
                <div className="rounded-2xl p-8 border border-white/10 bg-white/[0.02] flex items-center justify-center gap-3 text-zinc-400">
                  <Loader2 className="w-4 h-4 animate-spin" />
                  Loading marketing videos
                </div>
              ) : videosError ? (
                <div className="rounded-2xl p-5 border border-red-500/20 bg-red-500/5 text-sm text-red-300">
                  {videosError}
                </div>
              ) : (
                <div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3">
                  {videos.map((video) => (
                    <VideoCard
                      key={video.id}
                      video={video}
                      isSelected={selectedVideo?.id === video.id}
                      onClick={() => handleVideoSelect(video)}
                    />
                  ))}
                </div>
              )}

              <div
                className="rounded-2xl p-4"
                style={{ background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.07)' }}
              >
                <div className="flex items-start justify-between gap-4">
                  <div>
                    <p className="text-sm font-semibold text-white">Scene CSV Upload</p>
                    <p className="text-xs text-zinc-400 mt-1">
                      Upload `scene_no,start_ms,end_ms,room_type,description` so the backend can attach scene labels to biometric packets.
                    </p>
                  </div>
                  <div className="flex items-center gap-2 text-[11px] text-zinc-400">
                    <FileSpreadsheet className="w-4 h-4 text-cyan-400" />
                    {selectedVideo ? selectedVideoSceneStatus : 'Select a video first'}
                  </div>
                </div>

                <div className="mt-4 flex flex-col gap-3 md:flex-row md:items-center">
                  <label
                    className="flex-1 rounded-xl border border-dashed border-white/15 px-4 py-3 text-sm text-zinc-400 cursor-pointer hover:border-cyan-400/40 hover:text-white transition-colors"
                  >
                    <input
                      type="file"
                      accept=".csv,text/csv"
                      className="hidden"
                      onChange={(event) => setSceneFile(event.target.files?.[0] ?? null)}
                    />
                    {sceneFile ? sceneFile.name : 'Choose scene CSV'}
                  </label>
                  <motion.button
                    whileHover={{ scale: 1.02 }}
                    whileTap={{ scale: 0.98 }}
                    onClick={handleSceneUpload}
                    disabled={!selectedVideo || !sceneFile || sceneUploadState === 'uploading'}
                    className="px-4 py-3 rounded-xl text-sm font-semibold text-white disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center gap-2 min-w-[180px]"
                    style={{ background: 'linear-gradient(135deg, #0891b2, #2563eb)' }}
                  >
                    {sceneUploadState === 'uploading' ? <Loader2 className="w-4 h-4 animate-spin" /> : <Upload className="w-4 h-4" />}
                    Upload Scene Map
                  </motion.button>
                </div>
              </div>

              <motion.button
                whileHover={{ scale: 1.02 }}
                whileTap={{ scale: 0.98 }}
                disabled={!selectedVideo}
                onClick={handleVideoConfirm}
                className="w-full py-3 rounded-xl text-sm font-semibold text-white transition-all disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center gap-2"
                style={{
                  background: selectedVideo ? 'linear-gradient(135deg, #3b82f6, #06b6d4)' : 'rgba(255,255,255,0.06)',
                  boxShadow: selectedVideo ? '0 0 20px rgba(59,130,246,0.3)' : 'none',
                }}
              >
                <Play className="w-4 h-4" />
                Continue with {selectedVideo?.property_name ?? 'selected video'}
              </motion.button>
            </motion.div>
          )}

          {step === 'select-mode' && (
            <motion.div
              key="select-mode"
              initial={{ opacity: 0, x: 20 }}
              animate={{ opacity: 1, x: 0 }}
              exit={{ opacity: 0, x: -20 }}
              transition={{ duration: 0.2 }}
              className="flex flex-col gap-3"
            >
              <p className="text-sm text-zinc-400 mb-2">How would you like to start this session?</p>
              <motion.button
                whileHover={{ scale: 1.01, x: 4 }}
                whileTap={{ scale: 0.99 }}
                onClick={() => handleModeSelect('assigned')}
                className="flex items-start gap-4 p-5 rounded-2xl text-left"
                style={{ background: 'rgba(59,130,246,0.08)', border: '1px solid rgba(59,130,246,0.2)' }}
              >
                <div className="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0" style={{ background: 'rgba(59,130,246,0.15)' }}>
                  <Users className="w-5 h-5 text-blue-400" />
                </div>
                <div className="flex-1">
                  <p className="text-sm font-semibold text-white">Assigned Mode</p>
                  <p className="text-xs text-zinc-400 mt-1 leading-relaxed">
                    Select an existing client from your CRM before starting. All biometric data is linked to their profile in real time.
                  </p>
                </div>
                <ChevronRight className="w-4 h-4 text-zinc-500 flex-shrink-0 mt-3" />
              </motion.button>

              <motion.button
                whileHover={{ scale: 1.01, x: 4 }}
                whileTap={{ scale: 0.99 }}
                onClick={() => handleModeSelect('auto')}
                className="flex items-start gap-4 p-5 rounded-2xl text-left"
                style={{ background: 'rgba(245,158,11,0.08)', border: '1px solid rgba(245,158,11,0.2)' }}
              >
                <div className="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0" style={{ background: 'rgba(245,158,11,0.15)' }}>
                  <Zap className="w-5 h-5 text-amber-400" />
                </div>
                <div className="flex-1">
                  <p className="text-sm font-semibold text-white">Auto Mode</p>
                  <p className="text-xs text-zinc-400 mt-1 leading-relaxed">
                    Start immediately. The Sentinel gathers face, plate, and vehicle data from entry CCTV and matches or creates a lead after the session.
                  </p>
                  <div className="flex items-center gap-1.5 mt-2">
                    <Shuffle className="w-3 h-3 text-amber-500" />
                    <span className="text-[10px] text-amber-500 font-medium">Requires CCTV integration active</span>
                  </div>
                </div>
                <ChevronRight className="w-4 h-4 text-zinc-500 flex-shrink-0 mt-3" />
              </motion.button>
            </motion.div>
          )}

          {step === 'select-lead' && (
            <motion.div
              key="select-lead"
              initial={{ opacity: 0, x: 20 }}
              animate={{ opacity: 1, x: 0 }}
              exit={{ opacity: 0, x: -20 }}
              transition={{ duration: 0.2 }}
              className="space-y-4"
            >
              <div className="relative">
                <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-zinc-500" />
                <input
                  value={leadSearch}
                  onChange={(event) => setLeadSearch(event.target.value)}
                  placeholder="Search by client name, phone, interest, budget or tags"
                  className="w-full rounded-xl bg-white/[0.03] border border-white/10 pl-10 pr-4 py-3 text-sm text-white placeholder:text-zinc-500 outline-none focus:border-blue-500/40"
                />
              </div>
              <div className="flex flex-col gap-2 max-h-72 overflow-y-auto custom-scrollbar mb-4">
                {clientsLoading ? (
                  <div className="rounded-xl border border-white/8 bg-white/[0.02] px-4 py-8 text-center text-sm text-zinc-500 flex items-center justify-center gap-2">
                    <Loader2 className="w-4 h-4 animate-spin" />
                    Loading CRM contacts
                  </div>
                ) : clientsError ? (
                  <div className="rounded-xl border border-red-500/20 bg-red-500/5 px-4 py-6 text-center text-sm text-red-300">
                    {clientsError}
                  </div>
                ) : filteredLeads.map((lead) => (
                  <LeadRow
                    key={lead.personId}
                    lead={lead}
                    isSelected={selectedLead?.personId === lead.personId}
                    onClick={() => setSelectedLead(lead)}
                  />
                ))}
                {!clientsLoading && !clientsError && filteredLeads.length === 0 && (
                  <div className="rounded-xl border border-white/8 bg-white/[0.02] px-4 py-8 text-center text-sm text-zinc-500">
                    No client matches that search.
                  </div>
                )}
              </div>
              <motion.button
                whileHover={{ scale: 1.02 }}
                whileTap={{ scale: 0.98 }}
                disabled={!selectedLead}
                onClick={handleLeadConfirm}
                className="w-full py-3 rounded-xl text-sm font-semibold text-white flex items-center justify-center gap-2 disabled:opacity-40 disabled:cursor-not-allowed"
                style={{
                  background: selectedLead ? 'linear-gradient(135deg, #3b82f6, #06b6d4)' : 'rgba(255,255,255,0.06)',
                  boxShadow: selectedLead ? '0 0 20px rgba(59,130,246,0.3)' : 'none',
                }}
              >
                <User className="w-4 h-4" />
                Start Session with {selectedLead?.name ?? 'selected client'}
              </motion.button>
            </motion.div>
          )}

          {step === 'session' && selectedVideo && (
            <motion.div
              key="session"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.3 }}
            >
              {sessionMode === 'auto' && (
                <motion.div
                  initial={{ opacity: 0, y: -8 }}
                  animate={{ opacity: 1, y: 0 }}
                  className="flex items-center gap-2 px-4 py-2.5 rounded-xl mb-4"
                  style={{ background: 'rgba(245,158,11,0.08)', border: '1px solid rgba(245,158,11,0.2)' }}
                >
                  <Zap className="w-4 h-4 text-amber-400" />
                  <p className="text-xs text-amber-300 font-medium">
                    Auto mode active - CCTV data can be attached to this session and the backend will finalize lead matching when the video ends.
                  </p>
                </motion.div>
              )}
              <PerceptionPlayer
                videoUrl={resolveVideoUrl(selectedVideo.video_url)}
                videoAssetId={selectedVideo.id}
                personId={sessionMode === 'assigned' ? selectedLead?.personId : undefined}
                canonicalLeadId={sessionMode === 'assigned' ? selectedLead?.leadId ?? undefined : undefined}
                leadId={sessionMode === 'assigned' ? selectedLead?.legacyLiId ?? undefined : undefined}
                leadName={sessionMode === 'assigned' ? selectedLead?.name : undefined}
                leadBudget={sessionMode === 'assigned' ? selectedLead?.budget ?? undefined : undefined}
                leadInterest={sessionMode === 'assigned' ? selectedLead?.interest ?? undefined : undefined}
                priorInteractionCount={sessionMode === 'assigned' ? selectedLead?.priorInteractionCount : undefined}
                initialQdScore={sessionMode === 'assigned' ? selectedLead?.currentQdScore : undefined}
                sessionMode={sessionMode}
                videoTitle={selectedVideo.title}
                onSessionComplete={handleSessionComplete}
              />
            </motion.div>
          )}

          {step === 'summary' && (
            <motion.div
              key="summary"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
            >
              <SessionSummary
                lead={selectedLead ?? undefined}
                finalQdScore={finalQdScore}
                sessionMode={sessionMode}
                onNewSession={handleNewSession}
              />
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    </div>
  );
}
