import 'package:flutter/material.dart'; import '../../../../core/theme/app_theme.dart'; import '../models/trade_model.dart'; class TradeCalculationCard extends StatelessWidget { final TradeModel trade; final bool initiallyExpanded; final bool isCollapsible; const TradeCalculationCard({ super.key, required this.trade, this.initiallyExpanded = true, this.isCollapsible = false, }); String _formatLeverage(double lev) { if (lev <= 0) return '1x'; if (lev == lev.roundToDouble()) { return '${lev.toInt()}x'; } var s = lev.toStringAsFixed(2); if (s.endsWith('0')) { s = s.substring(0, s.length - 1); } return '${s.replaceAll('.', ',')}x'; } @override Widget build(BuildContext context) { final entry = trade.actualEntryPrice > 0 ? trade.actualEntryPrice : (trade.entryPrice > 0 ? trade.entryPrice : 1.0); final posSize = trade.positionSize > 0 ? trade.positionSize : 1000.0; final lev = trade.leverageUsed > 0 ? trade.leverageUsed : 1.0; final isShort = trade.signalType.toUpperCase() == 'SELL' || trade.signalType.toUpperCase() == 'SHORT'; final totalFees = trade.entryFee + (trade.exitFee > 0 ? trade.exitFee : 1.0); final quantity = entry > 0 ? (posSize / entry) : 0.0; // SL Risk final sl = trade.stopLoss; final movePctSL = entry > 0 && sl > 0 ? (isShort ? ((sl - entry) / entry) : ((entry - sl) / entry)) : 0.0; final rawLoss = (movePctSL * posSize * lev).abs(); final isDerivative = trade.instrumentType.toLowerCase().contains('knock') || trade.instrumentType.toLowerCase().contains('option') || trade.instrumentType.toLowerCase().contains('factor') || trade.instrumentType.toLowerCase().contains('turbo'); final cappedLoss = isDerivative ? rawLoss.clamp(0.0, posSize) : rawLoss; final riskAmountAbs = cappedLoss + totalFees; // TP Reward final tp = trade.takeProfit; final movePctTP = entry > 0 && tp > 0 ? (isShort ? ((entry - tp) / entry) : ((tp - entry) / entry)) : 0.0; final rawProfit = (movePctTP * posSize * lev); final profitAfterFees = rawProfit - totalFees; final rewardAmountAbs = profitAfterFees > 0 ? profitAfterFees : 0.0; // CRV final crv = (riskAmountAbs > 0 && rewardAmountAbs > 0) ? (rewardAmountAbs / riskAmountAbs) : 0.0; // Multi-Targets final targets = trade.takeProfitTargets.isNotEmpty ? trade.takeProfitTargets : (trade.takeProfit > 0 ? [trade.takeProfit] : []); final content = Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(14), border: Border.all(color: Colors.white.withValues(alpha: 0.08)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _statTile( 'Stückzahl (Basiswert)', '${quantity.toStringAsFixed(2)} Stk.', Colors.white, ), _statTile( 'Max. Verlust (SL)', '-€${riskAmountAbs.toStringAsFixed(2)}', AppTheme.accentRed, ), _statTile( 'Gewinn-Potenzial (TP)', '+€${rewardAmountAbs.toStringAsFixed(2)}', AppTheme.primaryEmerald, ), _statTile( 'Chance-Risiko (CRV)', crv > 0 ? '1 : ${crv.toStringAsFixed(2)}' : '-', AppTheme.accentCyan, ), ], ), const Divider(color: Colors.white10, height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Pauschalgebühren: €${totalFees.toStringAsFixed(2)} (€${trade.entryFee.toStringAsFixed(2)} Kauf + €${(trade.exitFee > 0 ? trade.exitFee : 1.0).toStringAsFixed(2)} Verkauf)', style: TextStyle(color: AppTheme.textMuted, fontSize: 11), ), if (lev > 1.0) Text( 'Effektiver Hebel: ${_formatLeverage(lev)}', style: TextStyle( color: AppTheme.accentCyan, fontSize: 11, fontWeight: FontWeight.bold, ), ), ], ), if (targets.length > 1) ...[ const Divider(color: Colors.white10, height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '🎯 MEHRSTUFIGE GEWINN-KALKULATION', style: TextStyle( color: AppTheme.primaryEmerald, fontSize: 11, fontWeight: FontWeight.w900, letterSpacing: 0.5, ), ), Text( '${targets.length} Ziele', style: TextStyle(color: AppTheme.textMuted, fontSize: 10), ), ], ), const SizedBox(height: 8), ...targets.asMap().entries.map((entryItem) { final idx = entryItem.key; final targetPrice = entryItem.value; final isCurrent = (tp - targetPrice).abs() < 0.001; final targetMovePct = entry > 0 ? (isShort ? ((entry - targetPrice) / entry) : ((targetPrice - entry) / entry)) : 0.0; final rawTargetProfit = targetMovePct * posSize * lev; final netTargetProfit = rawTargetProfit - totalFees; final cappedNet = netTargetProfit > 0 ? netTargetProfit : 0.0; final retPct = posSize > 0 ? (cappedNet / posSize * 100) : 0.0; final targetCrv = (riskAmountAbs > 0 && cappedNet > 0) ? (cappedNet / riskAmountAbs) : 0.0; final baseMove = (targetMovePct * 100).abs(); return Container( margin: const EdgeInsets.only(bottom: 6), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), decoration: BoxDecoration( color: isCurrent ? AppTheme.primaryEmerald.withValues(alpha: 0.14) : Colors.white.withValues(alpha: 0.03), borderRadius: BorderRadius.circular(8), border: Border.all( color: isCurrent ? AppTheme.primaryEmerald.withValues(alpha: 0.7) : Colors.white.withValues(alpha: 0.07), width: isCurrent ? 1.5 : 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2), decoration: BoxDecoration( color: isCurrent ? AppTheme.primaryEmerald : Colors.white12, borderRadius: BorderRadius.circular(4), ), child: Text( 'TP${idx + 1}', style: TextStyle( color: isCurrent ? Colors.black : Colors.white, fontSize: 10, fontWeight: FontWeight.w900, ), ), ), const SizedBox(width: 8), Text( '€${targetPrice.toStringAsFixed(2)}', style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 6), Text( '(+${baseMove.toStringAsFixed(1)}% Basiswert)', style: TextStyle( color: AppTheme.textMuted, fontSize: 10.5), ), ], ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '+€${cappedNet.toStringAsFixed(2)} (+${retPct.toStringAsFixed(1)}%)', style: TextStyle( color: isCurrent ? AppTheme.primaryEmerald : Colors.white, fontSize: 12, fontWeight: FontWeight.w900, ), ), if (targetCrv > 0) Text( 'CRV 1 : ${targetCrv.toStringAsFixed(2)}', style: TextStyle( color: isCurrent ? AppTheme.primaryEmerald : AppTheme.accentCyan, fontSize: 10, fontWeight: FontWeight.bold, ), ), ], ), ], ), ); }), ], ], ), ); if (!isCollapsible) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '3. LIVE-KALKULATION (AUTOMATISCH)', style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w900, letterSpacing: 0.5, ), ), const SizedBox(height: 8), content, ], ); } return Theme( data: ThemeData(dividerColor: Colors.transparent), child: ExpansionTile( initiallyExpanded: initiallyExpanded, tilePadding: EdgeInsets.zero, childrenPadding: EdgeInsets.zero, dense: true, iconColor: AppTheme.primaryEmerald, collapsedIconColor: Colors.white70, title: Row( children: [ Icon(Icons.calculate_outlined, color: AppTheme.primaryEmerald, size: 16), const SizedBox(width: 8), const Text( 'Live-Kalkulation & Gewinn-Potenzial', style: TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold, ), ), ], ), children: [ content, ], ), ); } Widget _statTile(String label, String value, Color col) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: TextStyle(color: AppTheme.textMuted, fontSize: 10)), const SizedBox(height: 2), Text(value, style: TextStyle( color: col, fontWeight: FontWeight.bold, fontSize: 12.5)), ], ); } }