'use client'

import { useState, useEffect, useMemo, useCallback } from 'react'
import dynamic from 'next/dynamic'
import { useRouter } from 'next/navigation'
import { useLanguage } from '@/lib/i18n'
import { motion, AnimatePresence, useReducedMotion } from 'motion/react'
import {
  Sparkles,
  RefreshCw,
  Layers,
  Trophy,
  Zap,
  Lightbulb,
  Sliders,
  CheckCircle2,
  Clock,
  AlertCircle,
  ChevronRight,
  Database,
  ArrowRight,
  Menu,
  Network,
  List,
} from 'lucide-react'
import { toast } from 'sonner'
import Link from 'next/link'
import { getNoteById } from '@/app/actions/notes'
import type { Note as NoteFull } from '@/lib/types'
import { X, Maximize2 } from 'lucide-react'

const NetworkGraph = dynamic(
  () => import('@/components/network-graph').then(m => ({ default: m.NetworkGraph })),
  {
    loading: () => (
      <div className="w-full h-full flex items-center justify-center">
        <RefreshCw className="animate-spin text-ochre/40" size={32} />
      </div>
    ),
    ssr: false,
  }
)

interface Note {
  id: string
  title: string | null
  content: string
  clusterId?: number
}

interface Cluster {
  id: string
  clusterId: number
  name?: string
  noteIds: string[]
  color?: string
}

interface BridgeNote {
  noteId: string
  bridgeScore: number
  clustersConnected: number[]
  clusterNames?: string[]
  note?: {
    id: string
    title: string | null
    content: string
  }
}

interface BridgeSuggestion {
  clusterAId: number
  clusterBId: number
  clusterAName: string
  clusterBName: string
  suggestedTitle: string
  suggestedContent: string
  justification: string
}

const COLOR_PALETTE = ['#F87171', '#60A5FA', '#34D399', '#FBBF24', '#A78BFA', '#F472B6', '#2DD4BF']

