import { useGameStore } from '@/store'; import { formatMoney, formatPercent, formatNumber, FUNDING_ROUNDS } from '@ai-tycoon/shared'; import type { FundingRoundType } from '@ai-tycoon/shared'; import { TrendingUp, DollarSign, PiggyBank, BarChart3, Rocket, Check, X as XIcon } from 'lucide-react'; import { AreaChart, Area, XAxis, YAxis, ResponsiveContainer, LineChart, Line, Tooltip } from 'recharts'; import { canRaiseFunding } from '@ai-tycoon/game-engine'; import type { GameState } from '@ai-tycoon/shared'; export function FinancePage() { const money = useGameStore((s) => s.economy.money); const revenuePerTick = useGameStore((s) => s.economy.revenuePerTick); const expensesPerTick = useGameStore((s) => s.economy.expensesPerTick); const funding = useGameStore((s) => s.economy.funding); const history = useGameStore((s) => s.economy.financialHistory); const infrastructure = useGameStore((s) => s.infrastructure); const talent = useGameStore((s) => s.talent); const raiseFunding = useGameStore((s) => s.raiseFunding); const totalRevenue = useGameStore((s) => s.economy.totalRevenue); const subscribers = useGameStore((s) => s.market.consumers.totalSubscribers); const reputationScore = useGameStore((s) => s.reputation.score); const state = useGameStore.getState(); const gameStateForFunding: GameState = { meta: state.meta, economy: state.economy, infrastructure: state.infrastructure, compute: state.compute, research: state.research, models: state.models, market: state.market, competitors: state.competitors, talent: state.talent, data: state.data, reputation: state.reputation, achievements: state.achievements, }; const fundingStatus = canRaiseFunding(gameStateForFunding); const netIncome = revenuePerTick - expensesPerTick; const burnRate = expensesPerTick > revenuePerTick ? expensesPerTick - revenuePerTick : 0; const runway = burnRate > 0 ? money / burnRate : Infinity; let infraCosts = 0; for (const cluster of infrastructure.clusters) { for (const campus of cluster.campuses) { for (const dc of campus.dataCenters) { infraCosts += dc.energyCostPerTick + dc.maintenanceCostPerTick; } } } const talentCosts = talent.totalSalaryPerTick; return (

Finance

= 0 ? 'text-green-400' : 'text-red-400'} />

Cash Over Time

{history.length > 1 ? ( ) : (
Data will appear as time passes
)}

Revenue vs Expenses

Revenue Expenses
{history.length > 1 ? ( [formatMoney(value), name === 'revenue' ? 'Revenue' : 'Expenses']} /> ) : (
Data will appear as time passes
)}

Income Statement (per second)

Revenue {formatMoney(revenuePerTick)}
Infrastructure -{formatMoney(infraCosts)}
Talent -{formatMoney(talentCosts)}
Total Expenses -{formatMoney(expensesPerTick)}
Net Income = 0 ? 'text-success' : 'text-danger'}`}> {formatMoney(netIncome)}

Funding

Founder Equity: {formatPercent(funding.founderEquity)}
Total Raised: {formatMoney(funding.totalRaised)}
{funding.isPublic && ( Public )}
{fundingStatus.nextRound && (() => { const roundConfig = FUNDING_ROUNDS[fundingStatus.nextRound as FundingRoundType]; const reqs = roundConfig.requirements; const checks = [ ...(reqs.minRevenue ? [{ label: `Total Revenue: ${formatMoney(totalRevenue)} / ${formatMoney(reqs.minRevenue)}`, met: totalRevenue >= reqs.minRevenue }] : []), ...(reqs.minUsers ? [{ label: `Subscribers: ${formatNumber(subscribers)} / ${formatNumber(reqs.minUsers)}`, met: subscribers >= reqs.minUsers }] : []), ...(reqs.minReputation ? [{ label: `Reputation: ${reputationScore} / ${reqs.minReputation}`, met: reputationScore >= reqs.minReputation }] : []), ]; return (

{fundingStatus.nextRound === 'ipo' ? 'IPO' : fundingStatus.nextRound.replace('series', 'Series ')}

{fundingStatus.canRaise && ( )}
{checks.length > 0 && (
{checks.map((c, i) => (
{c.met ? : } {c.label}
))}
)}
); })()} {funding.completedRounds.length === 0 ? (

No funding rounds completed yet.

) : (
{funding.completedRounds.map((round, i) => (
{round.type === 'ipo' ? 'IPO' : round.type.replace('series', 'Series ')}
{formatMoney(round.amount)} {formatPercent(round.dilution)} dilution
))}
)}
); } function FinanceCard({ icon: Icon, label, value, color }: { icon: typeof DollarSign; label: string; value: string; color: string; }) { return (
{label}
{value}
); }