import React, { useState, useEffect, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Users, User, BarChart2, AlertCircle, PlayCircle, Loader2 } from 'lucide-react';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
const agents = {
macro: { name: 'Macro Economist', role: 'Analyzes broader economic trends, rates, and inflation', icon: , color: 'text-blue-500', bg: 'bg-blue-500/10' },
tech: { name: 'Technical Analyst', role: 'Focuses on momentum, moving averages, and charts', icon: , color: 'text-purple-500', bg: 'bg-purple-500/10' },
skeptic: { name: 'The Skeptic', role: 'Looks for flaws, overvaluation, and risks', icon: , color: 'text-red-500', bg: 'bg-red-500/10' },
system: { name: 'System', role: 'Moderator', icon: , color: 'text-gs-gold', bg: 'bg-gs-gold/10' }
};
const mockDebates = {
'AAPL': [
{ agent: 'macro', text: 'iPhone demand remains steady globally, but services growth is the real story for Apple.' },
{ agent: 'tech', text: 'AAPL is consolidating near its 200-day average. A breakout above current levels would be very bullish.' },
{ agent: 'skeptic', text: 'Regulatory pressure in the EU and US is a massive dark cloud that could hurt margins.' },
{ agent: 'system', text: 'Consensus: Strong ecosystem but legal risks. Conviction Score: 72/100 (Hold).' }
],
'TSLA': [
{ agent: 'macro', text: 'High interest rates are cooling the EV market, forcing aggressive price cuts.' },
{ agent: 'tech', text: 'Tesla is in a clear downtrend. We need to see a higher low before turning bullish.' },
{ agent: 'skeptic', text: 'Elon is distracted and competition from China is fierce. Valuation is still disconnected from reality.' },
{ agent: 'system', text: 'Consensus: High volatility and macro headwinds. Conviction Score: 35/100 (Underweight).' }
],
'NVDA': [
{ agent: 'macro', text: 'The AI infrastructure build-out is a once-in-a-generation shift that favors NVIDIA.' },
{ agent: 'tech', text: 'Parabolic move. It is overextended, but momentum like this can last longer than expected.' },
{ agent: 'skeptic', text: 'At some point, the hyperscalers will stop buying at this rate. The drop will be as fast as the rise.' },
{ agent: 'system', text: 'Consensus: Unrivaled leader in a booming sector. Conviction Score: 88/100 (Overweight).' }
],
'MSFT': [
{ agent: 'macro', text: 'Enterprise software and cloud (Azure) are the backbone of the modern economy.' },
{ agent: 'tech', text: 'Steady uptrend. Microsoft is a "safe haven" in the tech world right now.' },
{ agent: 'skeptic', text: 'The Activision deal is done, but integrating it perfectly won\'t be easy or cheap.' },
{ agent: 'system', text: 'Consensus: Solid growth and AI tailwinds. Conviction Score: 82/100 (Overweight).' }
],
'default': [
{ agent: 'macro', text: 'The macro outlook for [TICKER] is heavily dependent on current sector trends and inflationary pressures affecting production costs.' },
{ agent: 'tech', text: '[TICKER] is currently testing a key resistance level. We need to see sustained volume before confirming a new upward trajectory.' },
{ agent: 'skeptic', text: 'A primary concern for [TICKER] is the potential for margin compression if competitors maintain aggressive pricing strategies.' },
{ agent: 'system', text: 'Consensus: Position is stable for [TICKER], but suggests a cautious stance until quarterly data confirms growth. Conviction Score: 62/100 (Neutral).' }
]
};
export default function InvestmentCommittee({ ticker, isDebating: externalIsDebating, setIsDebating: externalSetIsDebating, inline = false }) {
const [messages, setMessages] = useState([]);
const [convictionScore, setConvictionScore] = useState(null);
const [loading, setLoading] = useState(false);
const [internalIsDebating, setInternalIsDebating] = useState(false);
const scrollRef = useRef(null);
const isDebating = externalIsDebating !== undefined ? externalIsDebating : internalIsDebating;
const setIsDebating = externalSetIsDebating !== undefined ? externalSetIsDebating : setInternalIsDebating;
useEffect(() => {
setMessages([]);
setConvictionScore(null);
setIsDebating(false);
}, [ticker]);
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, [messages]);
const runDebate = async () => {
if (!ticker) return;
setIsDebating(true);
setMessages([]);
setConvictionScore(null);
setLoading(true);
const apiKey = import.meta.env.VITE_GEMINI_API_KEY;
if (apiKey && apiKey.length > 10) {
try {
const llm = new ChatGoogleGenerativeAI({
apiKey: apiKey,
modelName: 'gemini-1.5-flash',
maxOutputTokens: 2048,
});
// Agent 1: Macro
setMessages([{ agent: 'macro', text: `Quantifying macro factors for ${ticker}...` }]);
const macroResponse = await llm.invoke([
new SystemMessage(`You are a top-tier Macro Economist. Analyze the stock ${ticker} with extreme specificity. Mention a specific economic factor like "global logistics", "energy costs", or "labor markets" as it relates to this EXACT company. Provide a 12-month price target. 1 short sentence.`),
new HumanMessage(`What is your unique macro view on ${ticker}?`)
]);
setMessages([{ agent: 'macro', text: macroResponse.content }]);
// Agent 2: Tech
setMessages(prev => [...prev, { agent: 'tech', text: `Evaluating technical metrics for ${ticker}...` }]);
const techResponse = await llm.invoke([
new SystemMessage(`You are a Technical Analyst. Analyze ${ticker}'s price chart. Mention a specific "support zone", "RSI divergence", or "moving average cross" observation for this company. Provide a specific Fair Value. 1 sentence.`),
new HumanMessage(`Provide a non-generic technical view on ${ticker}.`)
]);
setMessages(prev => [prev[0], { agent: 'tech', text: techResponse.content }]);
// Agent 3: Skeptic
setMessages(prev => [...prev, { agent: 'skeptic', text: `Quantifying downside risks for ${ticker}...` }]);
const skepticResponse = await llm.invoke([
new SystemMessage(`You are a Professional Skeptic. Find a "poison pill" for ${ticker}. What is the one specific, non-obvious risk (e.g. patent cliff, specific litigation, supply chain bottleneck) for this stock? 1 sentence.`),
new HumanMessage(`What is the hidden risk in ${ticker}?`)
]);
setMessages(prev => [prev[0], prev[1], { agent: 'skeptic', text: skepticResponse.content }]);
// System consensus
setMessages(prev => [...prev, { agent: 'system', text: 'Synthesizing quantitative consensus...' }]);
const consensusResponse = await llm.invoke([
new SystemMessage("Committee Moderator. Based on the previous data points, output a final Conviction Score (0-100). Format: [SCORE] followed by a 1-sentence quantitative justification."),
new HumanMessage(`Synthesize these quantitative views for ${ticker}: 1. ${macroResponse.content} 2. ${techResponse.content} 3. ${skepticResponse.content}`)
]);
let score = parseInt(consensusResponse.content.replace(/\D/g,''));
if (isNaN(score)) score = 50;
setMessages(prev => [prev[0], prev[1], prev[2], { agent: 'system', text: consensusResponse.content }]);
setConvictionScore(score);
} catch (error) {
console.error("LLM Error:", error);
runMockDebate();
}
} else {
runMockDebate();
}
setLoading(false);
};
const runMockDebate = () => {
const script = mockDebates[ticker] || mockDebates['default'];
const debateScript = script.map(msg => ({
...msg,
text: msg.text.replace(/\[TICKER\]/g, ticker)
}));
let step = 0;
const interval = setInterval(() => {
if (step < debateScript.length) {
const msg = debateScript[step];
if (msg.agent === 'system' && msg.text.includes('Conviction Score')) {
const match = msg.text.match(/(\d+)\/100/);
if (match) setConvictionScore(parseInt(match[1]));
}
setMessages(prev => [...prev, msg]);
step++;
} else {
clearInterval(interval);
setLoading(false);
setIsDebating(false);
}
}, 1200);
};
return (