export default function InsightsPage() {
  const router = useRouter()
  const { t, language: locale } = useLanguage()

  const formatSyncTime = useCallback(
    (date: Date) =>
      date.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' }),
    [locale]
  )
  const [notes, setNotes] = useState<Note[]>([])
  const [clusters, setClusters] = useState<Cluster[]>([])
  const [bridgeNotes, setBridgeNotes] = useState<BridgeNote[]>([])
  const [suggestions, setSuggestions] = useState<BridgeSuggestion[]>([])
  const [loading, setLoading] = useState(true)
  const [isCalculating, setIsCalculating] = useState(false)
  const [isReindexing, setIsReindexing] = useState(false)
  const [embeddingStats, setEmbeddingStats] = useState<{ indexed: number; total: number } | null>(null)
  const [isStale, setIsStale] = useState(false)
  const [selectedClusterId, setSelectedClusterId] = useState<string | null>(null)
  const [viewMode, setViewMode] = useState<'graph' | 'dashboard'>('dashboard')
  const [graphMode, setGraphMode] = useState<'visual' | 'list'>('visual')
  const [lastSyncTime, setLastSyncTime] = useState<string>('')
  const [peekNote, setPeekNote] = useState<NoteFull | null>(null)
  const [peekLoading, setPeekLoading] = useState(false)
  const prefersReducedMotion = useReducedMotion()

  useEffect(() => {
    loadInitialData()
  }, [])

  // ─── Données calculées ───────────────────────────────────────────────────────

  const selectedCluster = useMemo(
    () => clusters.find(c => c.id === selectedClusterId) ?? null,
    [clusters, selectedClusterId]
  )

  const selectedClusterNotes = useMemo(
    () => (selectedCluster ? notes.filter(n => selectedCluster.noteIds.includes(n.id)) : []),
    [notes, selectedCluster]
  )

  const isolatedClusters = useMemo(() => {
    const networkedIds = new Set(
      bridgeNotes.flatMap(b => b.clustersConnected.map(cid => String(cid)))
    )
    return clusters.filter(c => !networkedIds.has(c.id))
  }, [clusters, bridgeNotes])

  const bridgeList = useMemo(
    () =>
      bridgeNotes.map(b => ({
        ...b,
        title: b.note?.title || t('insightsView.unknownNote'),
      })),
    [bridgeNotes, t]
  )

  // ─── Chargement initial ──────────────────────────────────────────────────────

  const loadInitialData = async () => {
    setLoading(true)
    try {
      const res = await fetch('/api/clusters')
      if (res.ok) {
        const data = await res.json()

        if (data.clusters?.length > 0) {
          const clustersWithColors = data.clusters.map((c: Cluster, i: number) => ({
            ...c,
            id: c.clusterId.toString(),
            color: COLOR_PALETTE[i % COLOR_PALETTE.length]
          }))
          setNotes(data.notes || [])
          setClusters(clustersWithColors)
          setIsStale(!!data.stale)

          // Bridge notes incluses dans la réponse GET /clusters (enrichies)
          if (data.bridgeNotes?.length > 0) {
            setBridgeNotes(data.bridgeNotes)
          } else {
            const bridgeRes = await fetch('/api/bridge-notes?details=true')
            if (bridgeRes.ok) {
              const bridgeData = await bridgeRes.json()
              setBridgeNotes(bridgeData.bridgeNotes || [])
            }
          }

          const suggestionsRes = await fetch('/api/bridge-notes/suggestions')
          if (suggestionsRes.ok) {
            const suggestionsData = await suggestionsRes.json()
            setSuggestions(suggestionsData.suggestions || [])
          }

          setLastSyncTime(formatSyncTime(new Date()))
          if (typeof data.embeddingCount === 'number' && typeof data.totalNotes === 'number') {
            setEmbeddingStats({ indexed: data.embeddingCount, total: data.totalNotes })
          }
        } else {
          setIsStale(false)
          if (typeof data.embeddingCount === 'number' && typeof data.totalNotes === 'number') {
            setEmbeddingStats({ indexed: data.embeddingCount, total: data.totalNotes })
          }
        }
      }
    } catch (error) {
      console.error('Error loading data:', error)
    } finally {
      setLoading(false)
    }
  }

  const handleReindexEmbeddings = async () => {
    setIsReindexing(true)
    try {
      const res = await fetch('/api/notes/reindex', { method: 'POST' })
      if (!res.ok) throw new Error('reindex failed')
      const data = await res.json()
      setEmbeddingStats(prev => ({
        indexed: data.count ?? prev?.indexed ?? 0,
        total: data.total ?? prev?.total ?? notes.length,
      }))
      setLastSyncTime(formatSyncTime(new Date()))
      setIsStale(true)
    } catch (error) {
      console.error('Error reindexing embeddings:', error)
    } finally {
      setIsReindexing(false)
    }
  }

  // ─── Analyse (POST) ──────────────────────────────────────────────────────────

  const performAnalysis = async () => {
    setIsCalculating(true)
    try {
      const res = await fetch('/api/clusters', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ force: true })
      })

      if (res.ok) {
        const data = await res.json()
        const clusterCount = data.clusters?.length || 0
        if (clusterCount === 0) {
          toast.info(t('insightsView.analysisNoClusters'))
        } else {
          toast.success(t('insightsView.analysisSuccess', { count: clusterCount }))
        }
        const clustersWithColors = (data.clusters || []).map((c: Cluster, i: number) => ({
          ...c,
          id: c.clusterId.toString(),
          color: COLOR_PALETTE[i % COLOR_PALETTE.length]
        }))
        setNotes(data.notes || [])
        setClusters(clustersWithColors)
        setBridgeNotes(data.bridgeNotes || [])
        setIsStale(false)

        const suggestionsRes = await fetch('/api/bridge-notes/suggestions')
        if (suggestionsRes.ok) {
          const suggestionsData = await suggestionsRes.json()
          setSuggestions(suggestionsData.suggestions || [])
        }

        setLastSyncTime(formatSyncTime(new Date()))
        if (data.notes?.length) {
          setEmbeddingStats(prev => ({
            indexed: prev?.indexed ?? data.notes.length,
            total: data.notes.length,
          }))
        }
      }
    } catch (error) {
      console.error('Error running analysis:', error)
      toast.error(t('insightsView.analysisFailed'))
    } finally {
      setIsCalculating(false)
    }
  }

  const handleNoteClick = async (noteId: string) => {
    setPeekLoading(true)
    try {
      const note = await getNoteById(noteId)
      if (note) setPeekNote(note)
    } catch {
      toast.error(t('general.error'))
    } finally {
      setPeekLoading(false)
    }
  }

  const closePeek = () => setPeekNote(null)

  const openPeekFully = () => {
    if (!peekNote) return
    router.push(`/home?openNote=${peekNote.id}`)
    setPeekNote(null)
  }

  const isRtl = locale === 'fa' || locale === 'ar'

  const motionConfig = prefersReducedMotion
    ? { initial: false as const, animate: { opacity: 1, y: 0 }, transition: { duration: 0 } }
    : {}

  // ─── Rendu ───────────────────────────────────────────────────────────────────────────

  return (
    <div className="h-full flex flex-col bg-[#F9F8F6] dark:bg-[#0D0D0D] overflow-hidden">

      {/* ── Header ── */}
      <div className="p-6 sm:p-8 border-b border-border/20 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between sticky top-0 bg-[#F9F8F6]/80 dark:bg-[#0D0D0D]/80 backdrop-blur-md z-30 shrink-0">
        <div className="flex items-center gap-4">
          <button
            className="p-2 -ms-1 text-foreground hover:bg-foreground/5 rounded-lg transition-colors shrink-0 cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
            onClick={() => window.dispatchEvent(new CustomEvent('toggle-insights-sidebar'))}
            aria-label="Toggle sidebar"
          >
            <Menu size={22} />
          </button>
          <div>
          <div className="flex items-center gap-3 mb-1">
            <div className="w-8 h-8 rounded-lg bg-ochre/10 flex items-center justify-center text-ochre">
              <Sparkles size={18} />
            </div>
            <h1 className="text-xl sm:text-2xl font-serif font-medium text-ink dark:text-dark-ink">
              {t('insightsView.title')}
            </h1>
          </div>
          <p className="text-[10px] text-concrete tracking-[0.25em] uppercase font-bold">
            {t('insightsView.subtitle')}
          </p>
          <div className="flex items-center gap-1.5 mt-1.5 text-[10px] text-concrete">
            <span>{t('insightsView.semanticGraphLegend')}</span>
            <Link href="/graph" className="inline-flex items-center gap-0.5 text-ochre hover:underline font-medium">
              {t('insightsView.openGraphMap')} <ArrowRight size={9} />
            </Link>
          </div>
          </div>
        </div>

        <div className="flex items-center justify-between sm:justify-end gap-3">
          {/* Tab switcher mobile */}
          <div className="flex lg:hidden p-1 bg-black/5 dark:bg-white/5 rounded-xl shrink-0">
            <button
              onClick={() => setViewMode('graph')}
              className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider rounded-lg transition-all ${
                viewMode === 'graph'
                  ? 'bg-white dark:bg-black text-ink dark:text-dark-ink shadow-sm'
                  : 'text-concrete'
              }`}
            >
              {t('insightsView.viewGraph')}
            </button>
            <button
              onClick={() => setViewMode('dashboard')}
              className={`px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider rounded-lg transition-all ${
                viewMode === 'dashboard'
                  ? 'bg-white dark:bg-black text-ink dark:text-dark-ink shadow-sm'
                  : 'text-concrete'
              }`}
            >
              {t('insightsView.viewDashboard')}
            </button>
          </div>

          <button
            onClick={performAnalysis}
            disabled={isCalculating}
            className="flex items-center gap-2 px-5 py-2.5 bg-ink text-paper dark:bg-white dark:text-black rounded-full text-xs font-bold uppercase tracking-widest hover:scale-105 active:scale-95 transition-all disabled:opacity-50 shadow-sm"
          >
            {isCalculating ? (
              <RefreshCw size={13} className="animate-spin" />
            ) : (
              <RefreshCw size={13} />
            )}
            {isCalculating ? t('insightsView.mapping') : t('insightsView.resync')}
          </button>
        </div>
      </div>

      {/* ── Chargement ── */}
      {loading && (
        <div className="flex-1 flex items-center justify-center">
          <motion.div
            initial={{ opacity: 0, scale: 0.9 }}
            animate={{ opacity: 1, scale: 1 }}
            className="text-center space-y-4"
          >
            <div className="animate-spin rounded-full h-10 w-10 border-b-2 border-ochre mx-auto" />
            <p className="text-sm text-concrete">{t('insightsView.loading')}</p>
          </motion.div>
        </div>
      )}

      {/* ── État vide ── */}
      {!loading && clusters.length === 0 && !isCalculating && (
        <div className="flex-1 flex items-center justify-center">
          <motion.div
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            className="text-center max-w-sm px-6"
          >
            <div className="w-20 h-20 rounded-2xl bg-ochre/10 flex items-center justify-center mx-auto mb-6">
              <Sparkles size={32} className="text-ochre/60" />
            </div>
            <h3 className="text-xl font-serif font-medium text-ink dark:text-dark-ink mb-3">
              {t('insightsView.emptyTitle')}
            </h3>
            <p className="text-sm text-concrete leading-relaxed mb-6">
              {embeddingStats && embeddingStats.total < 10
                ? t('insightsView.emptyNeedMoreNotes', { count: 10 - embeddingStats.total })
                : t('insightsView.emptyDescription')}
            </p>
            <button
              onClick={performAnalysis}
              disabled={isCalculating}
              className="inline-flex items-center gap-2 px-6 py-3 bg-ink text-paper dark:bg-white dark:text-black rounded-full text-xs font-bold uppercase tracking-widest hover:scale-105 active:scale-95 transition-all disabled:opacity-50"
            >
              <RefreshCw size={14} />
              {t('insightsView.analyzeNow')}
            </button>
          </motion.div>
        </div>
      )}

      {/* ── Calcul en cours ── */}
      {isCalculating && !loading && (
        <div className="flex-1 flex items-center justify-center">
          <motion.div
            initial={{ opacity: 0, scale: 0.9 }}
            animate={{ opacity: 1, scale: 1 }}
            className="text-center space-y-6 max-w-xs"
          >
            <div className="w-16 h-16 rounded-2xl bg-ochre/10 flex items-center justify-center mx-auto">
              <RefreshCw size={28} className="text-ochre animate-spin" />
            </div>
            <div className="space-y-2">
              <p className="text-sm font-semibold text-ink dark:text-dark-ink">
                {t('insightsView.mappingTitle')}
              </p>
              <p className="text-xs text-concrete leading-relaxed">
                {t('insightsView.mappingHint')}
              </p>
            </div>
          </motion.div>
        </div>
      )}

      {/* ── Contenu principal ── */}
      {!loading && clusters.length > 0 && !isCalculating && (
        <div className="flex-1 flex overflow-hidden min-h-0">

          {/* ── Graphe / Liste accessible (gauche) ── */}
          <div
            className={`flex-[1.4] p-6 relative min-h-0 flex flex-col ${
              viewMode === 'graph' ? 'block lg:flex' : 'hidden lg:flex'
            }`}
          >
            {/* Toggle visual/list accessible */}
            <div className="flex items-center gap-1 mb-3 shrink-0">
              <button
                onClick={() => setGraphMode('visual')}
                className={`flex items-center gap-1.5 px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider rounded-lg transition-all cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none ${
                  graphMode === 'visual'
                    ? 'bg-ink text-paper dark:bg-white dark:text-black shadow-sm'
                    : 'text-concrete hover:bg-black/5 dark:hover:bg-white/5'
                }`}
              >
                <Network size={12} /> {t('insightsView.viewGraph')}
              </button>
              <button
                onClick={() => setGraphMode('list')}
                className={`flex items-center gap-1.5 px-3 py-1.5 text-[10px] font-bold uppercase tracking-wider rounded-lg transition-all cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none ${
                  graphMode === 'list'
                    ? 'bg-ink text-paper dark:bg-white dark:text-black shadow-sm'
                    : 'text-concrete hover:bg-black/5 dark:hover:bg-white/5'
                }`}
              >
                <List size={12} /> {t('insightsView.listView') || 'List'}
              </button>
            </div>

            {/* Vue visuelle (D3) */}
            {graphMode === 'visual' && (
              <div
                className="flex-1 min-h-0"
                role="img"
                aria-label={t('insightsView.graphAriaLabel', {
                  clusters: clusters.length,
                  notes: notes.length,
                  bridges: bridgeNotes.length,
                }) || `Semantic network: ${clusters.length} clusters, ${notes.length} notes, ${bridgeNotes.length} bridges`}
              >
                <NetworkGraph
                  notes={notes}
                  clusters={clusters}
                  bridgeNotes={bridgeNotes}
                  onNoteSelect={handleNoteClick}
                  selectedClusterId={selectedClusterId}
                  onClusterSelect={setSelectedClusterId}
                  untitledLabel={t('insightsView.unknownNote')}
                  resetFocusLabel={t('insightsView.resetFocus')}
                  fitViewLabel={t('insightsView.fitGraphView')}
                />
              </div>
            )}

            {/* Vue liste accessible (a11y fallback) */}
            {graphMode === 'list' && (
              <div
                className="flex-1 min-h-0 overflow-y-auto custom-scrollbar space-y-4"
                role="region"
                aria-label={t('insightsView.listAriaLabel') || 'Accessible cluster list'}
              >
                {clusters.map(cluster => {
                  const clusterNotes = notes.filter(n => cluster.noteIds.includes(n.id))
                  const clusterBridges = bridgeNotes.filter(b =>
                    b.clustersConnected?.some(cid => String(cid) === cluster.id)
                  )
                  return (
                    <div
                      key={cluster.id}
                      className="p-4 rounded-xl bg-white dark:bg-zinc-800 border border-border/30"
                    >
                      <div className="flex items-center gap-2 mb-3">
                        <div className="w-2.5 h-2.5 rounded-full shrink-0" style={{ backgroundColor: cluster.color }} />
                        <h3 className="text-xs font-bold uppercase tracking-wider text-ink dark:text-dark-ink">
                          {cluster.name || t('insightsView.clusterFallback', { index: cluster.clusterId })}
                        </h3>
                        <span className="text-[9px] text-concrete ml-auto shrink-0">
                          {clusterNotes.length} {t('insightsView.graphNotesLabel')}
                          {clusterBridges.length > 0 && ` · ${clusterBridges.length} ${t('insightsView.bridgeCount')}`}
                        </span>
                      </div>
                      <ul className="space-y-1">
                        {clusterNotes.map(note => (
                          <li key={note.id}>
                            <button
                              onClick={() => handleNoteClick(note.id)}
                              className="w-full text-left px-2.5 py-1.5 rounded-lg hover:bg-black/5 dark:hover:bg-white/5 text-xs text-ink dark:text-dark-ink flex items-center gap-2 cursor-pointer transition-colors focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
                            >
                              <ChevronRight size={11} className="text-concrete shrink-0" />
                              <span className="truncate">{note.title || t('insightsView.unknownNote')}</span>
                            </button>
                          </li>
                        ))}
                      </ul>
                    </div>
                  )
                })}
              </div>
            )}
          </div>

          {/* ── Dashboard (droite) ── */}
          <div
            className={`flex-1 border-l border-border/20 flex flex-col min-h-0 overflow-hidden bg-[#fcfbfa] dark:bg-zinc-900/10 backdrop-blur-sm ${
              viewMode === 'dashboard' ? 'flex' : 'hidden lg:flex'
            }`}
          >
            <div className="p-6 sm:p-8 flex-1 overflow-y-auto custom-scrollbar space-y-10">

              {/* Avertissement d'obsolescence (stale banner) */}
              {isStale && !isCalculating && (
                <motion.div
                  initial={{ opacity: 0, y: -10 }}
                  animate={{ opacity: 1, y: 0 }}
                  className="p-4 rounded-2xl bg-amber-500/10 border border-amber-500/20 text-amber-800 dark:text-amber-300 text-xs flex items-center justify-between gap-4 shadow-sm"
                >
                  <div className="flex items-center gap-2.5">
                    <AlertCircle size={16} className="shrink-0 text-amber-500" />
                    <span>
                      {t('insightsView.staleResults')}
                    </span>
                  </div>
                  <button
                    onClick={performAnalysis}
                    className="px-3.5 py-2 bg-amber-500 text-white dark:text-zinc-950 font-bold uppercase tracking-wider text-[10px] rounded-lg hover:scale-105 active:scale-95 transition-all shrink-0 shadow-sm"
                  >
                    {t('insightsView.resync')}
                  </button>
                </motion.div>
              )}

              {/* ① Panneau d'inspection cluster */}
              <AnimatePresence>
                {selectedCluster && (
                  <motion.div
                    initial={{ opacity: 0, y: -16 }}
                    animate={{ opacity: 1, y: 0 }}
                    exit={{ opacity: 0, y: -16 }}
                    className="p-6 rounded-2xl bg-white dark:bg-zinc-800 border-2 border-ochre/30 shadow-md relative overflow-hidden"
                  >
                    <div
                      className="absolute top-0 left-0 w-1.5 h-full"
                      style={{ backgroundColor: selectedCluster.color }}
                    />
                    <div className="flex items-center justify-between gap-4 mb-4 pl-3">
                      <div className="space-y-0.5">
                        <span className="text-[9px] font-bold uppercase tracking-widest text-ochre">
                          {t('insightsView.focusCluster.title')}
                        </span>
                        <h3 className="text-base font-serif font-semibold text-ink dark:text-dark-ink">
                          {selectedCluster.name ||
                            t('insightsView.clusterFallback', { index: selectedCluster.clusterId })}
                        </h3>
                      </div>
                      <button
                        onClick={() => setSelectedClusterId(null)}
                        className="p-1 px-3 bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 text-[10px] font-bold rounded-lg uppercase tracking-wider transition-colors shrink-0"
                      >
                        {t('insightsView.focusCluster.close')}
                      </button>
                    </div>
                    <div className="pl-3 space-y-3">
                      <p className="text-xs text-concrete">
                        {t('insightsView.focusCluster.description', {
                          count: selectedClusterNotes.length,
                        })}
                      </p>
                      <div className="space-y-1.5 max-h-[180px] overflow-y-auto custom-scrollbar pr-1">
                        {selectedClusterNotes.map(note => (
                          <button
                            key={note.id}
                            onClick={() => handleNoteClick(note.id)}
                            className="w-full text-left p-2.5 rounded-lg bg-black/[0.03] hover:bg-black/[0.07] dark:bg-white/[0.03] dark:hover:bg-white/[0.07] text-xs font-medium text-ink dark:text-dark-ink flex items-center justify-between gap-3 group transition-all"
                          >
                            <span className="truncate group-hover:translate-x-0.5 transition-transform">
                              {note.title || t('insightsView.unknownNote')}
                            </span>
                            <ChevronRight size={12} className="text-concrete shrink-0" />
                          </button>
                        ))}
                      </div>
                    </div>
                  </motion.div>
                )}
              </AnimatePresence>

              {/* ② Stats */}
              <div className="grid grid-cols-2 gap-4">
                <div className="p-5 rounded-2xl bg-white dark:bg-zinc-800/40 border border-border/40 shadow-sm flex flex-col justify-between">
                  <div className="flex items-center gap-2 text-indigo-500 mb-2">
                    <Layers size={14} />
                    <span className="text-[10px] font-bold uppercase tracking-widest">
                      {t('insightsView.stats.clusters')}
                    </span>
                  </div>
                  <div>
                    <div className="text-2xl font-serif font-semibold text-ink dark:text-dark-ink">
                      {clusters.length}
                    </div>
                    <p className="text-[9px] text-concrete font-medium uppercase mt-1">
                      {t('insightsView.graphNotesLabel')}
                    </p>
                  </div>
                </div>
                <div className="p-5 rounded-2xl bg-white dark:bg-zinc-800/40 border border-border/40 shadow-sm flex flex-col justify-between">
                  <div className="flex items-center gap-2 text-ochre mb-2">
                    <Trophy size={14} />
                    <span className="text-[10px] font-bold uppercase tracking-widest">
                      {t('insightsView.stats.bridgeNotes')}
                    </span>
                  </div>
                  <div>
                    <div className="text-2xl font-serif font-semibold text-ink dark:text-dark-ink">
                      {bridgeNotes.length}
                    </div>
                    <p className="text-[9px] text-concrete font-medium uppercase mt-1">
                      {t('insightsView.bridgeCount')}
                    </p>
                  </div>
                </div>
              </div>

              {/* ③ Système de Recalcul */}
              <section className="p-5 rounded-2xl bg-white dark:bg-zinc-800 border border-border/40 shadow-sm space-y-4">
                <div className="flex items-center justify-between gap-4">
                  <div className="flex items-center gap-2">
                    <Sliders size={15} className="text-ochre" />
                    <h4 className="text-[11px] font-black uppercase tracking-[0.2em] text-ink dark:text-dark-ink">
                      {t('insightsView.recalcSystem.title')}
                    </h4>
                  </div>
                  <span className="flex items-center gap-1 text-[9.5px] font-bold text-emerald-500 uppercase">
                    <CheckCircle2 size={11} /> {t('insightsView.recalcSystem.statusSynced')}
                  </span>
                </div>
                <div className="grid grid-cols-2 gap-4 pt-1">
                  <div className="space-y-1">
                    <span className="text-[9px] text-concrete block">{t('insightsView.recalcSystem.scheduledCron')}</span>
                    <p className="text-xs text-ink dark:text-dark-ink font-semibold flex items-center gap-1.5">
                      <Clock size={12} className="opacity-50" /> 04:00
                    </p>
                  </div>
                  <div className="space-y-1">
                    <span className="text-[9px] text-concrete block">{t('insightsView.recalcSystem.lastSync')}</span>
                    <p className="text-xs text-ink dark:text-dark-ink font-bold font-mono">
                      {lastSyncTime || '—'}
                    </p>
                  </div>
                </div>
                <div className="pt-2 border-t border-border/10 space-y-3">
                  <div className="flex justify-between items-center text-[10px]">
                    <span className="text-concrete">
                      {embeddingStats
                        ? t('insightsView.embeddingsHint', {
                            indexed: embeddingStats.indexed,
                            total: embeddingStats.total,
                          })
                        : '—'}
                    </span>
                    <span className="font-bold font-mono text-ink dark:text-dark-ink shrink-0 ml-3">
                      {embeddingStats
                        ? `${embeddingStats.indexed} / ${embeddingStats.total}`
                        : '—'}
                    </span>
                  </div>
                  <p className="text-[8px] text-concrete italic block leading-relaxed">
                    {t('insightsView.tipClusters')}
                  </p>
                  <button
                    type="button"
                    onClick={() => void handleReindexEmbeddings()}
                    disabled={isReindexing || isCalculating}
                    className="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl border border-ochre/30 bg-ochre/5 hover:bg-ochre/10 text-[10px] font-bold uppercase tracking-widest text-ochre disabled:opacity-50 transition-colors"
                  >
                    {isReindexing ? (
                      <RefreshCw size={13} className="animate-spin" />
                    ) : (
                      <Database size={13} />
                    )}
                    {isReindexing ? t('insightsView.mapping') : t('insightsView.resync')}
                  </button>
                  <span className="text-[8px] text-concrete italic block leading-relaxed">
                    {t('insightsView.tipClustersAction')}
                  </span>
                </div>
              </section>

              {/* ④ Clusters Isolés */}
              <section className="space-y-4">
                <div className="flex items-center justify-between gap-4 px-1">
                  <div className="flex items-center gap-2">
                    <AlertCircle size={15} className="text-rose-400" />
                    <h3 className="text-xs font-bold uppercase tracking-[0.2em] text-ink dark:text-dark-ink">
                      {t('insightsView.isolatedClusters.title', { count: isolatedClusters.length })}
                    </h3>
                  </div>
                  <span className="text-[9px] text-concrete italic">{t('insightsView.tipIsolatedAction')}</span>
                </div>
                <div className="space-y-2">
                  {isolatedClusters.map(c => (
                    <motion.div
                      key={c.id}
                      whileHover={prefersReducedMotion ? undefined : { y: -1 }}
                      onClick={() => setSelectedClusterId(c.id)}
                      className="p-3.5 rounded-xl bg-white dark:bg-zinc-800 border border-border/30 hover:border-black/10 dark:hover:border-white/10 flex items-center justify-between cursor-pointer transition-all focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
                    >
                      <div className="flex items-center gap-2.5">
                        <div className="w-2 h-2 rounded-full" style={{ backgroundColor: c.color }} />
                        <span className="text-xs font-medium text-ink dark:text-dark-ink">
                          {c.name || t('insightsView.clusterFallback', { index: c.clusterId })}
                        </span>
                      </div>
                      <span className="text-[10px] text-rose-500 font-semibold uppercase tracking-wider bg-rose-500/5 px-2.5 py-0.5 rounded-full border border-rose-500/10">
                        {t('insightsView.isolatedClusters.badge')}
                      </span>
                    </motion.div>
                  ))}
                  {isolatedClusters.length === 0 && (
                    <div className="p-4 bg-white dark:bg-zinc-800 rounded-xl text-xs text-concrete text-center italic border border-border/20">
                      {t('insightsView.isolatedClusters.empty')}
                    </div>
                  )}
                </div>
              </section>

              {/* ⑤ Notes-Ponts Influentes */}
              <section className="space-y-4">
                <div className="flex items-center gap-2 px-1">
                  <Zap size={16} className="text-ochre" />
                  <h3 className="text-xs font-bold uppercase tracking-[0.2em] text-ink dark:text-dark-ink">
                    {t('insightsView.bridgeNotes.title')}
                  </h3>
                </div>
                <p className="text-[10px] text-concrete italic px-1 -mt-2 leading-relaxed">{t('insightsView.tipBridgeNotes')}</p>
                <div className="space-y-3">
                  {bridgeList.map(bridge => (
                    <motion.div
                      key={bridge.noteId}
                      whileHover={prefersReducedMotion ? undefined : { x: 4 }}
                      onClick={() => handleNoteClick(bridge.noteId)}
                      className="p-4 rounded-xl bg-white dark:bg-zinc-800 border border-border/30 hover:border-ochre/40 hover:shadow-sm transition-all cursor-pointer group focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
                      tabIndex={0}
                      role="button"
                      onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleNoteClick(bridge.noteId) } }}
                    >
                      <div className="flex items-center justify-between mb-2 gap-4">
                        <h4 className="text-xs font-semibold text-ink dark:text-dark-ink truncate flex-1 group-hover:text-ochre transition-colors">
                          {bridge.title}
                        </h4>
                        <span className="text-[9.5px] font-bold text-ochre bg-ochre/5 border border-ochre/10 px-2.5 py-0.5 rounded-full shrink-0">
                          {t('insightsView.bridgeNotes.score', {
                            score: (bridge.bridgeScore * 100).toFixed(0),
                          })}
                        </span>
                      </div>
                      <div className="flex flex-wrap gap-1.5 pt-1.5 border-t border-black/5 dark:border-white/5">
                        {bridge.clustersConnected.map(cid => {
                          const cluster = clusters.find(c => c.id === String(cid))
                          return (
                            <div
                              key={cid}
                              onClick={e => {
                                e.stopPropagation()
                                setSelectedClusterId(String(cid))
                              }}
                              className="flex items-center gap-1.5 px-2 py-0.5 bg-black/[0.02] dark:bg-white/[0.02] border border-border/30 rounded-md hover:border-concrete/40 transition-colors cursor-pointer"
                            >
                              <div
                                className="w-1.5 h-1.5 rounded-full"
                                style={{ backgroundColor: cluster?.color || '#cbd5e1' }}
                              />
                              <span className="text-[9.5px] text-concrete font-medium uppercase tracking-wider">
                                {cluster?.name || t('insightsView.clusterFallback', { index: cid })}
                              </span>
                            </div>
                          )
                        })}
                      </div>
                    </motion.div>
                  ))}
                  {bridgeList.length === 0 && !isCalculating && (
                    <div className="text-xs text-concrete italic text-center p-6 bg-white dark:bg-zinc-800 rounded-xl border border-border/20">
                      {t('insightsView.bridgeNotes.empty')}
                    </div>
                  )}
                </div>
              </section>

              {/* ⑥ Opportunités de Connexion */}
              <section className="space-y-4">
                <div className="flex items-center gap-2 px-1">
                  <Lightbulb size={16} className="text-indigo-500" />
                  <h3 className="text-xs font-bold uppercase tracking-[0.2em] text-ink dark:text-dark-ink">
                    {t('insightsView.suggestions.title')}
                  </h3>
                </div>
                <p className="text-[10px] text-concrete italic px-1 -mt-2 leading-relaxed">{t('insightsView.tipSuggestions')}</p>
                <div className="space-y-4">
                  {suggestions.map(s => (
                    <div
                      key={`${s.clusterAId}-${s.clusterBId}`}
                      className="p-6 rounded-2xl bg-gradient-to-br from-indigo-500/5 via-transparent to-transparent border border-indigo-500/10 hover:border-indigo-500/20 transition-all shadow-sm"
                    >
                      <div className="flex items-center gap-3 mb-4">
                        <div className="flex -space-x-2 shrink-0">
                          <div className="w-5 h-5 rounded-full border-2 border-paper bg-indigo-500 flex items-center justify-center text-[9px] text-white font-bold">
                            A
                          </div>
                          <div className="w-5 h-5 rounded-full border-2 border-paper bg-ochre flex items-center justify-center text-[9px] text-white font-bold">
                            B
                          </div>
                        </div>
                        <span className="text-[9px] font-bold uppercase tracking-wider text-indigo-500/70 truncate">
                          {t('insightsView.suggestions.bridging', {
                            clusterA: s.clusterAName,
                            clusterB: s.clusterBName,
                          })}
                        </span>
                      </div>
                      <h4 className="text-sm font-semibold text-ink dark:text-dark-ink mb-2">
                        {s.suggestedTitle}
                      </h4>
                      <p className="text-xs text-muted-ink leading-relaxed mb-4">
                        {s.suggestedContent}
                      </p>
                      <div className="p-3.5 bg-white/60 dark:bg-zinc-800 rounded-xl border border-border/20 text-[10.5px] italic text-concrete flex gap-2">
                        <Zap size={13} className="shrink-0 text-ochre mt-0.5" />
                        <span>{s.justification}</span>
                      </div>
                    </div>
                  ))}
                  {isCalculating && (
                    <div className="animate-pulse space-y-4">
                      {[1, 2].map(i => (
                        <div
                          key={i}
                          className="h-32 bg-indigo-500/5 rounded-2xl border border-indigo-500/10"
                        />
                      ))}
                    </div>
                  )}
                  {!isCalculating && suggestions.length === 0 && (
                    <div className="text-xs text-concrete text-center italic p-6 border border-border/20 bg-white/40 dark:bg-zinc-800 rounded-xl">
                      {t('insightsView.suggestions.emptyDescription')}
                    </div>
                  )}
                </div>
              </section>

            </div>
          </div>
        </div>
      )}

      {/* ── Peek panel (slide from right) ── */}
      <AnimatePresence>
        {peekNote && (
          <motion.aside
            key="insights-peek"
            initial={{ x: isRtl ? '-100%' : '100%', opacity: 0 }}
            animate={{ x: 0, opacity: 1 }}
            exit={{ x: isRtl ? '-100%' : '100%', opacity: 0 }}
            transition={prefersReducedMotion ? { duration: 0 } : { type: 'spring', stiffness: 340, damping: 34 }}
            className={`fixed top-0 ${isRtl ? 'left-0' : 'right-0'} z-[80] h-full w-full sm:w-[min(50vw,640px)] bg-[#fafaf9] dark:bg-zinc-950 flex flex-col overflow-hidden shadow-2xl ${isRtl ? 'border-r' : 'border-l'} border-black/10 dark:border-white/10`}
          >
            {/* Peek header */}
            <div className="shrink-0 px-5 py-3 flex items-center justify-between gap-3 border-b border-black/[0.06] dark:border-white/[0.06] bg-white/80 dark:bg-zinc-900/80 backdrop-blur-sm">
              <span className="text-[10px] font-bold uppercase tracking-[0.2em] text-concrete truncate">
                {peekLoading ? t('insightsView.loading') : (peekNote.title || t('insightsView.unknownNote'))}
              </span>
              <div className="flex items-center gap-1 shrink-0">
                <button
                  onClick={openPeekFully}
                  className="inline-flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-[10px] font-bold uppercase tracking-wide text-blue-600 dark:text-blue-400 hover:bg-blue-500/10 transition-colors cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
                >
                  <Maximize2 size={12} />
                </button>
                <button
                  onClick={closePeek}
                  className="p-1.5 rounded-lg text-concrete hover:text-ink dark:hover:text-dark-ink hover:bg-black/5 dark:hover:bg-white/5 transition-colors cursor-pointer focus-visible:ring-2 focus-visible:ring-ochre/50 focus-visible:outline-none"
                  aria-label="Close"
                >
                  <X size={16} />
                </button>
              </div>
            </div>

            {/* Peek content */}
            <div className="flex-1 min-h-0 overflow-y-auto custom-scrollbar">
              <div className="max-w-2xl mx-auto w-full px-6 sm:px-8 py-8 pb-24">
                <h2 className="text-xl font-serif font-medium text-ink dark:text-dark-ink mb-6">
                  {peekNote.title || t('insightsView.unknownNote')}
                </h2>
                {peekNote.content ? (
                  <div
                    dir="auto"
                    className="prose prose-sm dark:prose-invert max-w-none text-ink dark:text-dark-ink [&_a]:text-blue-600 [&_blockquote]:border-l-blue-400"
                    dangerouslySetInnerHTML={{ __html: peekNote.content }}
                  />
                ) : (
                  <p className="text-sm text-concrete italic">—</p>
                )}
              </div>
            </div>
          </motion.aside>
        )}
      </AnimatePresence>

    </div>
  )
}
