"""
PDF report generator for SonarQube scan results.
"""
import logging
from pathlib import Path
from datetime import datetime
from typing import Dict, Optional, List
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT

logger = logging.getLogger(__name__)


class ReportGenerator:
    """Generates PDF reports from SonarQube scan results."""
    
    def __init__(self, reports_dir: str = "./reports"):
        """
        Initialize report generator.
        
        Args:
            reports_dir: Directory where reports will be saved
        """
        self.reports_dir = Path(reports_dir)
        self.reports_dir.mkdir(parents=True, exist_ok=True)
    
    def generate_report(
        self,
        repo_name: str,
        scan_results: Dict,
        sonar_results: Optional[Dict] = None,
        scan_output: Optional[str] = None
    ) -> Path:
        """
        Generate PDF report for a scan.
        
        Args:
            repo_name: Repository name
            scan_results: Scan execution results dictionary
            sonar_results: SonarQube API results (optional)
            scan_output: Raw scanner output (optional)
            
        Returns:
            Path to generated PDF file
        """
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{repo_name}_{timestamp}.pdf"
        filepath = self.reports_dir / filename
        
        logger.info(f"Generating PDF report: {filepath}")
        
        try:
            doc = SimpleDocTemplate(
                str(filepath),
                pagesize=letter,
                rightMargin=0.75*inch,
                leftMargin=0.75*inch,
                topMargin=0.75*inch,
                bottomMargin=0.75*inch
            )
            
            # Container for the 'Flowable' objects
            elements = []
            
            # Define styles
            styles = getSampleStyleSheet()
            title_style = ParagraphStyle(
                'CustomTitle',
                parent=styles['Heading1'],
                fontSize=24,
                textColor=colors.HexColor('#0891b2'),
                spaceAfter=30,
                alignment=TA_CENTER
            )
            
            # Title
            title = Paragraph(f"SonarQube Scan Report: {repo_name}", title_style)
            elements.append(title)
            elements.append(Spacer(1, 0.2*inch))
            
            # Scan Information
            elements.append(Paragraph("Scan Information", styles['Heading2']))
            scan_info_data = [
                ["Repository", repo_name],
                ["Scan Date", datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
                ["Status", "Success" if scan_results.get("success") else "Failed"]
            ]
            
            if scan_results.get("task_id"):
                scan_info_data.append(["Task ID", scan_results["task_id"]])
            if scan_results.get("analysis_id"):
                scan_info_data.append(["Analysis ID", scan_results["analysis_id"]])
            
            scan_info_table = Table(scan_info_data, colWidths=[2*inch, 4*inch])
            scan_info_table.setStyle(TableStyle([
                ('BACKGROUND', (0, 0), (0, -1), colors.grey),
                ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTSIZE', (0, 0), (-1, 0), 12),
                ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                ('GRID', (0, 0), (-1, -1), 1, colors.black)
            ]))
            elements.append(scan_info_table)
            elements.append(Spacer(1, 0.3*inch))
            
            # Quality Gate Status
            if sonar_results and sonar_results.get("quality_gate"):
                elements.append(Paragraph("Quality Gate Status", styles['Heading2']))
                qg_status = sonar_results["quality_gate"]
                status_color = colors.green if qg_status == "OK" else colors.red
                
                qg_data = [["Status", qg_status]]
                qg_table = Table(qg_data, colWidths=[2*inch, 4*inch])
                qg_table.setStyle(TableStyle([
                    ('BACKGROUND', (0, 0), (0, -1), colors.grey),
                    ('TEXTCOLOR', (1, 0), (1, 0), status_color),
                    ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                    ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                    ('FONTSIZE', (0, 0), (-1, 0), 12),
                    ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                    ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                    ('GRID', (0, 0), (-1, -1), 1, colors.black)
                ]))
                elements.append(qg_table)
                elements.append(Spacer(1, 0.3*inch))
            
            # Metrics
            if sonar_results and sonar_results.get("metrics"):
                elements.append(Paragraph("Code Metrics", styles['Heading2']))
                metrics = sonar_results["metrics"]
                
                metrics_data = [["Metric", "Value"]]
                for metric in metrics:
                    metric_name = metric.get("metric", "")
                    metric_value = metric.get("value", "N/A")
                    # Format metric names for readability
                    formatted_name = metric_name.replace("_", " ").title()
                    metrics_data.append([formatted_name, str(metric_value)])
                
                if len(metrics_data) > 1:
                    metrics_table = Table(metrics_data, colWidths=[3*inch, 3*inch])
                    metrics_table.setStyle(TableStyle([
                        ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
                        ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                        ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                        ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                        ('FONTSIZE', (0, 0), (-1, 0), 12),
                        ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                        ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                        ('GRID', (0, 0), (-1, -1), 1, colors.black)
                    ]))
                    elements.append(metrics_table)
                    elements.append(Spacer(1, 0.3*inch))
            
            # Error Information
            if not scan_results.get("success"):
                elements.append(Paragraph("Error Details", styles['Heading2']))
                error_text = scan_results.get("error", "Unknown error occurred")
                error_para = Paragraph(f"<b>Error:</b> {error_text}", styles['Normal'])
                elements.append(error_para)
                elements.append(Spacer(1, 0.2*inch))
            
            # Scan Output (truncated if too long)
            if scan_output:
                elements.append(PageBreak())
                elements.append(Paragraph("Scan Output", styles['Heading2']))
                # Truncate output if too long
                max_output_length = 5000
                if len(scan_output) > max_output_length:
                    truncated_output = scan_output[:max_output_length] + "\n\n... (output truncated)"
                else:
                    truncated_output = scan_output
                
                output_para = Paragraph(
                    f"<pre>{truncated_output}</pre>",
                    ParagraphStyle('Code', parent=styles['Code'], fontSize=8)
                )
                elements.append(output_para)
            
            # Build PDF
            doc.build(elements)
            logger.info(f"PDF report generated successfully: {filepath}")
            return filepath
            
        except Exception as e:
            logger.error(f"Failed to generate PDF report: {e}")
            raise

