#!/usr/bin/env python3
"""
Chart Exporters and Report Generators

Provides utilities for exporting charts and generating comprehensive
reports in various formats including HTML, PDF, and standalone charts.

Author: Pezhman Hajipour
Version: 3.0.0
"""

import logging
import json
import base64
from io import BytesIO
from datetime import datetime
from typing import Dict, List, Optional, Any, Union
from dataclasses import dataclass, asdict
import os

# Check for pandas (optional, used in dashboard components)
PANDAS_AVAILABLE = False
try:
    import pandas as pd
    PANDAS_AVAILABLE = True
except ImportError:
    PANDAS_AVAILABLE = False

# Check for visualization libraries
MATPLOTLIB_AVAILABLE = False
PLOTLY_AVAILABLE = False

try:
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_pdf import PdfPages
    import matplotlib.dates as mdates
    MATPLOTLIB_AVAILABLE = True
except ImportError:
    MATPLOTLIB_AVAILABLE = False

try:
    import plotly.graph_objects as go
    import plotly.io as pio
    from plotly.offline import plot
    PLOTLY_AVAILABLE = True
except ImportError:
    PLOTLY_AVAILABLE = False
    # Create dummy objects for type hints when plotly is not available
    class _DummyGo:
        class Figure:
            pass
    go = _DummyGo()

logger = logging.getLogger(__name__)

@dataclass
class ExportConfig:
    """Configuration for chart export"""
    format: str = "png"  # png, jpg, svg, pdf, html
    dpi: int = 300
    width: int = 1200
    height: int = 800
    include_metadata: bool = True
    compress: bool = False

@dataclass
class ReportSection:
    """Section for comprehensive reports"""
    title: str
    content: str
    charts: List[str] = None  # Chart file paths
    data: Dict[str, Any] = None
    metadata: Dict[str, Any] = None

class ChartExporter:
    """Utility class for exporting charts in various formats"""
    
    def __init__(self):
        self.exported_charts = []
        
    def export_matplotlib_figure(self, fig: plt.Figure, 
                               output_path: str, 
                               config: ExportConfig = None) -> bool:
        """Export matplotlib figure to file"""
        if not MATPLOTLIB_AVAILABLE:
            raise ImportError("Matplotlib not available. Install with: pip install hyperliquid-monitor-plus[viz]")
            
        if config is None:
            config = ExportConfig()
            
        try:
            # Configure figure
            fig.set_size_inches(config.width/100, config.height/100)
            
            # Save based on format
            if config.format.lower() == 'pdf':
                fig.savefig(output_path, format='pdf', dpi=config.dpi, 
                           bbox_inches='tight', metadata=config.metadata if config.include_metadata else None)
            elif config.format.lower() in ['png', 'jpg', 'jpeg']:
                fig.savefig(output_path, format=config.format, dpi=config.dpi, 
                           bbox_inches='tight', metadata=config.metadata if config.include_metadata else None)
            elif config.format.lower() == 'svg':
                fig.savefig(output_path, format='svg', 
                           bbox_inches='tight', metadata=config.metadata if config.include_metadata else None)
            else:
                raise ValueError(f"Unsupported format: {config.format}")
                
            self.exported_charts.append({
                'path': output_path,
                'format': config.format,
                'size': os.path.getsize(output_path) if os.path.exists(output_path) else 0,
                'timestamp': datetime.now().isoformat()
            })
            
            logger.info(f"Chart exported successfully to {output_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to export chart: {e}")
            return False
            
    def export_plotly_figure(self, fig: go.Figure, 
                           output_path: str, 
                           config: ExportConfig = None) -> bool:
        """Export Plotly figure to file"""
        if not PLOTLY_AVAILABLE:
            raise ImportError("Plotly not available. Install with: pip install hyperliquid-monitor-plus[viz]")
            
        if config is None:
            config = ExportConfig()
            
        try:
            # Configure figure size
            fig.update_layout(
                width=config.width,
                height=config.height,
                title_x=0.5
            )
            
            # Export based on format
            if config.format.lower() == 'html':
                fig.write_html(output_path, include_plotlyjs='cdn', config={'displayModeBar': True})
            elif config.format.lower() in ['png', 'jpg', 'jpeg', 'svg', 'pdf']:
                # For image formats, use kaleido
                fig.write_image(output_path, format=config.format, width=config.width, 
                               height=config.height, scale=config.dpi/100)
            else:
                raise ValueError(f"Unsupported format: {config.format}")
                
            self.exported_charts.append({
                'path': output_path,
                'format': config.format,
                'size': os.path.getsize(output_path) if os.path.exists(output_path) else 0,
                'timestamp': datetime.now().isoformat()
            })
            
            logger.info(f"Interactive chart exported successfully to {output_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to export interactive chart: {e}")
            return False
            
    def export_to_base64(self, fig: Union[plt.Figure, go.Figure], 
                        config: ExportConfig = None) -> Optional[str]:
        """Export chart to base64 encoded string for embedding"""
        if config is None:
            config = ExportConfig()
            
        try:
            buffer = BytesIO()
            
            if isinstance(fig, plt.Figure) and MATPLOTLIB_AVAILABLE:
                fig.savefig(buffer, format='png', dpi=config.dpi, bbox_inches='tight')
            elif isinstance(fig, go.Figure) and PLOTLY_AVAILABLE:
                buffer.write(pio.to_image(fig, format='png', width=config.width, 
                                        height=config.height, scale=config.dpi/100).encode())
            else:
                return None
                
            buffer.seek(0)
            image_base64 = base64.b64encode(buffer.getvalue()).decode()
            buffer.close()
            
            return f"data:image/{config.format};base64,{image_base64}"
            
        except Exception as e:
            logger.error(f"Failed to export chart to base64: {e}")
            return None
            
    def get_export_statistics(self) -> Dict[str, Any]:
        """Get statistics about exported charts"""
        if not self.exported_charts:
            return {'total_exports': 0}
            
        total_size = sum(chart['size'] for chart in self.exported_charts)
        formats = {}
        
        for chart in self.exported_charts:
            fmt = chart['format']
            formats[fmt] = formats.get(fmt, 0) + 1
            
        return {
            'total_exports': len(self.exported_charts),
            'total_size_bytes': total_size,
            'total_size_mb': round(total_size / (1024*1024), 2),
            'formats': formats,
            'latest_export': self.exported_charts[-1] if self.exported_charts else None
        }

