"""
Report Generator Module
Main class for generating various types of trading reports
"""

import threading
import json
import csv
import io
from datetime import datetime, timedelta
from typing import List, Optional, Dict, Any, Callable

from hyperliquid_monitor_plus.reports.types import (
    ReportConfig,
    ReportFormat,
    ReportType,
    ReportPeriod,
    ReportData,
    GeneratedReport,
    TableData,
    SectionData
)
from hyperliquid_monitor_plus.pnl.types import PortfolioPnL, PnLRecord
from hyperliquid_monitor_plus.positions.types import PositionSnapshot, LivePosition
from hyperliquid_monitor_plus.strategy.types import StrategyMetrics, StrategyRecommendation
from hyperliquid_monitor_plus.alerts.types import Alert


class ReportGenerator:
    """
    Generates comprehensive trading reports in various formats
    
    Features:
    - Multiple output formats (HTML, Markdown, JSON, CSV, Text)
    - Various report types (PnL, Positions, Strategy, Alerts)
    - Customizable templates and sections
    - Chart generation support
    - Period-based filtering
    
    Thread-safe implementation using RLock
    """
    
    def __init__(
        self,
        report_callback: Optional[Callable[[GeneratedReport], None]] = None
    ):
        """
        Initialize Report Generator
        
        Args:
            report_callback: Optional callback when report is generated
        """
        self._report_callback = report_callback
        self._lock = threading.RLock()
        
        # Data storage
        self._pnl_records: List[PnLRecord] = []
        self._positions: List[LivePosition] = []
        self._alerts: List[Alert] = []
        self._portfolio: Optional[PortfolioPnL] = None
        self._strategy_metrics: Optional[StrategyMetrics] = None
        self._position_snapshot: Optional[PositionSnapshot] = None
    
    def set_portfolio_data(self, portfolio: PortfolioPnL) -> None:
        """Set portfolio PnL data"""
        with self._lock:
            self._portfolio = portfolio
            # Extract PnL records
            self._pnl_records.clear()
            for coin_pnl in portfolio.coin_pnls.values():
                self._pnl_records.extend(coin_pnl.pnl_history)
    
    def set_position_data(self, snapshot: PositionSnapshot) -> None:
        """Set position snapshot data"""
        with self._lock:
            self._position_snapshot = snapshot
            self._positions = list(snapshot.positions.values())
    
    def set_strategy_data(self, metrics: StrategyMetrics) -> None:
        """Set strategy metrics data"""
        with self._lock:
            self._strategy_metrics = metrics
    
    def set_alerts(self, alerts: List[Alert]) -> None:
        """Set alert history"""
        with self._lock:
            self._alerts = list(alerts)
    
    def add_pnl_record(self, record: PnLRecord) -> None:
        """Add a PnL record"""
        with self._lock:
            self._pnl_records.append(record)
    
    def clear_data(self) -> None:
        """Clear all stored data"""
        with self._lock:
            self._pnl_records.clear()
            self._positions.clear()
            self._alerts.clear()
            self._portfolio = None
            self._strategy_metrics = None
            self._position_snapshot = None
    
    def generate(self, config: ReportConfig) -> GeneratedReport:
        """
        Generate a report based on configuration
        
        Args:
            config: Report configuration
            
        Returns:
            GeneratedReport with content
        """
        with self._lock:
            report = GeneratedReport(
                config=config,
                generated_at=datetime.now()
            )
            
            try:
                # Prepare report data
                data = self._prepare_data(config)
                
                # Set period
                report.data_period_start = data.metadata.get("period_start")
                report.data_period_end = data.metadata.get("period_end")
                
                # Generate content based on format
                if config.format == ReportFormat.HTML:
                    report.content = self._generate_html(config, data)
                elif config.format == ReportFormat.MARKDOWN:
                    report.content = self._generate_markdown(config, data)
                elif config.format == ReportFormat.JSON:
                    report.content = self._generate_json(config, data)
                elif config.format == ReportFormat.CSV:
                    report.content = self._generate_csv(config, data)
                else:  # TEXT
                    report.content = self._generate_text(config, data)
                
                # Callback if set
                if self._report_callback:
                    self._report_callback(report)
                
            except Exception as e:
                report.error = str(e)
            
            return report
    
    def _prepare_data(self, config: ReportConfig) -> ReportData:
        """Prepare report data based on configuration"""
        data = ReportData()
        
        # Calculate period
        end_date = datetime.now()
        start_date = self._calculate_start_date(config.period, end_date)
        
        if config.period == ReportPeriod.CUSTOM:
            start_date = config.custom_start_date
            end_date = config.custom_end_date
        
        data.metadata["period_start"] = start_date
        data.metadata["period_end"] = end_date
        
        # Filter records by period
        filtered_records = [
            r for r in self._pnl_records
            if start_date <= r.timestamp <= end_date
        ]
        
        # Prepare PnL summary
        if self._portfolio or filtered_records:
            data.pnl_summary = self._prepare_pnl_summary(filtered_records)
            data.equity_curve = [sum(r.pnl for r in filtered_records[:i+1]) 
                                 for i in range(len(filtered_records))]
            data.performance_by_coin = self._calculate_coin_performance(filtered_records)
        
        # Prepare positions
        if self._positions:
            data.positions = [self._position_to_dict(p) for p in self._positions]
        
        # Prepare strategy metrics
        if self._strategy_metrics:
            data.strategy_metrics = self._metrics_to_dict(self._strategy_metrics)
            if self._strategy_metrics.identified_patterns:
                data.recommendations = [
                    {"type": p.pattern_type.value, "confidence": p.confidence, 
                     "description": p.description}
                    for p in self._strategy_metrics.identified_patterns
                ]
        
        # Prepare alerts
        if self._alerts:
            filtered_alerts = [
                a for a in self._alerts
                if start_date <= a.triggered_at <= end_date
            ]
            data.alerts = [self._alert_to_dict(a) for a in filtered_alerts]
        
        # Prepare trades
        if filtered_records:
            data.trades = [self._record_to_dict(r) for r in filtered_records]
        
        # Calculate statistics
        data.statistics = self._calculate_statistics(filtered_records)
        
        return data
    
    def _calculate_start_date(self, period: ReportPeriod, end_date: datetime) -> datetime:
        """Calculate start date based on period"""
        if period == ReportPeriod.TODAY:
            return end_date.replace(hour=0, minute=0, second=0, microsecond=0)
        elif period == ReportPeriod.YESTERDAY:
            yesterday = end_date - timedelta(days=1)
            return yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
        elif period == ReportPeriod.LAST_7_DAYS:
            return end_date - timedelta(days=7)
        elif period == ReportPeriod.LAST_30_DAYS:
            return end_date - timedelta(days=30)
        elif period == ReportPeriod.LAST_90_DAYS:
            return end_date - timedelta(days=90)
        elif period == ReportPeriod.THIS_WEEK:
            days_since_monday = end_date.weekday()
            return (end_date - timedelta(days=days_since_monday)).replace(
                hour=0, minute=0, second=0, microsecond=0
            )
        elif period == ReportPeriod.THIS_MONTH:
            return end_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        elif period == ReportPeriod.THIS_YEAR:
            return end_date.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
        else:  # ALL_TIME
            return datetime.min
    
    def _prepare_pnl_summary(self, records: List[PnLRecord]) -> Dict[str, Any]:
        """Prepare PnL summary from records"""
        if not records:
            return {
                "total_pnl": 0,
                "total_trades": 0,
                "winning_trades": 0,
                "losing_trades": 0,
                "win_rate": 0,
                "gross_profit": 0,
                "gross_loss": 0
            }
        
        gross_profit = sum(r.pnl for r in records if r.pnl > 0)
        gross_loss = abs(sum(r.pnl for r in records if r.pnl < 0))
        winning = sum(1 for r in records if r.pnl > 0)
        losing = sum(1 for r in records if r.pnl < 0)
        
        return {
            "total_pnl": gross_profit - gross_loss,
            "total_trades": len(records),
            "winning_trades": winning,
            "losing_trades": losing,
            "win_rate": (winning / (winning + losing) * 100) if (winning + losing) > 0 else 0,
            "gross_profit": gross_profit,
            "gross_loss": gross_loss,
            "avg_win": gross_profit / winning if winning > 0 else 0,
            "avg_loss": gross_loss / losing if losing > 0 else 0,
            "profit_factor": gross_profit / gross_loss if gross_loss > 0 else float('inf')
        }
    
    def _calculate_coin_performance(self, records: List[PnLRecord]) -> Dict[str, float]:
        """Calculate performance by coin"""
        performance = {}
        for record in records:
            if record.coin not in performance:
                performance[record.coin] = 0
            performance[record.coin] += record.pnl
        return performance
    
    def _calculate_statistics(self, records: List[PnLRecord]) -> Dict[str, Any]:
        """Calculate general statistics"""
        if not records:
            return {"trade_count": 0}
        
        pnls = [r.pnl for r in records]
        return {
            "trade_count": len(records),
            "total_pnl": sum(pnls),
            "avg_pnl": sum(pnls) / len(pnls),
            "max_pnl": max(pnls),
            "min_pnl": min(pnls),
            "total_fees": sum(r.fee for r in records)
        }
    
    def _position_to_dict(self, position: LivePosition) -> Dict[str, Any]:
        """Convert LivePosition to dictionary"""
        return {
            "coin": position.coin,
            "side": position.side,
            "size": position.size,
            "entry_price": position.entry_price,
            "mark_price": position.mark_price,
            "liquidation_price": position.liquidation_price,
            "unrealized_pnl": position.unrealized_pnl,
            "leverage": position.leverage,
            "notional_value": position.notional_value,
            "pnl_percentage": position.pnl_percentage
        }
    
    def _metrics_to_dict(self, metrics: StrategyMetrics) -> Dict[str, Any]:
        """Convert StrategyMetrics to dictionary"""
        return {
            "strategy_name": metrics.strategy_name,
            "total_trades": metrics.total_trades,
            "winning_trades": metrics.winning_trades,
            "losing_trades": metrics.losing_trades,
            "win_rate": metrics.win_rate,
            "profit_factor": metrics.profit_factor,
            "risk_reward_ratio": metrics.risk_reward_ratio,
            "net_profit": metrics.net_profit,
            "max_drawdown": metrics.max_drawdown,
            "sharpe_ratio": metrics.sharpe_ratio,
            "grade": metrics.get_grade()
        }
    
    def _alert_to_dict(self, alert: Alert) -> Dict[str, Any]:
        """Convert Alert to dictionary"""
        return {
            "level": alert.level.value,
            "type": alert.alert_type.value,
            "message": alert.message,
            "triggered_at": alert.triggered_at.isoformat(),
            "coin": alert.trade.coin if alert.trade else None,
            "value": alert.trade.size * alert.trade.price if alert.trade else None
        }
    
    def _record_to_dict(self, record: PnLRecord) -> Dict[str, Any]:
        """Convert PnLRecord to dictionary"""
        return {
            "timestamp": record.timestamp.isoformat(),
            "coin": record.coin,
            "pnl": record.pnl,
            "side": record.trade_side,
            "entry_price": record.entry_price,
            "exit_price": record.exit_price,
            "size": record.size,
            "fee": record.fee
        }
    
    # =========================================================================
    # HTML Generation
    # =========================================================================
    
    def _generate_html(self, config: ReportConfig, data: ReportData) -> str:
        """Generate HTML report"""
        theme_bg = "#ffffff" if config.theme == "light" else "#1a1a2e"
        theme_text = "#333333" if config.theme == "light" else "#e0e0e0"
        theme_card = "#f5f5f5" if config.theme == "light" else "#16213e"
        
        html = f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{config.title}</title>
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: {theme_bg};
            color: {theme_text};
        }}
        .container {{
            max-width: 1200px;
            margin: 0 auto;
        }}
        .header {{
            text-align: center;
            margin-bottom: 30px;
            padding: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 10px;
        }}
        .header h1 {{
            margin: 0;
            font-size: 2.5em;
        }}
        .header p {{
            margin: 10px 0 0;
            opacity: 0.9;
        }}
        .card {{
            background: {theme_card};
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        .card h2 {{
            margin-top: 0;
            color: #667eea;
        }}
        .metrics-grid {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }}
        .metric {{
            background: {theme_bg};
            padding: 15px;
            border-radius: 8px;
            text-align: center;
        }}
        .metric-value {{
            font-size: 1.8em;
            font-weight: bold;
            color: #667eea;
        }}
        .metric-label {{
            font-size: 0.9em;
            opacity: 0.7;
            margin-top: 5px;
        }}
        .positive {{ color: #4CAF50; }}
        .negative {{ color: #F44336; }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
        }}
        th, td {{
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid rgba(0,0,0,0.1);
        }}
        th {{
            background: rgba(102, 126, 234, 0.1);
            font-weight: 600;
        }}
        .footer {{
            text-align: center;
            padding: 20px;
            opacity: 0.7;
            font-size: 0.9em;
        }}
        .chart-container {{
            height: 300px;
            background: {theme_bg};
            border-radius: 8px;
            padding: 15px;
            margin: 15px 0;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>{config.title}</h1>
            {f'<p>{config.subtitle}</p>' if config.subtitle else ''}
            <p>Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
        </div>
"""
        
        # Add sections based on report type and available data
        if data.has_pnl_data:
            html += self._generate_html_pnl_section(data)
        
        if data.has_strategy_data:
            html += self._generate_html_strategy_section(data)
        
        if data.has_position_data:
            html += self._generate_html_positions_section(data)
        
        if data.has_trade_data and config.include_raw_data:
            html += self._generate_html_trades_section(data)
        
        if data.has_alert_data:
            html += self._generate_html_alerts_section(data)
        
        # Footer
        html += f"""
        <div class="footer">
            <p>Report generated by {config.author}</p>
            <p>Hyperliquid Monitor Plus</p>
        </div>
    </div>
</body>
</html>"""
        
        return html
    
    def _generate_html_pnl_section(self, data: ReportData) -> str:
        """Generate HTML PnL section"""
        pnl = data.pnl_summary
        pnl_class = "positive" if pnl["total_pnl"] >= 0 else "negative"
        
        return f"""
        <div class="card">
            <h2>PnL Summary</h2>
            <div class="metrics-grid">
                <div class="metric">
                    <div class="metric-value {pnl_class}">${pnl['total_pnl']:,.2f}</div>
                    <div class="metric-label">Total PnL</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{pnl['total_trades']}</div>
                    <div class="metric-label">Total Trades</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{pnl['win_rate']:.1f}%</div>
                    <div class="metric-label">Win Rate</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{pnl.get('profit_factor', 0):.2f}</div>
                    <div class="metric-label">Profit Factor</div>
                </div>
                <div class="metric">
                    <div class="metric-value positive">${pnl['gross_profit']:,.2f}</div>
                    <div class="metric-label">Gross Profit</div>
                </div>
                <div class="metric">
                    <div class="metric-value negative">${pnl['gross_loss']:,.2f}</div>
                    <div class="metric-label">Gross Loss</div>
                </div>
            </div>
        </div>
"""
    
    def _generate_html_strategy_section(self, data: ReportData) -> str:
        """Generate HTML strategy section"""
        metrics = data.strategy_metrics
        return f"""
        <div class="card">
            <h2>Strategy Analysis</h2>
            <div class="metrics-grid">
                <div class="metric">
                    <div class="metric-value">{metrics['grade']}</div>
                    <div class="metric-label">Strategy Grade</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{metrics['win_rate']:.1f}%</div>
                    <div class="metric-label">Win Rate</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{metrics['risk_reward_ratio']:.2f}</div>
                    <div class="metric-label">Risk/Reward</div>
                </div>
                <div class="metric">
                    <div class="metric-value">{metrics['sharpe_ratio']:.2f}</div>
                    <div class="metric-label">Sharpe Ratio</div>
                </div>
            </div>
        </div>
"""
    
    def _generate_html_positions_section(self, data: ReportData) -> str:
        """Generate HTML positions section"""
        html = """
        <div class="card">
            <h2>Open Positions</h2>
            <table>
                <thead>
                    <tr>
                        <th>Coin</th>
                        <th>Side</th>
                        <th>Size</th>
                        <th>Entry</th>
                        <th>Mark</th>
                        <th>PnL</th>
                        <th>PnL %</th>
                    </tr>
                </thead>
                <tbody>
"""
        
        for pos in data.positions:
            pnl_class = "positive" if pos["unrealized_pnl"] >= 0 else "negative"
            html += f"""
                    <tr>
                        <td>{pos['coin']}</td>
                        <td>{pos['side']}</td>
                        <td>{pos['size']:.4f}</td>
                        <td>${pos['entry_price']:,.2f}</td>
                        <td>${pos['mark_price']:,.2f}</td>
                        <td class="{pnl_class}">${pos['unrealized_pnl']:,.2f}</td>
                        <td class="{pnl_class}">{pos['pnl_percentage']:.2f}%</td>
                    </tr>
"""
        
        html += """
                </tbody>
            </table>
        </div>
"""
        return html
    
    def _generate_html_trades_section(self, data: ReportData) -> str:
        """Generate HTML trades section"""
        html = """
        <div class="card">
            <h2>Trade History</h2>
            <table>
                <thead>
                    <tr>
                        <th>Time</th>
                        <th>Coin</th>
                        <th>Side</th>
                        <th>Size</th>
                        <th>Entry</th>
                        <th>Exit</th>
                        <th>PnL</th>
                    </tr>
                </thead>
                <tbody>
"""
        
        for trade in data.trades[-50:]:  # Last 50 trades
            pnl_class = "positive" if trade["pnl"] >= 0 else "negative"
            html += f"""
                    <tr>
                        <td>{trade['timestamp'][:19]}</td>
                        <td>{trade['coin']}</td>
                        <td>{trade['side']}</td>
                        <td>{trade['size']:.4f}</td>
                        <td>${trade['entry_price']:,.2f}</td>
                        <td>${trade['exit_price']:,.2f}</td>
                        <td class="{pnl_class}">${trade['pnl']:,.2f}</td>
                    </tr>
"""
        
        html += """
                </tbody>
            </table>
        </div>
"""
        return html
    
    def _generate_html_alerts_section(self, data: ReportData) -> str:
        """Generate HTML alerts section"""
        html = """
        <div class="card">
            <h2>Recent Alerts</h2>
            <table>
                <thead>
                    <tr>
                        <th>Time</th>
                        <th>Level</th>
                        <th>Type</th>
                        <th>Message</th>
                    </tr>
                </thead>
                <tbody>
"""
        
        for alert in data.alerts[-20:]:  # Last 20 alerts
            html += f"""
                    <tr>
                        <td>{alert['triggered_at'][:19]}</td>
                        <td>{alert['level']}</td>
                        <td>{alert['type']}</td>
                        <td>{alert['message']}</td>
                    </tr>
"""
        
        html += """
                </tbody>
            </table>
        </div>
"""
        return html
    
    # =========================================================================
    # Markdown Generation
    # =========================================================================
    
    def _generate_markdown(self, config: ReportConfig, data: ReportData) -> str:
        """Generate Markdown report"""
        md = f"# {config.title}\n\n"
        
        if config.subtitle:
            md += f"*{config.subtitle}*\n\n"
        
        md += f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
        md += f"**Author:** {config.author}\n\n"
        md += "---\n\n"
        
        # PnL Summary
        if data.has_pnl_data:
            pnl = data.pnl_summary
            md += "## PnL Summary\n\n"
            md += f"| Metric | Value |\n"
            md += f"|--------|-------|\n"
            md += f"| Total PnL | ${pnl['total_pnl']:,.2f} |\n"
            md += f"| Total Trades | {pnl['total_trades']} |\n"
            md += f"| Win Rate | {pnl['win_rate']:.1f}% |\n"
            md += f"| Profit Factor | {pnl.get('profit_factor', 0):.2f} |\n"
            md += f"| Gross Profit | ${pnl['gross_profit']:,.2f} |\n"
            md += f"| Gross Loss | ${pnl['gross_loss']:,.2f} |\n\n"
        
        # Strategy Analysis
        if data.has_strategy_data:
            metrics = data.strategy_metrics
            md += "## Strategy Analysis\n\n"
            md += f"**Strategy Grade: {metrics['grade']}**\n\n"
            md += f"| Metric | Value |\n"
            md += f"|--------|-------|\n"
            md += f"| Win Rate | {metrics['win_rate']:.1f}% |\n"
            md += f"| Risk/Reward | {metrics['risk_reward_ratio']:.2f} |\n"
            md += f"| Sharpe Ratio | {metrics['sharpe_ratio']:.2f} |\n"
            md += f"| Max Drawdown | ${metrics['max_drawdown']:,.2f} |\n\n"
        
        # Open Positions
        if data.has_position_data:
            md += "## Open Positions\n\n"
            md += "| Coin | Side | Size | Entry | Mark | PnL | PnL % |\n"
            md += "|------|------|------|-------|------|-----|-------|\n"
            for pos in data.positions:
                md += (f"| {pos['coin']} | {pos['side']} | {pos['size']:.4f} | "
                      f"${pos['entry_price']:,.2f} | ${pos['mark_price']:,.2f} | "
                      f"${pos['unrealized_pnl']:,.2f} | {pos['pnl_percentage']:.2f}% |\n")
            md += "\n"
        
        # Performance by Coin
        if data.performance_by_coin:
            md += "## Performance by Coin\n\n"
            md += "| Coin | PnL |\n"
            md += "|------|-----|\n"
            for coin, pnl in sorted(data.performance_by_coin.items(), 
                                    key=lambda x: x[1], reverse=True):
                md += f"| {coin} | ${pnl:,.2f} |\n"
            md += "\n"
        
        # Alerts
        if data.has_alert_data:
            md += "## Recent Alerts\n\n"
            md += "| Time | Level | Message |\n"
            md += "|------|-------|----------|\n"
            for alert in data.alerts[-10:]:
                md += f"| {alert['triggered_at'][:19]} | {alert['level']} | {alert['message']} |\n"
            md += "\n"
        
        md += "---\n\n"
        md += f"*Report generated by {config.author} - Hyperliquid Monitor Plus*\n"
        
        return md
    
    # =========================================================================
    # JSON Generation
    # =========================================================================
    
    def _generate_json(self, config: ReportConfig, data: ReportData) -> str:
        """Generate JSON report"""
        report_dict = {
            "metadata": {
                "title": config.title,
                "subtitle": config.subtitle,
                "author": config.author,
                "generated_at": datetime.now().isoformat(),
                "period_start": data.metadata.get("period_start").isoformat() 
                               if data.metadata.get("period_start") else None,
                "period_end": data.metadata.get("period_end").isoformat()
                             if data.metadata.get("period_end") else None,
                "report_type": config.report_type.value,
                "format": config.format.value
            },
            "pnl_summary": data.pnl_summary,
            "positions": data.positions,
            "strategy_metrics": data.strategy_metrics,
            "alerts": data.alerts,
            "trades": data.trades if config.include_raw_data else None,
            "performance_by_coin": data.performance_by_coin,
            "statistics": data.statistics
        }
        
        # Remove None values
        report_dict = {k: v for k, v in report_dict.items() if v is not None}
        
        return json.dumps(report_dict, indent=2, default=str)
    
    # =========================================================================
    # CSV Generation
    # =========================================================================
    
    def _generate_csv(self, config: ReportConfig, data: ReportData) -> str:
        """Generate CSV report (trades data)"""
        output = io.StringIO()
        
        if data.has_trade_data:
            writer = csv.DictWriter(output, fieldnames=[
                "timestamp", "coin", "side", "size", 
                "entry_price", "exit_price", "pnl", "fee"
            ])
            writer.writeheader()
            for trade in data.trades:
                writer.writerow(trade)
        else:
            output.write("No trade data available\n")
        
        return output.getvalue()
    
    # =========================================================================
    # Text Generation
    # =========================================================================
    
    def _generate_text(self, config: ReportConfig, data: ReportData) -> str:
        """Generate plain text report"""
        text = "=" * 60 + "\n"
        text += f"{config.title.center(60)}\n"
        if config.subtitle:
            text += f"{config.subtitle.center(60)}\n"
        text += "=" * 60 + "\n\n"
        
        text += f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
        text += f"Author: {config.author}\n\n"
        
        # PnL Summary
        if data.has_pnl_data:
            pnl = data.pnl_summary
            text += "-" * 60 + "\n"
            text += "PNL SUMMARY\n"
            text += "-" * 60 + "\n"
            text += f"Total PnL:      ${pnl['total_pnl']:>12,.2f}\n"
            text += f"Total Trades:   {pnl['total_trades']:>12}\n"
            text += f"Win Rate:       {pnl['win_rate']:>11.1f}%\n"
            text += f"Profit Factor:  {pnl.get('profit_factor', 0):>12.2f}\n"
            text += f"Gross Profit:   ${pnl['gross_profit']:>12,.2f}\n"
            text += f"Gross Loss:     ${pnl['gross_loss']:>12,.2f}\n\n"
        
        # Strategy Analysis
        if data.has_strategy_data:
            metrics = data.strategy_metrics
            text += "-" * 60 + "\n"
            text += "STRATEGY ANALYSIS\n"
            text += "-" * 60 + "\n"
            text += f"Grade:          {metrics['grade']:>12}\n"
            text += f"Win Rate:       {metrics['win_rate']:>11.1f}%\n"
            text += f"Risk/Reward:    {metrics['risk_reward_ratio']:>12.2f}\n"
            text += f"Sharpe Ratio:   {metrics['sharpe_ratio']:>12.2f}\n\n"
        
        # Positions
        if data.has_position_data:
            text += "-" * 60 + "\n"
            text += "OPEN POSITIONS\n"
            text += "-" * 60 + "\n"
            for pos in data.positions:
                text += f"{pos['coin']:>6} {pos['side']:>5} "
                text += f"Size: {pos['size']:.4f} "
                text += f"PnL: ${pos['unrealized_pnl']:>8,.2f}\n"
            text += "\n"
        
        text += "=" * 60 + "\n"
        text += f"Hyperliquid Monitor Plus - {config.author}\n"
        text += "=" * 60 + "\n"
        
        return text
    
    # =========================================================================
    # Utility Methods
    # =========================================================================
    
    def get_data_summary(self) -> Dict[str, int]:
        """Get summary of available data"""
        with self._lock:
            return {
                "pnl_records": len(self._pnl_records),
                "positions": len(self._positions),
                "alerts": len(self._alerts),
                "has_portfolio": self._portfolio is not None,
                "has_strategy": self._strategy_metrics is not None
            }
