#!/usr/bin/env python3
"""
Company Research Report PDF Generator

Generates professionally styled PDF reports from research data.
Uses reportlab for high-quality PDF output with proper typography and layout.

Usage:
    python generate_report.py input.json output.pdf

Input JSON structure: See references/data-schema.md
"""

import json
import sys
from datetime import datetime
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    KeepTogether, HRFlowable, CondPageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

# macOS 中文字体：优先 Arial Unicode，其次 STHeiti（黑体-简），避免中文显示为方块
def _register_cjk_font():
    """注册支持中文的字体，返回 (normal_name, bold_name)。"""
    import os
    import platform
    candidates = []
    if platform.system() == 'Darwin':
        candidates = [
            ('HeitiSC', '/System/Library/Fonts/STHeiti Medium.ttc', 0),
            ('ArialUnicodeMS', '/System/Library/Fonts/Supplemental/Arial Unicode.ttf', None),
            ('SongtiSC', '/System/Library/Fonts/Supplemental/Songti.ttc', 0),
            ('PingFang', '/System/Library/Fonts/PingFang.ttc', 0),
        ]
        # 用户目录下的中文字体作为备选
        user_font = os.path.expanduser('~/Library/Fonts/FZLTHJW.TTF')
        if os.path.isfile(user_font):
            candidates.append(('FZLanTingHei', user_font, None))
    for name, path, sub in candidates:
        try:
            if os.path.isfile(path):
                if sub is not None:
                    f = TTFont(name, path, subfontIndex=sub)
                else:
                    f = TTFont(name, path)
                pdfmetrics.registerFont(f)
                return (name, name)
        except Exception:
            continue
    return ('Helvetica', 'Helvetica-Bold')

_CJK_FONT, _CJK_FONT_BOLD = _register_cjk_font()


def _escape_for_paragraph(s):
    """Paragraph 内需转义 & < >，避免被当作标签解析。"""
    if s is None:
        return ''
    s = str(s)
    return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')

# Color palette (professional slate-based)
COLORS = {
    'primary': colors.HexColor('#1e293b'),      # Dark slate
    'secondary': colors.HexColor('#334155'),    # Medium slate
    'muted': colors.HexColor('#64748b'),        # Light slate
    'accent_blue': colors.HexColor('#3b82f6'),
    'accent_emerald': colors.HexColor('#10b981'),
    'accent_violet': colors.HexColor('#8b5cf6'),
    'accent_amber': colors.HexColor('#f59e0b'),
    'accent_teal': colors.HexColor('#14b8a6'),
    'accent_indigo': colors.HexColor('#6366f1'),
    'accent_rose': colors.HexColor('#f43f5e'),
    'bg_light': colors.HexColor('#f8fafc'),
    'border': colors.HexColor('#e2e8f0'),
    'white': colors.white,
}


def create_styles():
    """Create custom paragraph styles for the report."""
    styles = getSampleStyleSheet()
    styles['Normal'].fontName = _CJK_FONT

    # Title style (for header)
    styles.add(ParagraphStyle(
        'ReportTitle',
        parent=styles['Heading1'],
        fontSize=24,
        textColor=COLORS['white'],
        spaceAfter=6,
        fontName=_CJK_FONT_BOLD
    ))

    # Section heading
    styles.add(ParagraphStyle(
        'SectionHeading',
        parent=styles['Heading2'],
        fontSize=14,
        textColor=COLORS['primary'],
        spaceBefore=16,
        spaceAfter=8,
        borderPadding=(0, 0, 4, 0),
        fontName=_CJK_FONT_BOLD
    ))

    # Subsection heading
    styles.add(ParagraphStyle(
        'SubHeading',
        parent=styles['Heading3'],
        fontSize=11,
        textColor=COLORS['secondary'],
        spaceBefore=12,
        spaceAfter=6,
        fontName=_CJK_FONT_BOLD
    ))

    # Body text (custom)
    styles.add(ParagraphStyle(
        'ReportBody',
        parent=styles['Normal'],
        fontSize=10,
        textColor=COLORS['secondary'],
        spaceAfter=8,
        leading=14,
        alignment=TA_JUSTIFY
    ))

    # Muted text (for metadata, footer)
    styles.add(ParagraphStyle(
        'MutedText',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['muted'],
        spaceAfter=4
    ))

    # Tag/pill style text
    styles.add(ParagraphStyle(
        'TagText',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['secondary'],
    ))

    # Item title (for bordered items)
    styles.add(ParagraphStyle(
        'ItemTitle',
        parent=styles['Normal'],
        fontSize=10,
        textColor=COLORS['primary'],
        fontName=_CJK_FONT_BOLD,
        spaceAfter=2
    ))

    # Item description
    styles.add(ParagraphStyle(
        'ItemDesc',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['secondary'],
        leading=12
    ))

    return styles


