#!/usr/bin/env python3
"""
Professional Markdown to PDF Converter using ReportLab
Converts Retool Product Analytics Plan to a styled PDF
"""

import markdown2
from reportlab.lib.pagesizes import A4, letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.colors import HexColor, black, blue, darkblue, darkgreen, grey
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Table, TableStyle
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib.enums import TA_LEFT, TA_JUSTIFY, TA_CENTER
from reportlab.pdfgen import canvas
from reportlab.lib import colors
from bs4 import BeautifulSoup
import re
import os

class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        canvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for (page_num, page_state) in enumerate(self._saved_page_states):
            self.__dict__.update(page_state)
            self.draw_page_number(page_num + 1, num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_page_number(self, page_num, total_pages):
        self.setFont("Helvetica", 9)
        self.setFillColor(grey)
        # Header - draw centered text
        text_width = self.stringWidth("Retool Product Analytics Strategy", "Helvetica", 9)
        self.drawString((A4[0] - text_width) / 2.0, A4[1] - 0.5*inch, "Retool Product Analytics Strategy")
        # Footer - draw centered text
        footer_text = f"Page {page_num} of {total_pages}"
        footer_width = self.stringWidth(footer_text, "Helvetica", 9)
        self.drawString((A4[0] - footer_width) / 2.0, 0.75*inch, footer_text)

def create_styles():
    """Create custom paragraph styles"""
    styles = getSampleStyleSheet()
    
    # Title style
    styles.add(ParagraphStyle(
        name='CustomTitle',
        parent=styles['Title'],
        fontSize=24,
        spaceAfter=24,
        spaceBefore=12,
        textColor=HexColor('#2c3e50'),
        fontName='Helvetica-Bold'
    ))
    
    # Heading styles
    styles.add(ParagraphStyle(
        name='CustomHeading1',
        parent=styles['Heading1'],
        fontSize=20,
        spaceAfter=18,
        spaceBefore=20,
        textColor=HexColor('#34495e'),
        fontName='Helvetica-Bold',
        keepWithNext=1
    ))
    
    styles.add(ParagraphStyle(
        name='CustomHeading2',
        parent=styles['Heading2'],
        fontSize=16,
        spaceAfter=12,
        spaceBefore=16,
        textColor=HexColor('#2c3e50'),
        fontName='Helvetica-Bold',
        keepWithNext=1
    ))
    
    styles.add(ParagraphStyle(
        name='CustomHeading3',
        parent=styles['Heading3'],
        fontSize=14,
        spaceAfter=10,
        spaceBefore=14,
        textColor=HexColor('#34495e'),
        fontName='Helvetica-Bold',
        keepWithNext=1
    ))
    
    styles.add(ParagraphStyle(
        name='CustomHeading4',
        parent=styles['Heading3'],
        fontSize=12,
        spaceAfter=8,
        spaceBefore=12,
        textColor=HexColor('#34495e'),
        fontName='Helvetica-Bold',
        keepWithNext=1
    ))
    
    # Body text
    styles.add(ParagraphStyle(
        name='CustomBodyText',
        parent=styles['BodyText'],
        fontSize=11,
        spaceAfter=8,
        spaceBefore=0,
        alignment=TA_JUSTIFY,
        fontName='Helvetica'
    ))
    
    # Code style
    styles.add(ParagraphStyle(
        name='CodeBlock',
        parent=styles['Code'],
        fontSize=9,
        spaceAfter=12,
        spaceBefore=8,
        leftIndent=20,
        backgroundColor=HexColor('#f8f9fa'),
        borderColor=HexColor('#e9ecef'),
        borderWidth=1,
        borderPadding=8,
        fontName='Courier'
    ))
    
    # List style
    styles.add(ParagraphStyle(
        name='CustomBullet',
        parent=styles['BodyText'],
        fontSize=11,
        spaceAfter=4,
        leftIndent=20,
        bulletIndent=10,
        fontName='Helvetica'
    ))
    
    # Table caption
    styles.add(ParagraphStyle(
        name='TableCaption',
        parent=styles['BodyText'],
        fontSize=10,
        spaceAfter=6,
        alignment=TA_CENTER,
        fontName='Helvetica-Oblique',
        textColor=HexColor('#555555')
    ))
    
    # Executive summary
    styles.add(ParagraphStyle(
        name='ExecutiveSummary',
        parent=styles['BodyText'],
        fontSize=11,
        spaceAfter=8,
        spaceBefore=8,
        leftIndent=15,
        rightIndent=15,
        alignment=TA_JUSTIFY,
        backgroundColor=HexColor('#f8f9fa'),
        borderColor=HexColor('#3498db'),
        borderWidth=2,
        borderPadding=12,
        fontName='Helvetica'
    ))
    
    return styles

def parse_html_to_story(html_content, styles):
    """Parse HTML content to ReportLab story elements"""
    soup = BeautifulSoup(html_content, 'html.parser')
    story = []
    
    for element in soup.body.children:
        if element.name is None:  # Text node
            continue
            
        if element.name == 'h1':
            story.append(Paragraph(element.get_text(), styles['CustomTitle']))
            story.append(Spacer(1, 12))
        elif element.name == 'h2':
            story.append(Paragraph(element.get_text(), styles['CustomHeading1']))
            story.append(Spacer(1, 8))
        elif element.name == 'h3':
            story.append(Paragraph(element.get_text(), styles['CustomHeading2']))
            story.append(Spacer(1, 6))
        elif element.name == 'h4':
            story.append(Paragraph(element.get_text(), styles['CustomHeading3']))
            story.append(Spacer(1, 6))
        elif element.name == 'h5' or element.name == 'h6':
            story.append(Paragraph(element.get_text(), styles['CustomHeading4']))
            story.append(Spacer(1, 4))
        elif element.name == 'p':
            text = element.get_text()
            if text.strip():
                # Check if it's an executive summary section
                if 'Executive Summary' in text or text.startswith('**Key Metrics Framework:**'):
                    story.append(Paragraph(clean_text(text), styles['ExecutiveSummary']))
                else:
                    story.append(Paragraph(clean_text(text), styles['CustomBodyText']))
                story.append(Spacer(1, 4))
        elif element.name == 'ul':
            for li in element.find_all('li', recursive=False):
                bullet_text = clean_text(li.get_text())
                # Handle checkmarks
                if bullet_text.startswith('✅'):
                    bullet_text = '✓ ' + bullet_text[2:].strip()
                story.append(Paragraph(f"• {bullet_text}", styles['CustomBullet']))
            story.append(Spacer(1, 8))
        elif element.name == 'ol':
            for i, li in enumerate(element.find_all('li', recursive=False)):
                bullet_text = clean_text(li.get_text())
                story.append(Paragraph(f"{i+1}. {bullet_text}", styles['CustomBullet']))
            story.append(Spacer(1, 8))
        elif element.name == 'pre':
            code_text = element.get_text()
            story.append(Paragraph(code_text, styles['CodeBlock']))
            story.append(Spacer(1, 8))
        elif element.name == 'table':
            table_data = []
            # Get table headers
            headers = []
            header_row = element.find('thead')
            if header_row:
                for th in header_row.find_all('th'):
                    headers.append(clean_text(th.get_text()))
                table_data.append(headers)
            
            # Get table rows
            tbody = element.find('tbody') or element
            for tr in tbody.find_all('tr'):
                if tr.find('th'):  # Skip header rows in tbody
                    continue
                row = []
                for td in tr.find_all('td'):
                    cell_text = clean_text(td.get_text())
                    row.append(cell_text)
                if row:
                    table_data.append(row)
            
            if table_data:
                table = Table(table_data)
                table.setStyle(TableStyle([
                    ('BACKGROUND', (0, 0), (-1, 0), HexColor('#3498db')),
                    ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                    ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                    ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                    ('FONTSIZE', (0, 0), (-1, -1), 9),
                    ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                    ('BACKGROUND', (0, 1), (-1, -1), HexColor('#f8f9fa')),
                    ('GRID', (0, 0), (-1, -1), 1, HexColor('#bdc3c7')),
                    ('VALIGN', (0, 0), (-1, -1), 'TOP'),
                ]))
                story.append(table)
                story.append(Spacer(1, 12))
        elif element.name == 'hr':
            story.append(Spacer(1, 12))
            story.append(PageBreak())
        elif element.name == 'blockquote':
            quote_text = clean_text(element.get_text())
            story.append(Paragraph(quote_text, styles['ExecutiveSummary']))
            story.append(Spacer(1, 8))
    
    return story

def clean_text(text):
    """Clean and format text for ReportLab"""
    # Remove extra whitespace
    text = re.sub(r'\s+', ' ', text.strip())
    
    # Handle markdown formatting that might remain
    text = text.replace('**', '<b>').replace('**', '</b>')
    text = text.replace('*', '<i>').replace('*', '</i>')
    
    # Handle checkmarks
    text = text.replace('✅', '✓')
    
    # Escape XML characters
    text = text.replace('&', '&amp;')
    text = text.replace('<', '&lt;').replace('>', '&gt;')
    
    # Restore formatting tags
    text = text.replace('&lt;b&gt;', '<b>').replace('&lt;/b&gt;', '</b>')
    text = text.replace('&lt;i&gt;', '<i>').replace('&lt;/i&gt;', '</i>')
    
    return text

def convert_markdown_to_pdf(input_file, output_file):
    """Convert markdown file to professional PDF using ReportLab"""
    
    # Read the markdown file
    with open(input_file, 'r', encoding='utf-8') as f:
        markdown_content = f.read()
    
    # Convert markdown to HTML
    html_content = markdown2.markdown(
        markdown_content,
        extras=[
            'fenced-code-blocks',
            'tables',
            'header-ids',
            'strike',
            'task_list',
            'footnotes',
            'cuddled-lists',
            'code-friendly',
        ]
    )
    
    # Create the PDF document
    doc = SimpleDocTemplate(
        output_file,
        pagesize=A4,
        rightMargin=0.75*inch,
        leftMargin=0.75*inch,
        topMargin=1*inch,
        bottomMargin=1*inch
    )
    
    # Create styles
    styles = create_styles()
    
    # Parse HTML to story elements
    story = parse_html_to_story(f'<html><body>{html_content}</body></html>', styles)
    
    # Build PDF
    try:
        doc.build(story, canvasmaker=NumberedCanvas)
        return True
    except Exception as e:
        print(f"Error building PDF: {e}")
        return False

def main():
    """Main conversion function"""
    input_file = "/Users/igloo/.openclaw/workspace/scratch/retool-product-analytics-plan.md"
    output_file = "/Users/igloo/.openclaw/workspace/scratch/retool-product-analytics-plan.pdf"
    
    print(f"Converting {input_file} to {output_file}...")
    
    if not os.path.exists(input_file):
        print(f"Error: Input file {input_file} not found!")
        return False
    
    success = convert_markdown_to_pdf(input_file, output_file)
    
    if success:
        # Get file size
        file_size = os.path.getsize(output_file)
        file_size_mb = file_size / (1024 * 1024)
        
        print(f"✅ Successfully converted to PDF!")
        print(f"📁 Output file: {output_file}")
        print(f"📊 File size: {file_size:,} bytes ({file_size_mb:.2f} MB)")
        return True
    else:
        print("❌ Conversion failed!")
        return False

if __name__ == "__main__":
    main()