/**
 * Learn — Module-organized content hub
 * 
 * 10 learning modules sourced from "The Ocean Doesn't Care About Your Swimming Lessons",
 * Mr. Grumpy's Investing Survival Guide, and three podcast interviews.
 * Features: attention-grabbing quote rotator, podcast video embeds, book excerpts by topic.
 */

import { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { Breadcrumb } from "@/components/Breadcrumb";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import {
  ArrowLeft,
  BookOpen,
  ChevronRight,
  Clock,
  Play,
  Waves,
  Target,
  Shield,
  Settings,
  Building,
  Brain,
  AlertTriangle,
  TrendingUp,
  Scale,
  X,
  ExternalLink,
  Quote,
  Sparkles,
  Video,
  FileText,
  ChevronDown,
  ChevronUp,
  Volume2,
  Loader2,
  CheckCircle2,
  Bookmark,
} from "lucide-react";
import { Link } from "wouter";
import { motion, AnimatePresence } from "framer-motion";
import { LazyStreamdown as Streamdown } from "@/components/LazyStreamdown";
import { SEOHead, pageSEO } from "@/components/SEOHead";
import { BreadcrumbJsonLd, breadcrumbs } from "@/components/BreadcrumbJsonLd";
import { formatReadingTime, getReadingStats, stripMarkdown, calculateReadingTime } from "@/lib/readingTime";
import { AudioPlayer, VoiceSelector } from "@/components/AudioPlayer";
import { BookmarkPopup } from "@/components/BookmarkPopup";
import { BookmarksPanel } from "@/components/BookmarksPanel";
import { trpc } from "@/lib/trpc";
import { toast } from "sonner";
import { useAuth } from "@/_core/hooks/useAuth";
import { PageTransition } from "@/components/PageTransition";
import { QUERY_CACHE } from "@/lib/queryConfig";
import { EmptyState, ErrorState } from "@/components/EmptyState";
import { ScrollReveal } from "@/components/ScrollReveal";

// ─── Types ───────────────────────────────────────────────────────────────────

interface Module {
  id: string;
  number: number;
  title: string;
  tagline: string;
  description: string;
  icon: string;
  color: string;
}

interface ModuleEssay {
  id: string;
  title: string;
  category: string;
  module: string;
  description: string;
  readTime: string;
  source: string;
  content: string;
}

interface PodcastSegment {
  label: string;
  startSeconds: number;
  endSeconds: number;
  modules: number[];
}

interface PodcastVideo {
  id: string;
  title: string;
  youtubeId: string;
  duration: string;
  description: string;
  segments: PodcastSegment[];
}

interface InsightQuote {
  quote: string;
  source: string;
  module: number;
}

interface ModulesData {
  modules: Module[];
  podcastVideos: PodcastVideo[];
  insightOfTheDay: InsightQuote[];
}

// ─── Icon Map ────────────────────────────────────────────────────────────────

const iconMap: Record<string, React.ElementType> = {
  Waves,
  Clock,
  Scale,
  TrendingUp,
  Target,
  Shield,
  Settings,
  Building,
  Brain,
  AlertTriangle,
};

// ─── Helper: format seconds to mm:ss ─────────────────────────────────────────

function formatTime(seconds: number): string {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;
  if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
  return `${m}:${String(s).padStart(2, "0")}`;
}

// ─── Quote Rotator ───────────────────────────────────────────────────────────

function QuoteRotator({ quotes, modules }: { quotes: InsightQuote[]; modules: Module[] }) {
  const [idx, setIdx] = useState(() => Math.floor(Math.random() * quotes.length));

  useEffect(() => {
    const timer = setInterval(() => {
      setIdx((prev) => (prev + 1) % quotes.length);
    }, 8000);
    return () => clearInterval(timer);
  }, [quotes.length]);

  const q = quotes[idx];
  const mod = modules.find((m) => m.number === q.module);

  return (
    <div className="relative overflow-hidden rounded-2xl border border-primary/20 bg-gradient-to-br from-primary/5 via-background to-primary/10 p-8 md:p-12">
      {/* Decorative */}
      <Quote className="absolute top-4 right-4 h-16 w-16 text-foreground/60/10" />
      <div className="absolute bottom-0 left-0 w-32 h-32 bg-primary/5 rounded-full blur-3xl" />

      <AnimatePresence mode="wait">
        <motion.div
          key={idx}
          initial={{ opacity: 0, y: 12 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: -12 }}
          transition={{ duration: 0.5 }}
        >
          <p className="font-display text-xl md:text-2xl lg:text-3xl font-medium leading-relaxed mb-6 max-w-4xl">
            "{q.quote}"
          </p>
          <div className="flex items-center gap-3 flex-wrap">
            <span className="text-sm text-muted-foreground italic">{q.source}</span>
            {mod && (
              <>
                <span className="text-muted-foreground/30">·</span>
                <span
                  className="text-xs font-mono uppercase tracking-wider px-2 py-1 rounded-full border"
                  style={{ color: mod.color, borderColor: `${mod.color}40` }}
                >
                  Module {mod.number}
                </span>
              </>
            )}
          </div>
        </motion.div>
      </AnimatePresence>

      {/* Dots */}
      <div className="flex gap-1.5 mt-6">
        {quotes.slice(0, Math.min(quotes.length, 20)).map((_, i) => (
          <button
            key={i}
            onClick={() => setIdx(i)}
            className={cn(
              "w-1.5 h-1.5 rounded-full transition-[background-color,transform]",
              i === idx ? "bg-primary w-4" : "bg-muted-foreground/30 hover:bg-muted-foreground/50"
            )}
          />
        ))}
      </div>
    </div>
  );
}

// ─── YouTube Embed ───────────────────────────────────────────────────────────

function YouTubeEmbed({
  videoId,
  startSeconds,
  title,
}: {
  videoId: string;
  startSeconds?: number;
  title: string;
}) {
  const src = startSeconds
    ? `https://www.youtube.com/embed/${videoId}?start=${startSeconds}&rel=0`
    : `https://www.youtube.com/embed/${videoId}?rel=0`;

  return (
    <div className="relative aspect-video rounded-xl overflow-hidden border border-border bg-background">
      <iframe
        src={src}
        title={title}
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
        allowFullScreen
        className="absolute inset-0 w-full h-full"
      />
    </div>
  );
}

// ─── Continue Reading Section ────────────────────────────────────────────────

function ContinueReadingSection({
  moduleEssays,
  onSelectEssay,
  essayProgressMap,
}: {
  moduleEssays: ModuleEssay[];
  onSelectEssay: (essay: ModuleEssay) => void;
  essayProgressMap: Map<string, { scrollProgress: number; isCompleted: boolean }>;
}) {
  // Filter to essays that have progress > 0 but are not completed
  const continueReadingEssays = useMemo(() => {
    const inProgress: { essay: ModuleEssay; scrollProgress: number }[] = [];
    for (const essay of moduleEssays) {
      const progress = essayProgressMap.get(essay.id);
      if (progress && progress.scrollProgress > 0 && !progress.isCompleted) {
        inProgress.push({ essay, scrollProgress: progress.scrollProgress });
      }
    }
    // Sort by highest progress first (closest to completion)
    return inProgress.sort((a, b) => b.scrollProgress - a.scrollProgress).slice(0, 5);
  }, [moduleEssays, essayProgressMap]);

  if (continueReadingEssays.length === 0) return null;

  return (
    <section className="mb-8">
      <div className="flex items-center gap-2 mb-4">
        <BookOpen className="h-5 w-5 text-foreground/60" />
        <ScrollReveal delay={0.00}>
        <h2 className="text-lg font-semibold font-brand tracking-tight">Continue Reading</h2>
        </ScrollReveal>
        <span className="text-xs text-muted-foreground font-mono ml-auto">
          {continueReadingEssays.length} in progress
        </span>
      </div>

      <div className="grid gap-3">
        {continueReadingEssays?.length === 0 && <EmptyState variant="generic" title="No data yet" description="Content will appear here once available." />}
                {continueReadingEssays.map(({ essay, scrollProgress }) => (
          <motion.div
            key={essay.id}
            initial={{ opacity: 0, x: -10 }}
            animate={{ opacity: 1, x: 0 }}
            className="group glass-card border-primary/20 rounded-xl p-4 hover:border-primary/50 transition-[colors,opacity,transform,shadow] cursor-pointer relative overflow-hidden"
            onClick={() => onSelectEssay(essay)}
          >
            {/* Progress bar at bottom */}
            <div className="absolute bottom-0 left-0 right-0 h-1 bg-muted">
              <div
                className="h-full bg-primary/60 transition-[width]"
                style={{ width: `${scrollProgress}%` }}
              />
            </div>

            <div className="flex items-center gap-4">
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2 mb-1">
                  <p className="text-xs text-foreground font-mono uppercase tracking-wider">
                    {essay.source?.split("'")[0] || essay.category}
                  </p>
                  <span className="text-xs text-muted-foreground">
                    {scrollProgress}% read
                  </span>
                </div>
                <h3 className="font-medium text-sm group-hover:text-primary transition-colors truncate">
                  {essay.title}
                </h3>
              </div>

              <div className="flex items-center gap-2">
                <div className="flex items-center gap-1 text-xs text-muted-foreground">
                  <Clock className="h-3 w-3" />
                  {formatReadingTime(essay.content)}
                </div>
                <ChevronRight className="h-4 w-4 text-muted-foreground group-hover:text-foreground/60 group-hover:translate-x-1 transition-[color,transform]" />
              </div>
            </div>
          </motion.div>
        ))}
      </div>
    </section>
  );
}

// ─── Module Card ─────────────────────────────────────────────────────────────

function ModuleCard({
  module,
  essayCount,
  podcastCount,
  completedCount = 0,
  totalReadingMinutes = 0,
  onClick,
}: {
  module: Module;
  essayCount: number;
  podcastCount: number;
  completedCount?: number;
  totalReadingMinutes?: number;
  onClick: () => void;
}) {
  const Icon = iconMap[module.icon] || BookOpen;
  const progressPct = essayCount > 0 ? Math.round((completedCount / essayCount) * 100) : 0;
  const isComplete = completedCount > 0 && completedCount >= essayCount;

  return (
    <motion.article
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ delay: module.number * 0.05 }}
      className="group glass-card rounded-xl p-6 hover:border-primary/50 transition-[colors,opacity,transform,shadow] cursor-pointer relative overflow-hidden float-card hover-lift"
      onClick={onClick}
    >
      {/* Module number badge */}
      <div
        className="absolute top-0 right-0 w-16 h-16 flex items-end justify-start pb-2 pl-2 rounded-bl-2xl"
        style={{ backgroundColor: `${module.color}15` }}
      >
        <span className="text-2xl font-bold font-data tabular-nums" style={{ color: `${module.color}80` }}>
          {module.number}
        </span>
      </div>

      <div
        className="w-10 h-10 rounded-lg flex items-center justify-center mb-4"
        style={{ backgroundColor: `${module.color}20` }}
      >
        <Icon className="h-5 w-5" style={{ color: module.color }} />
      </div>

      <h3 className="text-lg font-editorial font-semibold mb-1 group-hover:text-primary transition-colors pr-12">
        {module.title}
      </h3>
      <p className="text-xs font-mono text-muted-foreground mb-3 italic">
        "{module.tagline}"
      </p>
      <p className="text-sm text-muted-foreground mb-4 line-clamp-2">{module.description}</p>

      {/* Module completion progress bar */}
      {completedCount > 0 && (
        <div className="mb-3">
          <div className="flex items-center justify-between mb-1">
            <span className="text-[10px] font-mono text-muted-foreground">
              {isComplete ? 'Completed' : `${completedCount}/${essayCount} read`}
            </span>
            <span className="text-[10px] font-mono" style={{ color: isComplete ? module.color : undefined }}>
              {progressPct}%
            </span>
          </div>
          <div className="w-full h-1 bg-muted rounded-full overflow-hidden">
            <div
              className="h-full rounded-full transition-[width] duration-500 ease-out"
              style={{ width: `${progressPct}%`, backgroundColor: module.color }}
            />
          </div>
        </div>
      )}

      <div className="flex items-center gap-4 text-xs text-muted-foreground">
        <span className="flex items-center gap-1">
          <FileText className="h-3 w-3" />
          {essayCount} {essayCount === 1 ? "essay" : "essays"}
        </span>
        {totalReadingMinutes > 0 && (
          <span className="flex items-center gap-1">
            <Clock className="h-3 w-3" />
            {totalReadingMinutes} min
          </span>
        )}
        {podcastCount > 0 && (
          <span className="flex items-center gap-1">
            <Video className="h-3 w-3" />
            {podcastCount} {podcastCount === 1 ? "clip" : "clips"}
          </span>
        )}
        <ChevronRight className="h-4 w-4 ml-auto group-hover:text-foreground/60 group-hover:translate-x-1 transition-[color,transform]" />
      </div>
    </motion.article>
  );
}