def create_header_table(data, styles):
    """Create the dark header section."""
    company = data.get('company_name', 'Unknown Company')
    date = data.get('report_date', datetime.now().strftime('%B %d, %Y'))
    url = data.get('source_url', '')

    header_content = [
        [Paragraph('<font color="white" size="9">ACCOUNT RESEARCH REPORT</font>', styles['Normal'])],
        [Paragraph(f'<font color="white" size="20"><b>{company}</b></font>', styles['Normal'])],
        [Spacer(1, 8)],
        [Paragraph(f'<font color="#94a3b8" size="9"><b>Date:</b> {date}  |  <b>Source:</b> {url}  |  <b>Analyst:</b> openclaw</font>', styles['Normal'])]
    ]

    header_table = Table(header_content, colWidths=[7*inch])
    header_table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), COLORS['primary']),
        ('LEFTPADDING', (0, 0), (-1, -1), 24),
        ('RIGHTPADDING', (0, 0), (-1, -1), 24),
        ('TOPPADDING', (0, 0), (0, 0), 20),
        ('BOTTOMPADDING', (0, -1), (-1, -1), 20),
    ]))

    return header_table


def create_section_heading(title, styles):
    """Create a section heading with bottom border."""
    elements = []
    elements.append(Paragraph(title, styles['SectionHeading']))
    elements.append(HRFlowable(width="100%", thickness=2, color=COLORS['border'], spaceAfter=8))
    return elements


def create_profile_table(profile_data, styles):
    """Create the company profile table；单元格用 Paragraph 渲染以正确显示中文。"""
    label_style = ParagraphStyle(
        'ProfileLabel',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['secondary'],
        fontName=_CJK_FONT_BOLD,
    )
    value_style = ParagraphStyle(
        'ProfileValue',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['secondary'],
        fontName=_CJK_FONT,
        leading=12,
    )
    rows = []
    fields = [
        ('Company Name', 'name'),
        ('Industry', 'industry'),
        ('Headquarters', 'headquarters'),
        ('Founded', 'founded'),
        ('CEO/Founder', 'ceo'),
        ('Company Size', 'size'),
        ('Website', 'website'),
        ('Recent Funding', 'funding'),
    ]

    for label, key in fields:
        value = profile_data.get(key, '')
        if value:
            rows.append([
                Paragraph(_escape_for_paragraph(label), label_style),
                Paragraph(_escape_for_paragraph(value), value_style),
            ])

    if not rows:
        return None

    table = Table(rows, colWidths=[1.8*inch, 5.2*inch])
    table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (0, -1), COLORS['bg_light']),
        ('TEXTCOLOR', (0, 0), (0, -1), COLORS['secondary']),
        ('TEXTCOLOR', (1, 0), (1, -1), COLORS['secondary']),
        ('FONTSIZE', (0, 0), (-1, -1), 9),
        ('PADDING', (0, 0), (-1, -1), 8),
        ('GRID', (0, 0), (-1, -1), 0.5, COLORS['border']),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
        ('ROWBACKGROUNDS', (0, 0), (-1, -1), [COLORS['bg_light'], COLORS['white']]),
    ]))

    return table


