import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/widgets/glass_container.dart'; import '../../favorites/cubit/favorites_cubit.dart'; import '../../favorites/models/favorite_asset_model.dart'; import '../models/trade_model.dart'; import 'trade_detail_modal.dart'; class TradeCard extends StatelessWidget { final TradeModel trade; final VoidCallback? onAccept; final VoidCallback? onClose; final VoidCallback? onSettings; const TradeCard({ super.key, required this.trade, this.onAccept, this.onClose, this.onSettings, }); @override Widget build(BuildContext context) { final isBuy = trade.signalType == 'BUY'; final signalColor = isBuy ? AppTheme.primaryEmerald : AppTheme.accentRed; final isProposed = trade.isProposed; final isActive = trade.isActive; final isClosed = trade.isClosed; return BlocBuilder( builder: (context, favState) { double livePrice = 0.0; final keyUpper = (trade.isin.isNotEmpty ? trade.isin : trade.symbol).toUpperCase(); final match = favState.favoriteDetails.firstWhere( (f) => f.isin.toUpperCase() == keyUpper || f.symbol.toUpperCase() == keyUpper, orElse: () => const FavoriteAssetModel(isin: '', symbol: '', name: '', currentPrice: 0.0, change24h: 0.0), ); if (match.currentPrice > 0) { livePrice = match.currentPrice; } final pnlAbs = livePrice > 0 ? trade.calculateLivePnlAbs(livePrice) : trade.calculatedPnlAbs; final pnlPct = livePrice > 0 ? trade.calculateLivePnlPct(livePrice) : trade.calculatedPnlPct; final isPnlPos = pnlAbs >= 0; final pnlColor = isPnlPos ? AppTheme.primaryEmerald : AppTheme.accentRed; final currPrice = livePrice > 0 ? livePrice : trade.effectiveCurrentPrice; return GestureDetector( onTap: () => TradeDetailModal.show( context, trade: trade, onAccept: onAccept, onClose: onClose, ), child: GlassContainer( margin: const EdgeInsets.only(bottom: 14), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row: Signal, Symbol, Status & Live PnL Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: signalColor.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(8), border: Border.all(color: signalColor.withValues(alpha: 0.4)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( isBuy ? Icons.trending_up : Icons.trending_down, size: 14, color: signalColor, ), const SizedBox(width: 4), Text( trade.signalType, style: TextStyle(color: signalColor, fontWeight: FontWeight.bold, fontSize: 12), ), ], ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( trade.companyName.isNotEmpty && trade.companyName != 'UNKNOWN' ? trade.companyName : (trade.symbol.isNotEmpty && trade.symbol != 'UNKNOWN' ? trade.symbol : (trade.isin.isNotEmpty ? trade.isin : 'Aktie')), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white), ), if (trade.isin.isNotEmpty || (trade.symbol.isNotEmpty && trade.symbol != 'UNKNOWN' && trade.symbol != trade.companyName)) Text( trade.isin.isNotEmpty ? trade.isin : trade.symbol, style: TextStyle(color: AppTheme.textMuted, fontSize: 11), overflow: TextOverflow.ellipsis, ), ], ), ), if (isActive || isClosed) Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: pnlColor.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(10), border: Border.all(color: pnlColor.withValues(alpha: 0.3)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( '${isPnlPos ? '+' : ''}${pnlAbs.toStringAsFixed(2)} €', style: TextStyle(color: pnlColor, fontWeight: FontWeight.bold, fontSize: 14), ), Text( '${isPnlPos ? '+' : ''}${pnlPct.toStringAsFixed(2)}%', style: TextStyle(color: pnlColor, fontSize: 11), ), ], ), ) else if (trade.isRejected) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppTheme.accentRed.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(6), border: Border.all(color: AppTheme.accentRed.withValues(alpha: 0.4)), ), child: Text( 'ABGELEHNT', style: TextStyle(color: AppTheme.accentRed, fontWeight: FontWeight.bold, fontSize: 10), ), ) else Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.amber.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(6), border: Border.all(color: Colors.amber.withValues(alpha: 0.4)), ), child: const Text( 'VORSCHLAG', style: TextStyle(color: Colors.amber, fontWeight: FontWeight.bold, fontSize: 10), ), ), ], ), const SizedBox(height: 14), // Price Metrics Grid with Live Kurs Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.white.withValues(alpha: 0.05)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _priceItem( isActive || isClosed ? 'Ausführung' : 'Ziel-Einstieg', trade.actualEntryPrice > 0 ? '${trade.actualEntryPrice.toStringAsFixed(2)} €' : (trade.entryPrice > 0 ? '${trade.entryPrice.toStringAsFixed(2)} €' : '-'), Colors.white ), _priceItem('Live-Kurs', '${currPrice.toStringAsFixed(2)} €', AppTheme.accentCyan), _priceItem('Stop-Loss', '${trade.stopLoss.toStringAsFixed(2)} €', AppTheme.accentRed), _priceItem('Take-Profit', '${trade.takeProfit.toStringAsFixed(2)} €', AppTheme.primaryEmerald), ], ), ), if (trade.reasoning.isNotEmpty) ...[ const SizedBox(height: 10), Text( trade.reasoning, style: TextStyle(color: AppTheme.textMuted, fontSize: 12), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], const SizedBox(height: 12), // Footer Action Row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '${trade.instrumentType.isNotEmpty ? trade.instrumentType : "Stock"}${trade.derivativeIsin.isNotEmpty ? " (${trade.derivativeIsin})" : ""} • ${trade.timeframe.isNotEmpty ? trade.timeframe : "1D"}${trade.leverageUsed > 1 ? " • ${trade.leverageUsed.toStringAsFixed(0)}x Hebel" : ""}', style: TextStyle(color: AppTheme.textMuted, fontSize: 11), ), Row( children: [ IconButton( onPressed: () => TradeDetailModal.show( context, trade: trade, onAccept: onAccept, onClose: onClose, ), icon: Icon(Icons.info_outline, size: 18, color: AppTheme.accentCyan), tooltip: 'KI-Begründung & Details', ), if (isProposed && onAccept != null) ...[ const SizedBox(width: 6), ElevatedButton.icon( onPressed: onAccept, icon: const Icon(Icons.check_circle_outline, size: 16), label: const Text('Trade Übernehmen'), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primaryEmerald, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ), ], if (isActive && onClose != null) ...[ const SizedBox(width: 6), OutlinedButton.icon( onPressed: onClose, icon: Icon(Icons.close, size: 14, color: AppTheme.accentRed), label: Text('Position Schließen', style: TextStyle(color: AppTheme.accentRed, fontSize: 12)), style: OutlinedButton.styleFrom( side: BorderSide(color: AppTheme.accentRed.withValues(alpha: 0.5)), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ), ], if (isActive && onSettings != null) ...[ const SizedBox(width: 6), IconButton( onPressed: onSettings, icon: const Icon(Icons.settings, size: 16, color: Colors.white), tooltip: 'Einstellungen', style: IconButton.styleFrom( backgroundColor: AppTheme.glassSurface, ), ), ], ], ), ], ), ], ), ), ); }, ); } Widget _priceItem(String label, String val, Color valColor) { return Column( children: [ Text(label, style: TextStyle(color: AppTheme.textMuted, fontSize: 10)), const SizedBox(height: 2), Text(val, style: TextStyle(color: valColor, fontWeight: FontWeight.bold, fontSize: 12)), ], ); } }