// ─── Module Detail View ──────────────────────────────────────────────────────

function ModuleDetail({
  module,
  essays,
  podcasts,
  onBack,
  onSelectEssay,
  essayProgressMap,
}: {
  module: Module;
  essays: ModuleEssay[];
  podcasts: { video: PodcastVideo; segment: PodcastSegment }[];
  onBack: () => void;
  onSelectEssay: (essay: ModuleEssay) => void;
  essayProgressMap: Map<string, { scrollProgress: number; isCompleted: boolean }>;
}) {
  const Icon = iconMap[module.icon] || BookOpen;
  const [expandedPodcast, setExpandedPodcast] = useState<string | null>(null);

  return (
    <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
      {/* Module Header */}
      <div className="mb-8">
        <Button variant="ghost" size="sm" onClick={onBack} className="gap-2 mb-4">
          <ArrowLeft className="h-4 w-4" />
          All Modules
        </Button>

        <div className="flex items-start gap-4">
          <div
            className="w-14 h-14 rounded-xl flex items-center justify-center shrink-0"
            style={{ backgroundColor: `${module.color}20` }}
          >
            <Icon className="h-7 w-7" style={{ color: module.color }} />
          </div>
          <div>
            <div className="flex items-center gap-2 mb-1">
              <span
                className="text-xs font-mono uppercase tracking-wider px-2 py-0.5 rounded-full border"
                style={{ color: module.color, borderColor: `${module.color}40` }}
              >
                Module {module.number}
              </span>
            </div>
            <ScrollReveal delay={0.05}>
            <h2 className="text-2xl md:text-3xl font-editorial font-semibold">{module.title}</h2>
            </ScrollReveal>
            <p className="text-muted-foreground mt-1 max-w-2xl">{module.description}</p>
          </div>
        </div>
      </div>

      {/* Podcast Segments for this Module */}
      {podcasts.length > 0 && (
        <section className="mb-10">
          <h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
            <Video className="h-5 w-5 text-foreground/60" />
            Podcast Clips
          </h3>
          <div className="space-y-4">
            {podcasts.map(({ video, segment }, i) => {
              const key = `${video.id}-${i}`;
              const isExpanded = expandedPodcast === key;

              return (
                <div key={key} className="border border-border rounded-xl overflow-hidden">
                  <button
                    className="w-full flex items-center gap-4 p-4 hover:bg-card/60 backdrop-blur-md transition-colors text-left"
                    onClick={() => setExpandedPodcast(isExpanded ? null : key)}
                  >
                    <div className="w-10 h-10 rounded-lg bg-orange-500/10 flex items-center justify-center shrink-0">
                      <Play className="h-5 w-5 text-orange-700 dark:text-orange-400" />
                    </div>
                    <div className="flex-1 min-w-0">
                      <p className="font-medium truncate">{segment.label}</p>
                      <p className="text-xs text-muted-foreground">
                        {video.title} · {formatTime(segment.startSeconds)} – {formatTime(segment.endSeconds)}
                      </p>
                    </div>
                    {isExpanded ? (
                      <ChevronUp className="h-5 w-5 text-muted-foreground shrink-0" />
                    ) : (
                      <ChevronDown className="h-5 w-5 text-muted-foreground shrink-0" />
                    )}
                  </button>

                  <AnimatePresence>
                    {isExpanded && (
                      <motion.div
                        initial={{ height: 0, opacity: 0 }}
                        animate={{ height: "auto", opacity: 1 }}
                        exit={{ height: 0, opacity: 0 }}
                        transition={{ duration: 0.3 }}
                        className="overflow-hidden"
                      >
                        <div className="p-4 pt-0">
                          <YouTubeEmbed
                            videoId={video.youtubeId}
                            startSeconds={segment.startSeconds}
                            title={segment.label}
                          />
                        </div>
                      </motion.div>
                    )}
                  </AnimatePresence>
                </div>
              );
            })}
          </div>
        </section>
      )}

      {/* Essays for this Module */}
      <section>
        <h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
          <BookOpen className="h-5 w-5 text-foreground/60" />
          Book Excerpts & Essays
        </h3>
        <div className="content-stagger grid md:grid-cols-2 gap-4">
          {essays.map((essay) => {
            const progress = essayProgressMap.get(essay.id);
            const scrollPct = progress?.scrollProgress || 0;
            const isCompleted = progress?.isCompleted || false;

            return (
              <motion.article
                key={essay.id}
                initial={{ opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                className={cn(
                  "group glass-card rounded-xl p-5 hover:border-primary/50 transition-[colors,opacity,transform,shadow] cursor-pointer relative overflow-hidden float-card hover-lift",
                  isCompleted ? "border-primary/30" : "border-border"
                )}
                onClick={() => onSelectEssay(essay)}
              >
                <div className="flex items-start justify-between mb-2">
                  <span className="text-xs text-foreground font-mono uppercase tracking-wider">
                    {essay.category}
                  </span>
                  <div className="flex items-center gap-2">
                    {isCompleted && (
                      <span className="flex items-center gap-1 text-xs text-foreground">
                        <CheckCircle2 className="h-3 w-3" />
                        Done
                      </span>
                    )}
                    <span className="flex items-center gap-1 text-xs text-muted-foreground">
                      <Clock className="h-3 w-3" />
                      {formatReadingTime(essay.content)}
                    </span>
                  </div>
                </div>
                <h4 className="text-base font-semibold mb-1 group-hover:text-primary transition-colors">
                  {essay.title}
                </h4>
                <p className="text-sm text-muted-foreground line-clamp-2">{essay.description}</p>
                <div className="flex items-center justify-between mt-3">
                  <p className="text-xs text-muted-foreground/70 flex items-center gap-1">
                    <BookOpen className="h-3 w-3" />
                    {essay.source}
                  </p>
                  {scrollPct > 0 && !isCompleted && (
                    <span className="text-xs text-muted-foreground font-mono">{scrollPct}%</span>
                  )}
                </div>
                {/* Progress bar at bottom of card */}
                {scrollPct > 0 && (
                  <div className="absolute bottom-0 left-0 right-0 h-1 bg-muted">
                    <div
                      className={cn(
                        "h-full transition-[width] duration-300",
                        isCompleted ? "bg-primary" : "bg-primary/60"
                      )}
                      style={{ width: `${scrollPct}%` }}
                    />
                  </div>
                )}
              </motion.article>
            );
          })}
        </div>
      </section>
    </motion.div>
  );
}

// ─── Essay Reading View ──────────────────────────────────────────────────────

function EssayReader({
  essay,
  onBack,
  isAuthenticated,
  onProgressUpdate,
}: {
  essay: ModuleEssay;
  onBack: () => void;
  isAuthenticated: boolean;
  onProgressUpdate?: () => void;
}) {
  // TTS state
  const [audioData, setAudioData] = useState<string | null>(null);
  const [audioUrl, setAudioUrl] = useState<string | null>(null);
  const [audioFormat, setAudioFormat] = useState<string>('mp3');
  const [isGeneratingAudio, setIsGeneratingAudio] = useState(false);
  const [selectedVoiceId, setSelectedVoiceId] = useState<string>(() => {
    if (typeof window !== 'undefined') {
      return localStorage.getItem('speechify-preferred-voice') || 'george';
    }
    return 'george';
  });

  // Scroll progress state
  const [scrollPercent, setScrollPercent] = useState(0);
  const scrollRef = useRef<HTMLDivElement>(null);
  const contentRef = useRef<HTMLElement>(null);
  const lastSavedProgress = useRef(0);
  const readingStartTime = useRef<number>(Date.now());

  // Bookmarks state
  const [showBookmarks, setShowBookmarks] = useState(false);
  const utils = trpc.useUtils();
  const { data: bookmarks = [], isLoading: bookmarksLoading } = trpc.essayBookmarks.getAll.useQuery(
    { essayId: essay.id }, { ...QUERY_CACHE.STATIC,  enabled: isAuthenticated });
  const addBookmarkMutation = trpc.essayBookmarks.add.useMutation({
    onSuccess: () => {
      utils.essayBookmarks.getAll.invalidate({ essayId: essay.id });
      toast.success('Bookmark saved!');
    },
    onError: () => toast.error('Failed to save bookmark'),
  });
  const removeBookmarkMutation = trpc.essayBookmarks.remove.useMutation({
    onSuccess: () => {
      utils.essayBookmarks.getAll.invalidate({ essayId: essay.id });
      toast.success('Bookmark removed');
    },
    onError: () => toast.error('Failed to remove bookmark'),
  });
  const updateBookmarkMutation = trpc.essayBookmarks.update.useMutation({
    onSuccess: () => {
      utils.essayBookmarks.getAll.invalidate({ essayId: essay.id });
      toast.success('Bookmark updated');
    },
    onError: () => toast.error('Failed to update bookmark'),
  });

  // Fetch available voices
  const { data: voices = [] } = trpc.speechify.getVoices.useQuery(undefined, QUERY_CACHE.SLOW_MOVING);

  // TTS mutation
  const generateSpeech = trpc.speechify.generateLongSpeech.useMutation({
    onSuccess: (data) => {
      setAudioUrl(data.audioUrl || null);
      setAudioData(data.audioData || null);
      setAudioFormat(data.audioFormat);
      setIsGeneratingAudio(false);
    },
    onError: (error) => {
      console.error('TTS error:', error);
      toast.error('Failed to generate audio. Try again.');
      setIsGeneratingAudio(false);
    },
  });

  // Scroll progress mutation (debounced save)
  const updateScrollProgress = trpc.essayProgress.updateScrollProgress.useMutation({
    onSuccess: () => {
      onProgressUpdate?.();
    },
  });
  const updateReadTime = trpc.essayProgress.updateReadTime.useMutation();

  // Track scroll position
  useEffect(() => {
    const viewport = scrollRef.current?.querySelector('[data-slot="scroll-area-viewport"]') as HTMLElement | null;
    if (!viewport) return;

    let saveTimer: ReturnType<typeof setTimeout> | null = null;

    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = viewport;
      const maxScroll = scrollHeight - clientHeight;
      if (maxScroll <= 0) return;

      const percent = Math.round((scrollTop / maxScroll) * 100);
      setScrollPercent(percent);

      // Debounced save: only save if authenticated and progress increased by 5%+
      if (isAuthenticated && percent - lastSavedProgress.current >= 5) {
        if (saveTimer) clearTimeout(saveTimer);
        saveTimer = setTimeout(() => {
          lastSavedProgress.current = percent;
          updateScrollProgress.mutate({
            essayId: essay.id,
            scrollProgress: percent,
          });
        }, 1000);
      }
    };

    viewport.addEventListener('scroll', handleScroll, { passive: true });
    return () => {
      viewport.removeEventListener('scroll', handleScroll);
      if (saveTimer) clearTimeout(saveTimer);
    };
  }, [essay.id, isAuthenticated]);

  // Save reading time and final scroll position on unmount
  useEffect(() => {
    return () => {
      if (!isAuthenticated) return;

      const readingTime = Math.floor((Date.now() - readingStartTime.current) / 1000);
      if (readingTime > 5) {
        updateReadTime.mutate({
          essayId: essay.id,
          additionalSeconds: readingTime,
        });
      }

      // Final save of scroll position
      if (scrollPercent > lastSavedProgress.current) {
        updateScrollProgress.mutate({
          essayId: essay.id,
          scrollProgress: scrollPercent,
        });
      }
    };
  }, []);

  // Handle listen button click
  const handleListen = () => {
    if (audioData || audioUrl) {
      setAudioData(null);
      setAudioUrl(null);
      return;
    }

    setIsGeneratingAudio(true);
    const cleanText = stripMarkdown(essay.content);
    generateSpeech.mutate({ text: cleanText, voiceId: selectedVoiceId });
  };

  // Handle voice change
  const handleVoiceChange = (voiceId: string) => {
    setSelectedVoiceId(voiceId);
    if (typeof window !== 'undefined') {
      localStorage.setItem('speechify-preferred-voice', voiceId);
    }
    setAudioData(null);
    setAudioUrl(null);
  };

  const readingStats = getReadingStats(essay.content);

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="fixed inset-0 z-50 bg-background"
    >
      {/* Reading progress bar at the very top */}
      <div className="fixed top-0 left-0 right-0 z-[60] h-1 bg-muted">
        <motion.div
          className="h-full bg-primary"
          initial={{ width: 0 }}
          animate={{ width: `${scrollPercent}%` }}
          transition={{ duration: 0.15, ease: 'linear' }}
        />
      </div>

      <div className="sticky top-0 glass-strong backdrop-blur-md border-b border-border z-10 pt-1">
        <div className="container mx-auto px-4 py-3">
          <div className="flex items-center justify-between">
            <Button variant="ghost" size="sm" onClick={onBack} className="gap-2">
              <ArrowLeft className="h-4 w-4" />
              Back
            </Button>
            <div className="flex items-center gap-2">
              {/* Scroll progress indicator */}
              <span className="text-xs text-muted-foreground font-mono hidden sm:block">
                {scrollPercent}%
              </span>
              {/* Voice Selector */}
              {voices.length > 0 && (
                <VoiceSelector
                  voices={voices}
                  selectedVoiceId={selectedVoiceId}
                  onVoiceChange={handleVoiceChange}
                  disabled={isGeneratingAudio}
                />
              )}
              {/* Bookmarks Button - only for authenticated users */}
              {isAuthenticated && (
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setShowBookmarks(true)}
                  className="gap-1.5 relative"
                >
                  <Bookmark className="h-4 w-4" />
                  <span className="hidden sm:inline">Bookmarks</span>
                  {bookmarks.length > 0 && (
                    <span className="absolute -top-1.5 -right-1.5 bg-primary text-primary-foreground text-[10px] font-bold rounded-full w-4 h-4 flex items-center justify-center">
                      {bookmarks.length}
                    </span>
                  )}
                </Button>
              )}
              {/* Listen Button */}
              <Button
                variant="outline"
                size="sm"
                onClick={handleListen}
                disabled={isGeneratingAudio}
                className="gap-2"
              >
                {isGeneratingAudio ? (
                  <>
                    <div className="skeleton-shimmer h-8 w-8 rounded-full" aria-hidden="true" />
                    <span className="hidden sm:inline">Generating...</span>
                  </>
                ) : (audioData || audioUrl) ? (
                  <>
                    <Volume2 className="h-4 w-4 text-foreground/60" />
                    <span className="hidden sm:inline">Stop</span>
                  </>
                ) : (
                  <>
                    <Volume2 className="h-4 w-4" />
                    <span className="hidden sm:inline">Listen</span>
                  </>
                )}
              </Button>
            </div>
          </div>
        </div>
      </div>

      <ScrollArea className="h-[calc(100vh-56px)]" ref={scrollRef}>
        <article className="container mx-auto px-4 py-8 max-w-3xl relative" ref={contentRef as any}>
          <header className="mb-8">
            <span className="text-xs text-foreground font-mono uppercase tracking-wider">
              {essay.category}
            </span>
            <ScrollReveal delay={0.10}>
            <h1 className="text-3xl md:text-4xl font-display font-semibold mt-2 mb-3">
              {essay.title}
            </h1>
            </ScrollReveal>
            <p className="text-muted-foreground">{essay.description}</p>
            <div className="flex items-center gap-4 mt-4 text-sm text-muted-foreground">
              <span className="flex items-center gap-1">
                <Clock className="h-4 w-4" />
                {readingStats.readingTimeFormatted}
              </span>
              <span className="flex items-center gap-1 text-xs text-muted-foreground/70">
                {readingStats.wordCount.toLocaleString()} words
              </span>
              <span className="flex items-center gap-1">
                <BookOpen className="h-4 w-4" />
                {essay.source}
              </span>
            </div>

            {/* Audio Player - appears when audio is generated */}
            {(audioData || audioUrl) && (
              <div className="mt-4">
                <AudioPlayer
                  audioData={audioUrl ? undefined : audioData || undefined}
                  src={audioUrl || undefined}
                  audioFormat={audioFormat}
                  autoPlay
                  showKeyboardHints
                  onEnded={() => {
                    setAudioData(null);
                    setAudioUrl(null);
                  }}
                />
              </div>
            )}
          </header>

          <div className="prose prose-lg dark:prose-invert max-w-none">
            <Streamdown>{essay.content}</Streamdown>
          </div>

          <footer className="mt-12 pt-8 border-t border-border">
            <p className="text-sm text-muted-foreground italic">
              From the writings of David Steinberg, Founder & Chief Investment Officer of Marlowe
              Partners.
            </p>
          </footer>
        </article>
      </ScrollArea>

      {/* Bookmark text selection popup */}
      {isAuthenticated && contentRef.current && (
        <BookmarkPopup
          isAuthenticated={isAuthenticated}
          containerRef={contentRef}
          isSaving={addBookmarkMutation.isPending}
          onSave={(data) => {
            addBookmarkMutation.mutate({
              essayId: essay.id,
              ...data,
            });
          }}
        />
      )}

      {/* Bookmarks panel */}
      <BookmarksPanel
        isOpen={showBookmarks}
        onClose={() => setShowBookmarks(false)}
        bookmarks={bookmarks}
        isLoading={bookmarksLoading}
        essayTitle={essay.title}
        onDelete={(bookmarkId) => removeBookmarkMutation.mutate({ bookmarkId })}
        onUpdate={(bookmarkId, data) => updateBookmarkMutation.mutate({ bookmarkId, ...data })}
        isDeleting={removeBookmarkMutation.isPending}
        isUpdating={updateBookmarkMutation.isPending}
      />
    </motion.div>
  );
}