class HTMLReportGenerator:
    """Generate comprehensive HTML reports with embedded charts"""
    
    def __init__(self):
        self.sections = []
        self.metadata = {}
        
    def add_section(self, section: ReportSection):
        """Add section to report"""
        self.sections.append(section)
        
    def add_metadata(self, key: str, value: Any):
        """Add metadata to report"""
        self.metadata[key] = value
        
    def generate_report(self, output_path: str, 
                       embedded_charts: bool = True,
                       config: ExportConfig = None) -> bool:
        """Generate comprehensive HTML report"""
        if config is None:
            config = ExportConfig()
            
        try:
            # Create HTML content
            html_content = self._generate_html_content(embedded_charts, config)
            
            # Write to file
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(html_content)
                
            logger.info(f"HTML report generated successfully: {output_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to generate HTML report: {e}")
            return False
            
    def _generate_html_content(self, embedded_charts: bool, config: ExportConfig) -> str:
        """Generate HTML content for report"""
        
        # Start HTML document
        html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Whale Trading Analysis Report</title>
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
            color: #333;
        }}
        .container {{
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 0 20px rgba(0,0,0,0.1);
        }}
        .header {{
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 2px solid #007bff;
        }}
        .title {{
            color: #007bff;
            font-size: 2.5em;
            margin-bottom: 10px;
        }}
        .subtitle {{
            color: #666;
            font-size: 1.2em;
        }}
        .section {{
            margin-bottom: 40px;
        }}
        .section-title {{
            color: #007bff;
            font-size: 1.8em;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }}
        .section-content {{
            line-height: 1.6;
            margin-bottom: 20px;
        }}
        .chart-container {{
            text-align: center;
            margin: 20px 0;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 8px;
        }}
        .chart-container img {{
            max-width: 100%;
            height: auto;
            border-radius: 5px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }}
        .metadata {{
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
        }}
        .metadata h4 {{
            margin-top: 0;
            color: #495057;
        }}
        .metadata-item {{
            margin: 5px 0;
            padding: 5px 10px;
            background: white;
            border-radius: 3px;
        }}
        .footer {{
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            text-align: center;
            color: #666;
        }}
        .stats-grid {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }}
        .stat-card {{
            background: #007bff;
            color: white;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
        }}
        .stat-number {{
            font-size: 2em;
            font-weight: bold;
            margin-bottom: 5px;
        }}
        .stat-label {{
            font-size: 0.9em;
            opacity: 0.9;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1 class="title">🐋 Whale Trading Analysis Report</h1>
            <p class="subtitle">Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
        </div>
"""
        
        # Add metadata section if available
        if self.metadata:
            html += """
        <div class="metadata">
            <h4>📊 Report Metadata</h4>
"""
            for key, value in self.metadata.items():
                html += f'            <div class="metadata-item"><strong>{key}:</strong> {value}</div>\n'
            html += "        </div>\n"
        
        # Add sections
        for i, section in enumerate(self.sections, 1):
            html += f"""
        <div class="section">
            <h2 class="section-title">{i}. {section.title}</h2>
            <div class="section-content">
                {section.content}
            </div>
"""
            
            # Add charts if provided
            if section.charts:
                for chart_path in section.charts:
                    if os.path.exists(chart_path) and embedded_charts:
                        # Convert to base64 for embedding
                        try:
                            with open(chart_path, 'rb') as f:
                                chart_data = base64.b64encode(f.read()).decode()
                            chart_type = 'png' if chart_path.lower().endswith('.png') else 'jpg'
                            html += f"""
            <div class="chart-container">
                <img src="data:image/{chart_type};base64,{chart_data}" alt="Chart">
            </div>
"""
                        except Exception as e:
                            logger.warning(f"Could not embed chart {chart_path}: {e}")
                    elif os.path.exists(chart_path):
                        # Add link to external chart
                        html += f"""
            <div class="chart-container">
                <p><a href="{chart_path}" target="_blank">📊 View Chart: {os.path.basename(chart_path)}</a></p>
            </div>
"""
                            
            # Add data table if provided
            if section.data:
                html += self._generate_data_table(section.data)
                
            html += "        </div>\n"
        
        # Add footer
        html += f"""
        <div class="footer">
            <p>Generated by Hyperliquid Monitor Plus | Version 3.0.0</p>
            <p>Report ID: {self._generate_report_id()}</p>
        </div>
    </div>
</body>
</html>
"""
        
        return html
        
    def _generate_data_table(self, data: Dict[str, Any]) -> str:
        """Generate HTML table for data"""
        if not data:
            return ""
            
        html = '        <div class="data-table">\n            <table style="width: 100%; border-collapse: collapse; margin: 20px 0;">\n'
        
        for key, value in data.items():
            html += f'                <tr><td style="padding: 8px; border: 1px solid #ddd; font-weight: bold;">{key}</td><td style="padding: 8px; border: 1px solid #ddd;">{value}</td></tr>\n'
            
        html += '            </table>\n        </div>\n'
        return html
        
    def _generate_report_id(self) -> str:
        """Generate unique report ID"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        return f"WHALE_REPORT_{timestamp}"

class PDFReportGenerator:
    """Generate PDF reports with embedded charts"""
    
    def __init__(self):
        self.sections = []
        self.cover_image = None
        
    def add_section(self, section: ReportSection):
        """Add section to report"""
        self.sections.append(section)
        
    def set_cover_image(self, image_path: str):
        """Set cover image for PDF"""
        self.cover_image = image_path
        
    def generate_pdf_report(self, output_path: str, 
                           config: ExportConfig = None) -> bool:
        """Generate PDF report with charts"""
        if not MATPLOTLIB_AVAILABLE:
            raise ImportError("Matplotlib not available for PDF generation. Install with: pip install hyperliquid-monitor-plus[viz]")
            
        if config is None:
            config = ExportConfig()
            
        try:
            with PdfPages(output_path) as pdf:
                # Add cover page
                self._add_cover_page(pdf, config)
                
                # Add sections
                for section in self.sections:
                    self._add_section_to_pdf(pdf, section, config)
                    
                # Add metadata page
                self._add_metadata_page(pdf, config)
                
            logger.info(f"PDF report generated successfully: {output_path}")
            return True
            
        except Exception as e:
            logger.error(f"Failed to generate PDF report: {e}")
            return False
            
    def _add_cover_page(self, pdf: PdfPages, config: ExportConfig):
        """Add cover page to PDF"""
        fig, ax = plt.subplots(figsize=(8.5, 11))
        ax.axis('off')
        
        # Title
        ax.text(0.5, 0.8, '🐋 Whale Trading Analysis Report', 
               fontsize=24, fontweight='bold', ha='center', transform=ax.transAxes)
        
        # Subtitle
        ax.text(0.5, 0.7, 'Generated by Hyperliquid Monitor Plus', 
               fontsize=16, ha='center', transform=ax.transAxes, color='gray')
        
        # Date
        ax.text(0.5, 0.6, f'Generated on {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}', 
               fontsize=12, ha='center', transform=ax.transAxes)
        
        # Add cover image if available
        if self.cover_image and os.path.exists(self.cover_image):
            try:
                ax.imshow(plt.imread(self.cover_image), aspect='auto', alpha=0.3)
            except Exception as e:
                logger.warning(f"Could not load cover image: {e}")
        
        # Report summary
        ax.text(0.1, 0.4, 'Report Contents:', fontsize=14, fontweight='bold', transform=ax.transAxes)
        y_pos = 0.35
        for i, section in enumerate(self.sections, 1):
            ax.text(0.15, y_pos, f'{i}. {section.title}', fontsize=10, transform=ax.transAxes)
            y_pos -= 0.03
            
        # Footer
        ax.text(0.5, 0.1, 'Version 3.0.0', fontsize=10, ha='center', 
               transform=ax.transAxes, color='gray')
        
        pdf.savefig(fig, bbox_inches='tight')
        plt.close(fig)
        
    def _add_section_to_pdf(self, pdf: PdfPages, section: ReportSection, config: ExportConfig):
        """Add section content to PDF"""
        # Add section title page
        fig, ax = plt.subplots(figsize=(8.5, 11))
        ax.axis('off')
        
        ax.text(0.5, 0.9, section.title, fontsize=20, fontweight='bold', 
               ha='center', transform=ax.transAxes)
        
        # Add content
        if section.content:
            y_pos = 0.8
            for line in section.content.split('\n'):
                if y_pos < 0.1:
                    break
                ax.text(0.1, y_pos, line, fontsize=10, transform=ax.transAxes, wrap=True)
                y_pos -= 0.03
                
        pdf.savefig(fig, bbox_inches='tight')
        plt.close(fig)
        
        # Add charts if available
        if section.charts:
            for chart_path in section.charts:
                if os.path.exists(chart_path):
                    try:
                        # Load and display chart
                        img = plt.imread(chart_path)
                        fig, ax = plt.subplots(figsize=(8.5, 11))
                        ax.imshow(img)
                        ax.axis('off')
                        ax.set_title(f'Chart: {os.path.basename(chart_path)}', 
                                   fontsize=14, pad=20)
                        pdf.savefig(fig, bbox_inches='tight')
                        plt.close(fig)
                    except Exception as e:
                        logger.warning(f"Could not add chart to PDF: {e}")
                        
    def _add_metadata_page(self, pdf: PdfPages, config: ExportConfig):
        """Add metadata page to PDF"""
        fig, ax = plt.subplots(figsize=(8.5, 11))
        ax.axis('off')
        
        ax.text(0.5, 0.9, 'Report Metadata', fontsize=18, fontweight='bold', 
               ha='center', transform=ax.transAxes)
        
        y_pos = 0.8
        ax.text(0.1, y_pos, 'Generation Details:', fontsize=14, fontweight='bold', 
               transform=ax.transAxes)
        y_pos -= 0.05
        
        metadata_items = [
            ('Generated on', datetime.now().strftime('%Y-%m-%d %H:%M:%S')),
            ('Report ID', f"WHALE_REPORT_{datetime.now().strftime('%Y%m%d_%H%M%S')}"),
            ('Version', '3.0.0'),
            ('Sections', str(len(self.sections))),
        ]
        
        for key, value in metadata_items:
            ax.text(0.15, y_pos, f'{key}: {value}', fontsize=10, transform=ax.transAxes)
            y_pos -= 0.03
            
        pdf.savefig(fig, bbox_inches='tight')
        plt.close(fig)