/** * Emotion graph component for Smart Montage Planner * Visualizes emotional arc and intensity throughout the montage */ import { Activity, Frown, Heart, Smile, Sparkles, Zap } from "lucide-react" import React from "react" import { useTranslation } from "react-i18next" import { Badge } from "@/components/ui/badge" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { cn } from "@/lib/utils" import type { EmotionalArc, MontagePlan } from "../../types" interface EmotionGraphProps { plan?: MontagePlan emotionalArc?: EmotionalArc[] className?: string } export function EmotionGraph({ plan, emotionalArc, className }: EmotionGraphProps) { const { t } = useTranslation() const getEmotionIcon = (emotion: string) => { const icons: Record = { joy: , excitement: , tension: , sadness: , love: , inspiration: , } return icons[emotion.toLowerCase()] || } const getEmotionColor = (emotion: string) => { const colors: Record = { joy: "text-yellow-600 bg-yellow-100 dark:bg-yellow-900/20", excitement: "text-orange-600 bg-orange-100 dark:bg-orange-900/20", tension: "text-red-600 bg-red-100 dark:bg-red-900/20", sadness: "text-blue-600 bg-blue-100 dark:bg-blue-900/20", love: "text-pink-600 bg-pink-100 dark:bg-pink-900/20", inspiration: "text-purple-600 bg-purple-100 dark:bg-purple-900/20", } return colors[emotion.toLowerCase()] || "text-gray-600 bg-gray-100 dark:bg-gray-900/20" } const getEnergyColor = (energy: number) => { if (energy >= 80) return "text-red-600" if (energy >= 60) return "text-orange-600" if (energy >= 40) return "text-yellow-600" return "text-green-600" } const getEnergyGradient = (energy: number) => { if (energy >= 80) return "from-red-500 to-orange-500" if (energy >= 60) return "from-orange-500 to-yellow-500" if (energy >= 40) return "from-yellow-500 to-green-500" return "from-green-500 to-blue-500" } // Calculate emotional journey const emotionalJourney = emotionalArc?.map((point, index) => { const nextPoint = emotionalArc[index + 1] const currentEnergy = point.peakEnergy ?? point.emotionalIntensity const nextEnergy = nextPoint ? (nextPoint.peakEnergy ?? nextPoint.emotionalIntensity) : currentEnergy const trend = nextPoint ? nextEnergy > currentEnergy ? "rising" : nextEnergy < currentEnergy ? "falling" : "stable" : "stable" // Calculate emotion intensity and dominant emotion const emotionIntensity = point.emotionalWeights ? Math.max(...Object.values(point.emotionalWeights)) : point.emotionalIntensity const dominantEmotion = point.emotionalWeights ? Object.entries(point.emotionalWeights).reduce((a, b) => (a[1] > b[1] ? a : b))[0] : point.category return { ...point, trend, emotionIntensity, dominantEmotion, } }) || [] // Calculate pacing statistics const averageEnergy = emotionalArc ? emotionalArc.reduce((sum, point) => sum + point.emotionalIntensity, 0) / emotionalArc.length : 0 const peakEnergy = emotionalArc ? Math.max(...emotionalArc.map((point) => point.emotionalIntensity)) : 0 const valleyEnergy = emotionalArc ? Math.min(...emotionalArc.map((point) => point.emotionalIntensity)) : 0 const emotionalRange = peakEnergy - valleyEnergy return ( {t("montage-planner.analysis.emotionalArc")} {t("montage-planner.analysis.emotionalArcDescription")} {t("montage-planner.analysis.energyGraph")} {t("montage-planner.emotions.title")} {t("montage-planner.analysis.title")} {/* Energy Graph Tab */} {/* Main Graph */}
{/* Y-axis labels */}
100 75 50 25 0
{/* Graph area */}
{/* Grid lines */}
{[0, 25, 50, 75, 100].map((value) => (
))}
{/* Energy bars */}
{emotionalJourney.map((point, index) => (
{/* Peak energy bar */}
{/* Average energy line */}
{/* Tooltip */}

{t("montage-planner.sequence")} {index + 1}

{t("montage-planner.analysis.peak")}: {point.emotionalIntensity}%

{t("montage-planner.analysis.avg")}: {point.score.toFixed(0)}%

{point.dominantEmotion}

))}
{/* X-axis labels */}
{t("montage-planner.timeline.start")} {t("montage-planner.timeline.middle")} {t("montage-planner.timeline.end")}
{/* Statistics */}

{t("montage-planner.analysis.averageEnergy")}

{averageEnergy.toFixed(0)}%

{t("montage-planner.analysis.peakEnergy")}

{peakEnergy}%

{t("montage-planner.analysis.valleyEnergy")}

{valleyEnergy.toFixed(0)}%

{t("montage-planner.analysis.dynamicRange")}

{emotionalRange.toFixed(0)}%

{/* Emotions Tab */} {/* Emotion Timeline */}

{t("montage-planner.emotions.journey")}

{emotionalJourney.map((point, index) => (
#{index + 1}
{getEmotionIcon(point.dominantEmotion)}
{point.dominantEmotion} {point.emotionIntensity.toFixed(0)}%
{point.trend === "rising" && "↗"} {point.trend === "falling" && "↘"} {point.trend === "stable" && "→"}
))}
{/* Emotion Distribution */}

{t("montage-planner.emotions.distribution")}

{emotionalArc && Object.entries( emotionalArc.reduce>((acc, point) => { // Group by category (using category as emotion type) const emotion = point.category acc[emotion] = (acc[emotion] || 0) + point.emotionalIntensity return acc }, {}), ) .sort((a, b) => b[1] - a[1]) .map(([emotion, totalWeight]) => (
{getEmotionIcon(emotion)}
{emotion} {((totalWeight / emotionalArc.length) * 100).toFixed(0)}%
))}
{/* Analysis Tab */} {/* Arc Type */}

{t("montage-planner.analysis.arcAnalysis")}

{emotionalRange > 50 && (
{t("montage-planner.analysis.highContrast")}

{t("montage-planner.analysis.highContrastDescription")}

)} {emotionalRange <= 50 && emotionalRange > 25 && (
{t("montage-planner.analysis.balanced")}

{t("montage-planner.analysis.balancedDescription")}

)} {emotionalRange <= 25 && (
{t("montage-planner.analysis.steady")}

{t("montage-planner.analysis.steadyDescription")}

)}
{/* Pacing Recommendations */}

{t("montage-planner.analysis.pacingInsights")}

{averageEnergy > 70 && (

{t("montage-planner.analysis.highEnergyDetected")}

{t("montage-planner.analysis.highEnergyAdvice")}

)} {averageEnergy < 40 && (

{t("montage-planner.analysis.lowEnergyDetected")}

{t("montage-planner.analysis.lowEnergyAdvice")}

)} {plan && plan.sequences.some((s) => s.energyLevel > 90) && (

{t("montage-planner.analysis.peakMoments")}

{t("montage-planner.analysis.peakMomentsAdvice")}

)}
) }