def create_bordered_item(title, description, accent_color, styles):
    """Create a left-bordered item block."""
    content = []
    if title:
        content.append([Paragraph(f'<b>{title}</b>', styles['ItemTitle'])])
    if description:
        content.append([Paragraph(description, styles['ItemDesc'])])

    if not content:
        return None

    inner_table = Table(content, colWidths=[6.6*inch])
    inner_table.setStyle(TableStyle([
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
        ('RIGHTPADDING', (0, 0), (-1, -1), 4),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
    ]))

    outer_table = Table([[inner_table]], colWidths=[7*inch])
    outer_table.setStyle(TableStyle([
        ('LINEAFTER', (0, 0), (0, -1), 0, COLORS['white']),
        ('LINEBEFORE', (0, 0), (0, -1), 4, accent_color),
        ('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#fafafa')),
        ('TOPPADDING', (0, 0), (-1, -1), 0),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
        ('LEFTPADDING', (0, 0), (-1, -1), 0),
    ]))

    return outer_table


def create_competitor_table(competitors, styles):
    """Create the competitor comparison table with proper text wrapping."""
    if not competitors:
        return None

    # Create cell style for wrapping text
    cell_style = ParagraphStyle(
        'TableCell',
        parent=styles['Normal'],
        fontSize=9,
        textColor=COLORS['secondary'],
        leading=12,
        fontName=_CJK_FONT
    )
    cell_style_bold = ParagraphStyle(
        'TableCellBold',
        parent=cell_style,
        fontName=_CJK_FONT_BOLD
    )
    header_style = ParagraphStyle(
        'TableHeader',
        parent=cell_style,
        fontName=_CJK_FONT_BOLD,
        textColor=COLORS['secondary']
    )

    # Create header row with Paragraphs
    header = [
        Paragraph('Competitor', header_style),
        Paragraph('Key Strengths', header_style),
        Paragraph('Differentiation', header_style)
    ]
    rows = [header]

    # Create data rows with Paragraphs for text wrapping
    for comp in competitors:
        rows.append([
            Paragraph(comp.get('name', ''), cell_style_bold),
            Paragraph(comp.get('strengths', ''), cell_style),
            Paragraph(comp.get('differentiation', ''), cell_style)
        ])

    table = Table(rows, colWidths=[1.6*inch, 2.7*inch, 2.7*inch])
    table.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), COLORS['bg_light']),
        ('PADDING', (0, 0), (-1, -1), 8),
        ('GRID', (0, 0), (-1, -1), 0.5, COLORS['border']),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
    ]))

    return table


def create_tags(keywords, color_map, styles):
    """Create keyword tags as a wrapped paragraph."""
    if not keywords:
        return None

    tags_text = '  '.join([f'<font color="{color_map.get(kw, "#334155")}" size="9">[{kw}]</font>' for kw in keywords])
    return Paragraph(tags_text, styles['TagText'])


def create_bullet_list(items, bullet_color, styles):
    """Create a simple bullet list."""
    if not items:
        return None

    elements = []
    for item in items:
        bullet_html = f'<font color="{bullet_color}">•</font>  {item}'
        elements.append(Paragraph(bullet_html, styles['ReportBody']))

    return elements