// ─── Full Podcast View ───────────────────────────────────────────────────────

function PodcastSection({ podcasts, modules }: { podcasts: PodcastVideo[]; modules: Module[] }) {
  const [activePodcast, setActivePodcast] = useState<string | null>(null);
  const [activeSegment, setActiveSegment] = useState<number | null>(null);

  return (
    <section className="mb-10">
      <h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
        <Video className="h-5 w-5 text-foreground/60" />
        Podcast Interviews
      </h3>
      <p className="text-sm text-muted-foreground mb-6">
        Three in-depth conversations covering investing philosophy, market structure, and the business of
        managing capital.
      </p>

      <div className="space-y-4">
        {podcasts.map((podcast) => (
          <div key={podcast.id} className="border border-border rounded-xl overflow-hidden">
            {/* Podcast Header */}
            <button
              className="w-full flex items-center gap-4 p-5 hover:bg-card/60 backdrop-blur-md transition-colors text-left"
              onClick={() => setActivePodcast(activePodcast === podcast.id ? null : podcast.id)}
            >
              <div className="w-12 h-12 rounded-xl bg-orange-500/10 flex items-center justify-center shrink-0">
                <Play className="h-6 w-6 text-orange-700 dark:text-orange-400" />
              </div>
              <div className="flex-1 min-w-0">
                <p className="font-semibold">{podcast.title}</p>
                <p className="text-sm text-muted-foreground mt-0.5">{podcast.description}</p>
                <p className="text-xs text-muted-foreground/70 mt-1">
                  {podcast.duration} · {podcast.segments.length} segments
                </p>
              </div>
              {activePodcast === podcast.id ? (
                <ChevronUp className="h-5 w-5 text-muted-foreground shrink-0" />
              ) : (
                <ChevronDown className="h-5 w-5 text-muted-foreground shrink-0" />
              )}
            </button>

            <AnimatePresence>
              {activePodcast === podcast.id && (
                <motion.div
                  initial={{ height: 0, opacity: 0 }}
                  animate={{ height: "auto", opacity: 1 }}
                  exit={{ height: 0, opacity: 0 }}
                  transition={{ duration: 0.3 }}
                  className="overflow-hidden"
                >
                  <div className="p-5 pt-0 space-y-4">
                    {/* Full video embed */}
                    <YouTubeEmbed
                      videoId={podcast.youtubeId}
                      startSeconds={activeSegment !== null ? podcast.segments[activeSegment]?.startSeconds : undefined}
                      title={podcast.title}
                    />

                    {/* Segment list */}
                    <div className="space-y-2">
                      <p className="text-xs font-mono uppercase tracking-wider text-muted-foreground">
                        Jump to segment
                      </p>
                      {podcast.segments.map((seg, i) => {
                        const segModules = seg.modules
                          .map((n) => modules.find((m) => m.number === n))
                          .filter(Boolean) as Module[];

                        return (
                          <button
                            key={i}
                            className={cn(
                              "w-full flex items-center gap-3 p-3 rounded-lg text-left transition-colors",
                              activeSegment === i
                                ? "bg-primary/10 border border-primary/30"
                                : "hover:bg-card border border-transparent"
                            )}
                            onClick={() => setActiveSegment(i)}
                          >
                            <span className="text-xs font-mono text-muted-foreground w-14 shrink-0">
                              {formatTime(seg.startSeconds)}
                            </span>
                            <span className="flex-1 text-sm font-medium">{seg.label}</span>
                            <div className="flex gap-1">
                              {segModules.map((m) => (
                                <span
                                  key={m.id}
                                  className="text-[10px] font-mono px-1.5 py-0.5 rounded-full border"
                                  style={{ color: m.color, borderColor: `${m.color}40` }}
                                >
                                  {m.number}
                                </span>
                              ))}
                            </div>
                          </button>
                        );
                      })}
                    </div>
                  </div>
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        ))}
      </div>
    </section>
  );
}

// ─── Main Learn Page ─────────────────────────────────────────────────────────

export default function Learn() {
  const [modulesData, setModulesData] = useState<ModulesData | null>(null);
  const [moduleEssays, setModuleEssays] = useState<ModuleEssay[]>([]);
  const [selectedModule, setSelectedModule] = useState<Module | null>(null);
  const [selectedEssay, setSelectedEssay] = useState<ModuleEssay | null>(null);
  const [showPodcasts, setShowPodcasts] = useState(false);

  // Auth & reading progress
  const { isAuthenticated } = useAuth();
  const { data: progressData, refetch: refetchProgress } = trpc.essayProgress.getAll.useQuery(
    undefined, { ...QUERY_CACHE.STATIC,  enabled: isAuthenticated });

  // Build a map of essayId -> progress for quick lookup
  const essayProgressMap = useMemo(() => {
    const map = new Map<string, { scrollProgress: number; isCompleted: boolean }>();
    if (progressData) {
      for (const p of progressData) {
        map.set(p.essayId, {
          scrollProgress: p.scrollProgress || 0,
          isCompleted: p.isCompleted || false,
        });
      }
    }
    return map;
  }, [progressData]);

  // Load data
  useEffect(() => {
    Promise.all([
      fetch("/essays/modules.json").then((r) => r.json()),
      fetch("/essays/module-essays.json").then((r) => r.json()),
    ])
      .then(([mData, eData]) => {
        setModulesData(mData as ModulesData);
        setModuleEssays(eData as ModuleEssay[]);
      })
      .catch((err) => console.error("Failed to load learn data:", err));
  }, []);

  // Compute essay, podcast, and completion counts per module
  const moduleStats = useMemo(() => {
    if (!modulesData) return {};
    const stats: Record<string, { essays: number; podcasts: number; completed: number; totalReadingMinutes: number }> = {};
    for (const mod of modulesData.modules) {
      const modEssays = moduleEssays.filter((e) => e.module === mod.id);
      const essayCount = modEssays.length;
      let podcastCount = 0;
      for (const podcast of modulesData.podcastVideos) {
        podcastCount += podcast.segments.filter((s) => s.modules.includes(mod.number)).length;
      }
      // Count completed essays for this module
      let completedCount = 0;
      let totalReadingMinutes = 0;
      for (const essay of modEssays) {
        const progress = essayProgressMap.get(essay.id);
        if (progress?.isCompleted) completedCount++;
        totalReadingMinutes += calculateReadingTime(essay.content);
      }
      stats[mod.id] = { essays: essayCount, podcasts: podcastCount, completed: completedCount, totalReadingMinutes };
    }
    return stats;
  }, [modulesData, moduleEssays, essayProgressMap]);

  // Get podcasts relevant to selected module
  const modulePodcasts = useMemo(() => {
    if (!selectedModule || !modulesData) return [];
    const results: { video: PodcastVideo; segment: PodcastSegment }[] = [];
    for (const video of modulesData.podcastVideos) {
      for (const segment of video.segments) {
        if (segment.modules.includes(selectedModule.number)) {
          results.push({ video, segment });
        }
      }
    }
    return results;
  }, [selectedModule, modulesData]);

  // Dynamic SEO: update OG tags based on navigation depth
  const seoProps = useMemo(() => {
    if (selectedEssay) {
      return {
        title: `${selectedEssay.title} | Marlowe Keynes Learn`,
        description: selectedEssay.content
          ? selectedEssay.content.replace(/[#*_\[\]()>]/g, '').slice(0, 155).trim() + '...'
          : pageSEO.learn.description,
        image: pageSEO.learn.image,
        type: 'article' as const,
      };
    }
    if (selectedModule) {
      return {
        title: `${selectedModule.title} | Marlowe Keynes Learn`,
        description: selectedModule.description.slice(0, 155).trim() + (selectedModule.description.length > 155 ? '...' : ''),
        image: pageSEO.learn.image,
        type: 'course' as const,
      };
    }
    return pageSEO.learn;
  }, [selectedModule, selectedEssay]);
  SEOHead(seoProps);

  // Dynamic breadcrumbs based on navigation depth
  const currentBreadcrumbs = useMemo(() => {
    if (selectedEssay && selectedModule) {
      return breadcrumbs.learnEssay(selectedModule.title, selectedModule.id, selectedEssay.title, selectedEssay.id);
    }
    if (selectedModule) {
      return breadcrumbs.learnModule(selectedModule.title, selectedModule.id);
    }
    return breadcrumbs.learn;
  }, [selectedModule, selectedEssay]);

  // Course structured data for Google rich results
  useEffect(() => {
    if (!modulesData) return;
    const courseList = modulesData.modules.map((mod: Module) => ({
      "@type": "Course",
      "name": mod.title,
      "description": mod.description,
      "provider": {
        "@type": "Organization",
        "name": "Marlowe Keynes Learn",
        "url": "https://marlowekeyneslearn.com"
      },
      "hasCourseInstance": {
        "@type": "CourseInstance",
        "courseMode": "online",
        "courseWorkload": "PT1H",
        "isAccessibleForFree": true
      },
      "educationalLevel": "Intermediate",
      "about": mod.tagline,
      "inLanguage": "en"
    }));
    const script = document.createElement('script');
    script.type = 'application/ld+json';
    script.id = 'learn-course-structured-data';
    script.textContent = JSON.stringify({
      "@context": "https://schema.org",
      "@type": "ItemList",
      "name": "Marlowe Keynes Learn - Investment Education Modules",
      "description": "Structured investment education from The Ocean Doesn't Care About Your Swimming Lessons",
      "numberOfItems": courseList.length,
      "itemListElement": courseList.map((course: Record<string, unknown>, i: number) => ({
        "@type": "ListItem",
        "position": i + 1,
        "item": course
      }))
    });
    // Remove old one if exists
    document.getElementById('learn-course-structured-data')?.remove();
    document.head.appendChild(script);
    return () => { script.remove(); };
  }, [modulesData]);

  if (!modulesData) {
    return (
      <div className="min-h-screen bg-background flex items-center justify-center">
        <div className="animate-pulse text-muted-foreground">Loading learning modules...</div>
      </div>
    );
  }

  return (
    <PageTransition>
    <div className="min-h-screen bg-background text-foreground">
      {/* Header */}
      <header className="sticky top-0 z-40 glass border-b border-border/30">
        <div className="container mx-auto px-4 py-3">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-4">
              <Link href="/">
                <Button variant="ghost" size="icon" aria-label="Action" className="rounded-full">
                  <ArrowLeft className="h-5 w-5" />
                </Button>
              </Link>
              <div className="flex items-center gap-3">
                <div className="w-10 h-10 rounded-full bg-gradient-to-br from-primary/20 to-primary/40 flex items-center justify-center">
                  <Sparkles className="h-5 w-5 text-foreground/60" />
                </div>
                <div>
                  <h1 className="text-lg font-semibold font-editorial tracking-tight">Learn</h1>
                  <p className="text-xs text-muted-foreground">
                    The Ocean Doesn't Care About Your Swimming Lessons
                  </p>
                </div>
              </div>
            </div>

            <div className="flex items-center gap-2">
              <Button
                variant={showPodcasts ? "default" : "outline"}
                size="sm"
                onClick={() => {
                  setShowPodcasts(!showPodcasts);
                  setSelectedModule(null);
                  setSelectedEssay(null);
                }}
                className="gap-2"
              >
                <Video className="h-4 w-4" />
                <span className="hidden sm:inline">Podcasts</span>
              </Button>
              <Link href="/library">
                <Button variant="outline" size="sm" className="gap-2">
                  <BookOpen className="h-4 w-4" />
                  <span className="hidden sm:inline">Full Library</span>
                </Button>
              </Link>
            </div>
          </div>
        </div>
      </header>

      <BreadcrumbJsonLd items={currentBreadcrumbs} />

      <div className="container mx-auto px-4 py-6">
        <div className="mb-4"><Breadcrumb items={[{ label: "Learn" }]} /></div>
        {/* Essay Reading View */}
        <AnimatePresence>
          {selectedEssay && (
            <EssayReader
              essay={selectedEssay}
              onBack={() => setSelectedEssay(null)}
              isAuthenticated={isAuthenticated}
              onProgressUpdate={() => refetchProgress()}
            />
          )}
        </AnimatePresence>

        {!selectedEssay && (
          <>
            {/* Attention-Grabbing Quote Rotator */}
            {!selectedModule && !showPodcasts && (
              <div className="mb-8">
                <QuoteRotator
                  quotes={modulesData.insightOfTheDay}
                  modules={modulesData.modules}
                />
              </div>
            )}

            {/* Podcast View */}
            {showPodcasts && !selectedModule && (
              <div>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => setShowPodcasts(false)}
                  className="gap-2 mb-4"
                >
                  <ArrowLeft className="h-4 w-4" />
                  All Modules
                </Button>
                <PodcastSection
                  podcasts={modulesData.podcastVideos}
                  modules={modulesData.modules}
                />
              </div>
            )}

            {/* Module Detail View */}
            {selectedModule && !showPodcasts && (
              <ModuleDetail
                module={selectedModule}
                essays={moduleEssays.filter((e) => e.module === selectedModule.id)}
                podcasts={modulePodcasts}
                onBack={() => setSelectedModule(null)}
                onSelectEssay={setSelectedEssay}
                essayProgressMap={essayProgressMap}
              />
            )}

            {/* Continue Reading Section */}
            {!selectedModule && !showPodcasts && isAuthenticated && (
              <ContinueReadingSection
                moduleEssays={moduleEssays}
                onSelectEssay={setSelectedEssay}
                essayProgressMap={essayProgressMap}
              />
            )}

            {/* Module Grid (Home) */}
            {!selectedModule && !showPodcasts && (
              <section>
                <div className="flex items-center justify-between mb-6">
                  <div>
                    <h2 className="text-xl font-editorial font-semibold">Learning Modules</h2>
                    <p className="text-sm text-muted-foreground mt-1">
                      10 modules drawn from the book, Mr. Grumpy's guide, and three podcast
                      interviews
                    </p>
                  </div>
                  <span className="text-xs text-muted-foreground font-mono">
                    {moduleEssays.length} essays · {modulesData.podcastVideos.length} podcasts
                  </span>
                </div>

                <ScrollReveal delay={0.15}>
                <div className="content-stagger grid md:grid-cols-2 lg:grid-cols-3 gap-5">
                  {modulesData.modules.map((mod) => (
                    <ModuleCard
                      key={mod.id}
                      module={mod}
                      essayCount={moduleStats[mod.id]?.essays || 0}
                      podcastCount={moduleStats[mod.id]?.podcasts || 0}
                      completedCount={moduleStats[mod.id]?.completed || 0}
                      totalReadingMinutes={moduleStats[mod.id]?.totalReadingMinutes || 0}
                      onClick={() => setSelectedModule(mod)}
                    />
                  ))}
                </div>
                </ScrollReveal>
              </section>
            )}
          </>
        )}
      </div>
    </div>
    </PageTransition>
  );
}