def generate_pdf(data, output_path):
    """Generate the complete PDF report."""
    styles = create_styles()

    doc = SimpleDocTemplate(
        output_path,
        pagesize=letter,
        rightMargin=0.5*inch,
        leftMargin=0.5*inch,
        topMargin=0.5*inch,
        bottomMargin=0.5*inch
    )

    story = []

    # Header
    story.append(create_header_table(data, styles))
    story.append(Spacer(1, 16))

    # Executive Summary
    if data.get('executive_summary'):
        story.extend(create_section_heading('Executive Summary', styles))
        story.append(Paragraph(data['executive_summary'], styles['ReportBody']))
        story.append(Spacer(1, 8))

    # Company Profile
    if data.get('profile'):
        story.extend(create_section_heading('Company Profile', styles))
        profile_table = create_profile_table(data['profile'], styles)
        if profile_table:
            story.append(KeepTogether([profile_table]))
        story.append(Spacer(1, 8))

    # Products & Services
    if data.get('products'):
        story.extend(create_section_heading('Products & Services', styles))

        if data['products'].get('offerings'):
            story.append(Paragraph('<b>Core Offerings</b>', styles['SubHeading']))
            for item in data['products']['offerings']:
                block = create_bordered_item(item.get('name'), item.get('description'), COLORS['accent_blue'], styles)
                if block:
                    story.append(KeepTogether([block, Spacer(1, 6)]))

        if data['products'].get('differentiators'):
            story.append(Paragraph('<b>Key Differentiators</b>', styles['SubHeading']))
            for diff in data['products']['differentiators']:
                block = create_bordered_item(diff, None, COLORS['accent_emerald'], styles)
                if block:
                    story.append(block)
                    story.append(Spacer(1, 4))

        if data['products'].get('tech_stack'):
            story.append(Paragraph('<b>Technology Stack</b>', styles['SubHeading']))
            tech_text = '  |  '.join([f'<b>{k}:</b> {v}' for k, v in data['products']['tech_stack'].items()])
            story.append(Paragraph(tech_text, styles['MutedText']))

        story.append(Spacer(1, 8))

    # Target Market
    if data.get('target_market'):
        story.extend(create_section_heading('Target Market', styles))

        if data['target_market'].get('segments'):
            story.append(Paragraph(data['target_market']['segments'], styles['ReportBody']))

        if data['target_market'].get('verticals'):
            story.append(Paragraph('<b>Industry Verticals</b>', styles['SubHeading']))
            verticals_text = '  '.join([f'[{v}]' for v in data['target_market']['verticals']])
            story.append(Paragraph(verticals_text, styles['MutedText']))

        if data['target_market'].get('personas'):
            story.append(Paragraph('<b>Buyer Personas</b>', styles['SubHeading']))
            for persona in data['target_market']['personas']:
                block = create_bordered_item(persona.get('title'), persona.get('description'), COLORS['accent_violet'], styles)
                if block:
                    story.append(block)
                    story.append(Spacer(1, 4))

        if data['target_market'].get('business_model'):
            story.append(Paragraph('<b>Business Model</b>', styles['SubHeading']))
            story.append(Paragraph(data['target_market']['business_model'], styles['ReportBody']))

        story.append(Spacer(1, 8))

    # Use Cases & Pain Points (conditional page break only if needed)
    if data.get('use_cases'):
        # Use CondPageBreak to only break if less than 2 inches remain
        story.append(CondPageBreak(2*inch))
        story.extend(create_section_heading('Use Cases & Pain Points', styles))
        for uc in data['use_cases']:
            block = create_bordered_item(uc.get('title'), uc.get('description'), COLORS['accent_amber'], styles)
            if block:
                story.append(KeepTogether([block, Spacer(1, 6)]))
        story.append(Spacer(1, 8))

    # Competitive Landscape
    if data.get('competitors'):
        story.extend(create_section_heading('Competitive Landscape', styles))
        comp_table = create_competitor_table(data['competitors'], styles)
        if comp_table:
            story.append(KeepTogether([comp_table]))

        if data.get('competitive_positioning'):
            story.append(Spacer(1, 8))
            story.append(Paragraph('<b>Competitive Positioning</b>', styles['SubHeading']))
            story.append(Paragraph(data['competitive_positioning'], styles['ReportBody']))

        story.append(Spacer(1, 8))

    # Industry Dynamics
    if data.get('industry'):
        story.extend(create_section_heading('Industry Dynamics', styles))

        if data['industry'].get('trends'):
            story.append(Paragraph('<b>Market Trends</b>', styles['SubHeading']))
            for trend in data['industry']['trends']:
                story.append(Paragraph(f'<font color="#3b82f6">•</font>  {trend}', styles['ReportBody']))

        if data['industry'].get('opportunities'):
            story.append(Paragraph('<b>Growth Opportunities</b>', styles['SubHeading']))
            for opp in data['industry']['opportunities']:
                story.append(Paragraph(f'<font color="#10b981">•</font>  {opp}', styles['ReportBody']))

        if data['industry'].get('challenges'):
            story.append(Paragraph('<b>Challenges</b>', styles['SubHeading']))
            for ch in data['industry']['challenges']:
                story.append(Paragraph(f'<font color="#f59e0b">•</font>  {ch}', styles['ReportBody']))

        story.append(Spacer(1, 8))

    # Recent Developments
    if data.get('developments'):
        story.extend(create_section_heading('Recent Developments', styles))
        for dev in data['developments']:
            date_str = dev.get('date', '')
            title = dev.get('title', '')
            desc = dev.get('description', '')
            block = create_bordered_item(f'<font color="#14b8a6">{date_str}</font> — {title}', desc, COLORS['accent_teal'], styles)
            if block:
                story.append(KeepTogether([block, Spacer(1, 6)]))
        story.append(Spacer(1, 8))

    # Lead Generation Intelligence (conditional page break only if needed)
    if data.get('lead_gen'):
        # Use CondPageBreak to only break if less than 2 inches remain
        story.append(CondPageBreak(2*inch))
        story.extend(create_section_heading('Lead Generation Intelligence', styles))

        kw = data['lead_gen'].get('keywords', {})
        if kw.get('primary'):
            story.append(Paragraph('<b>Primary Service Keywords</b>', styles['SubHeading']))
            story.append(Paragraph('  '.join([f'<font color="#3b82f6">[{k}]</font>' for k in kw['primary']]), styles['TagText']))

        if kw.get('vertical'):
            story.append(Paragraph('<b>Vertical Keywords</b>', styles['SubHeading']))
            story.append(Paragraph('  '.join([f'<font color="#10b981">[{k}]</font>' for k in kw['vertical']]), styles['TagText']))

        if kw.get('technology'):
            story.append(Paragraph('<b>Technology Keywords</b>', styles['SubHeading']))
            story.append(Paragraph('  '.join([f'<font color="#8b5cf6">[{k}]</font>' for k in kw['technology']]), styles['TagText']))

        if kw.get('pain_point'):
            story.append(Paragraph('<b>Pain Point Keywords</b>', styles['SubHeading']))
            story.append(Paragraph('  '.join([f'<font color="#f59e0b">[{k}]</font>' for k in kw['pain_point']]), styles['TagText']))

        if data['lead_gen'].get('outreach_angles'):
            story.append(Spacer(1, 8))
            story.append(Paragraph('<b>Outreach Angles</b>', styles['SubHeading']))
            for angle in data['lead_gen']['outreach_angles']:
                block = create_bordered_item(angle.get('title'), angle.get('description'), COLORS['accent_indigo'], styles)
                if block:
                    story.append(block)
                    story.append(Spacer(1, 4))

        if data['lead_gen'].get('partnership_targets'):
            story.append(Spacer(1, 8))
            story.append(Paragraph('<b>Partnership Targets</b>', styles['SubHeading']))
            for partner in data['lead_gen']['partnership_targets']:
                block = create_bordered_item(partner.get('name'), partner.get('rationale'), COLORS['accent_rose'], styles)
                if block:
                    story.append(block)
                    story.append(Spacer(1, 4))

        story.append(Spacer(1, 8))

    # Information Gaps
    if data.get('info_gaps'):
        story.extend(create_section_heading('Information Gaps', styles))
        story.append(Paragraph('The following information was not publicly available:', styles['MutedText']))
        for gap in data['info_gaps']:
            story.append(Paragraph(f'<font color="#94a3b8">•</font>  {gap}', styles['MutedText']))
        story.append(Spacer(1, 8))

    # Footer
    story.append(Spacer(1, 16))
    story.append(HRFlowable(width="100%", thickness=1, color=COLORS['border']))
    report_date = data.get('report_date', datetime.now().strftime('%B %d, %Y'))
    footer_text = f'This report was prepared for business development and sales intelligence purposes. All information is based on publicly available sources and is current as of {report_date}. Verify critical details before making business decisions.'
    story.append(Paragraph(footer_text, styles['MutedText']))

    # Build PDF
    doc.build(story)
    return output_path


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print("Usage: python generate_report.py input.json output.pdf")
        sys.exit(1)

    input_file = sys.argv[1]
    output_file = sys.argv[2]

    with open(input_file, 'r') as f:
        data = json.load(f)

    generate_pdf(data, output_file)
    print(f"Report generated: {output_file}")
